Commit Graph
879 Commits
Author SHA1 Message Date
Miguel Ángel 23937497a9 chore(release): cut v0.8.78 (#4515) 2026-09-25 22:58:59 -04:00
Miguel Ángel 4ef2fc3f1e feat(player): expose picture size, durationchange and a click-to-play opt-out (#4505)
* feat(player): expose picture size, durationchange and a click-to-play opt-out

- compositionWidth/compositionHeight are public, ready carries them, and a
  resize event fires when the picture size changes.
- durationchange fires when the duration changes after ready, on both the
  runtime and the direct-timeline paths.
- disable-click-to-play leaves clicks on the picture to the host.

Nothing changes for a player that does not use the new attribute; ready's
detail only gains two fields.

* docs(player): say composition size, one doc line per size getter

* fix(player): apply scenes before ready fires, keep the zero-size warning, document the new API

* fix(player): fire a message's events after the whole message is applied

* fix(player): queue every player event behind the update that raised it

* fix(player): decide autoplay after ready listeners run, and restart a loop at time 0

* fix(player): keep raising events after a listener throws

* refactor(player): drop a comment the ordering test already pins

* fix(player): fire the rest of an update's events when a listener throws
2026-09-26 00:58:43 +00:00
Miguel Ángel dd88b5f5b7 chore: release v0.8.77 (#4489) 2026-09-25 12:51:35 +00:00
Miguel Ángel 5f95787cce docs(release): list the three changes v0.8.76 also shipped (#4488) 2026-09-25 12:04:00 +00:00
Miguel Ángel 8b4c3a1d3d chore: release v0.8.76 (#4485) 2026-09-25 11:20:26 +00:00
Miguel Ángel ab540fc42e perf(player): let paused players check in once a second with low-power-idle (#4483)
* perf(player): let paused players check in once a second with low-power-idle

* refactor(player): trim low-power-idle comments and tidy its test

* fix(core): keep the fast paused heartbeat until a timeline is bound

* fix(core): wait for sub-compositions to bind before slowing the paused heartbeat
2026-09-25 10:15:42 +00:00
Miguel Ángel 11ac9bce69 fix(studio-server): previewing a project never rewrites its files (#4480)
* fix(studio-server): previewing a project never rewrites its files

* fix(studio-server): a GSAP save on a served id writes that id to the file too
2026-09-25 10:04:38 +00:00
Miguel Ángel 7c634426fd docs(cli): explain how catalog search works and which model it downloads (#4462)
* docs(cli): explain how catalog search works and which model it downloads

* docs(cli): name the model catalog search was chosen against

* docs(cli): keep only live rules in the word-search header comment

* docs(cli): correct the hosted vector size in the local vector build comment
2026-09-25 04:43:54 +00:00
Miguel Angel Simon Sierra a08433acef chore: release v0.8.75 2026-09-24 21:51:48 -04:00
Miguel Ángel b8dd023a97 feat(core): a composition's script can load its own files with __hyperframes.assetUrl (#4434)
* feat(core): a composition's script can load its own files with __hyperframes.assetUrl

* test(core): a template composition inside a mounted file resolves assets from that file

* docs: assetUrl is for paths beside the composition, not project-root paths

* docs: say assetUrl misses a project-root path
2026-09-24 21:13:27 -04:00
Miguel Ángel 8af615a48e fix(cli): catalog --json carries each item's preview video and poster (#4443)
The catalog already loads every item's manifest, preview included, but the
--json rows dropped it, so an app listing the catalog had no way to show an
item before add downloads it. Rows now carry preview when the item has one.
2026-09-24 18:14:13 -04:00
Miguel Angel Simon Sierra 3a47b46057 chore: release v0.8.74 2026-09-24 17:04:02 -04:00
WaterrrForeverandClaude Opus 5 480beb62bd docs: state the 45 s cost of a missing data-no-timeline (#4402)
The attribute is in the HTML schema reference and enforced by the missing_data_no_timeline lint rule, but no page said what omitting it costs: a composition that never registers a GSAP timeline waits out player-ready-timeout (45 s by default) on every render.

That matters for triage because it is a fixed cost. "The render is slow" currently lists only causes that scale with the project - draft quality, media size, filter complexity - so an author whose renders are uniformly 45 s long reads the section, tunes the things it names, and sees no change.

- troubleshooting: add a symptom-keyed entry above "The render is slow", and point that section at it for the constant-penalty case.
- html-schema: give the attribute row the consequence and the lint code.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-25 02:29:25 +08:00
Miguel Ángel b9e5a16fcf fix(player): a play() made while the composition loads still plays (#4429)
* fix(player): a play() made while the composition loads still plays

The iframe's own load event reset the asset wait, and that reset also cleared the queued play,
so a play() between the first ready and load was dropped with no error. Play intent now leaves
the asset-wait reset: only pause, seek, disconnect and a new src or srcdoc clear it.

Also adds assets-loading-ui (player | none): none never shows the loading-assets card, while
the assets-loading attribute and the assetsready and painted events still fire.

* fix(player): switching the loading card off keeps a shader load on screen

* fix(player): the loading card and a shader load no longer hide each other
2026-09-24 12:48:55 -04:00
Miguel Ángel 6f7f463fc5 chore: release v0.8.73 2026-09-24 11:53:31 -04:00
Miguel Ángel 6a0fd68584 chore: release v0.8.72 2026-09-24 07:23:30 -04:00
Miguel Ángel 58c873d816 chore: release v0.8.71 (#4395) 2026-09-23 23:32:31 -07:00
Miguel Ángel fc9071c1fc chore: release v0.8.70 (#4389) 2026-09-23 22:10:27 -04:00
James Russo 01601d1105 feat: add Gemini TTS models and service-account auth to media skills (#4377)
* feat: add opt-in Gemini 3.8 TTS to media skills

* feat: support Gemini service accounts and older TTS models

* fix(audio): isolate Gemini auth and narrow OAuth scope

* fix(audio): pin Gemini Python helpers to UTF-8
2026-09-24 02:21:23 +01:00
Miguel Ángel 2c4bf075b5 chore: release v0.8.69 (#4376) 2026-09-23 20:13:08 -04:00
Miguel Ángel 86c5c53d25 chore: release v0.8.68 (#4361) 2026-09-23 17:16:00 -04:00
Miguel Ángel 9cee2bd345 chore: release v0.8.67 (#4354) 2026-09-23 16:14:31 -04:00
Miguel Ángel 4efe5f206d chore: release v0.8.66 (#4344) 2026-09-23 13:29:38 -04:00
Miguel Ángel aabfba5445 chore: release v0.8.65 (#4336) 2026-09-23 11:03:11 -04:00
Miguel Ángel 8055961740 feat(registry): a Lottie character walk-in, and looping Lottie that keeps playing (#4316)
* fix(core): looping Lottie animations keep cycling instead of freezing after one pass

* feat(registry): add a Lottie character walk-in and document the character route

* chore(registry): index lottie-character-walk in the catalog and search vectors

* chore(docs): list lottie-character-walk in the catalog gallery

* docs(skills): say that lottie-web loops when loop is left out

* fix(core): a finished Lottie holds its last frame instead of disappearing

* fix(core): hold a finished Lottie on its exact last frame

* chore(skills): refresh the manifest hash for the Lottie skill edits

* fix(core): wrap looping Lottie by frame so a loop never holds at its seam

* fix(core): a looping Lottie starts each cycle on frame 0 despite float error
2026-09-23 09:20:48 -04:00
Vance Ingalls ed75203cb6 chore: release v0.8.64 (#4326) 2026-09-23 04:03:02 -07:00
Vance IngallsandClaude Sonnet 5 b32b9a7dab feat(runtime): data-vfx-chain — a seek-deterministic per-pixel effect element (#4306)
* feat(core): data-vfx-chain defs and chain parsing (mirrors data-fx-chain)

Mirrors audioFx.ts's shape for the per-pixel VFX chain: a versioned
JSON chain attribute (data-vfx-chain), a def registry with typed
params (number/enum/bool/ref), and parse/serialize/normalize helpers.
HF_VFX holds one def, fractal-noise, with a placeholder frag; the
kernel and its consumers (packages/core/src/runtime/vfx.ts) land in
Task 1.2/1.3 of the vfx-chain-runtime plan, so vfx.ts is added to
.fallowrc.jsonc's entry list for now.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* feat(runtime): paint data-vfx-chain canvases on every seek

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* feat(vfx): fractal-noise kernel (Basic/fBm approximation) with CPU reference

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* feat(vfx): self capture through layoutsubtree with the page-composite readiness protocol

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* feat(vfx): wave-warp kernel (Sine)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* feat(vfx): displacement-map kernel (self-referential map)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test(vfx): chain order is nesting order; preceding CSS effects are captured

...and following ones apply outside. The plan's one-line message for Task 2.4
is 105 characters; commitlint caps the header at 100, so the tail moved here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test(vfx): seek determinism and CPU-reference PSNR for fractal-noise

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(vfx): size the output canvas from the host's layout box, not its transformed AABB

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* feat(telemetry): vfx node count, capture class and types on render_complete

Threads vfxNodeCount, vfxCapture and vfxTypes from a static scan of the
compiled composition's data-vfx-chain hosts (mirrors the existing
compositionElementCount/colorGradingCount scan) through
RenderPerfSummary.drawElement into the render_complete event, next to
de_capture_mode. Exports chainCapture/parseVfxChain/HfVfxCapture from
@hyperframes/core's index for the producer to consume. The PostHog
dashboard tile is not created here — left for the coordinator.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* docs(vfx): data-vfx-chain guide — element shape, capture table, Studio flag, known constraints

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(vfx): register chain hosts that arrive with a sub-composition mount

`initVfx(document.body, fps)` ran once, synchronously, three lines after
`void loadExternalCompositions(...)` — so every `data-vfx-chain` host that
enters the DOM only when a `data-composition-src` mount resolves was never
registered. An unregistered host paints nothing and reports nothing: no
`[HyperFrames] composition script error`, the `.hf-vfx-out` canvas keeps its
300x150 default, and `paintVfx` never even arms the page-composite flag.
Measured on a real multi-file export served raw: `#main-l5-text`'s output
canvas stayed 300x150 and `window.__timelines` never gained the sub-comp.

Re-scan in the loader's `.finally`, before `maybePublishRenderReady()`, so
registration precedes readiness. `initVfx` now releases the outgoing
registry's programs, capture textures and ping-pong targets first — the
output canvas hands back the same WebGL2 context on a re-scan, so the
previous pass's GL objects would otherwise leak.

Two browser cases in `vfxDeterminism.test.ts`, both against the real runtime
bundle: a host whose `.hf-vfx-in` IS the mount (already worked — the mount
replaces the wrapper's children, not the wrapper, so the registered source
node survives), and a host that arrives INSIDE a mounted sub-composition
(failed with `armed: false` and no error; passes now).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(vfx): runtime tsconfig typecheck passes

Under noUncheckedIndexedAccess, resolveCaptureSource's null return
widened VfxEntry.src past its VfxCaptureSource | undefined type; the
function is internal-only, so its return type moves to
VfxCaptureSource | undefined instead. Indexing PingPong.framebuffers
by a non-literal index produced | undefined against
WebGLFramebuffer | null, coalesced to null. No behavior change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(vfx): structural DOM predicates instead of realm-bound instanceof

vfx.ts checked `instanceof HTMLCanvasElement`/`HTMLElement` directly, which
returns false for inner-realm nodes when the Studio previews across an
iframe realm. domRealm.ts had no canvas predicate yet, so this adds
isCanvasElement mirroring the existing isImageElement pattern, then swaps
all three vfx.ts checks to the structural predicates the lint guard requires.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(vfx): paint self-capture hosts under hyperframes snapshot, not only the engine path

`paintVfx(t, { engineMode: true })` armed the page-composite protocol and
returned, betting that every capturing chain runs under `frameCapture.ts`.
`hyperframes snapshot` (and check/compare/validate/layout, and Studio's
thumbnail capture) seek through the same `renderSeek`, never read
`__hf_page_composite_pending` and never call `__hf_page_composite_resolve` —
so a `self` chain painted nothing there, in silence, because its content
lives in a `layoutsubtree` canvas the browser never paints directly.

Engine mode now arms the preview-side capture as well and paints on whichever
completes first. A seek token stops a superseded async capture from repainting
a newer frame, and a registry-identity check stops it painting an entry
`initVfx` already released. `resolveVfxCapture` stays non-idempotent on
purpose: the engine resolves only after its own before-capture hooks have
mutated the DOM, so its capture is still the authoritative one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(vfx): an exporter-emitted .hf-vfx-out gets the box the spec fixes for it

findOrCreateOut adopted a canvas the exporter had already emitted without
applying the layout cssText, so it kept the default position:static;
display:inline and wrapped to the line AFTER the layer-wide .hf-vfx-src
canvas — painting a second, misplaced copy of the layer one full layer
height below the host. Measured on retro-wave #main-l6-text: .hf-vfx-src
rect top 315.1 h 93.0, .hf-vfx-out rect top 409.2, both style=null,
position static (ae-mcp findings Task 3.5b). Hosts with no emitted
out-canvas were never affected, which is why only this one host moved.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* refactor(telemetry): vfx_node_count counts hosts, not chain nodes — rename to vfx_host_count

The field increments once per `data-vfx-chain` attribute occurrence, never
per node inside a chain's JSON, so the name promised something the scan does
not measure. Renames the internal `vfxNodeCount` and the wire property
`vfx_node_count` to `vfxHostCount`/`vfx_host_count` across the orchestrator
scan, the perf summary, the CLI render path and the telemetry event. No
dashboard consumes the field yet, so the wire rename costs nothing now and
would cost a migration later.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(vfx): join the preview capture to the seek-completion barrier, not race it

`paintVfx` fired `capturePreviewThenPaint` and forgot it, so nothing the CLI
awaits waited for a `self` chain's paint. Every snapshot-family command
(`snapshot`, `check`, `compare`, `validate`, `layout`) seeks through
`seekCompositionTimeline`, which drains `window.__hfWaitForSeekCompletion`
and then allows one settle race before screenshotting — and only the
`"hf-seek"` event's `waitUntil()` could put anything in that barrier. The
screenshot therefore landed on however many hosts happened to have finished,
which varied with host count and machine speed.

Extracts the "track, untrack on settle, retain the first rejection" block
`dispatch()` built inline into an exported `registerSeekCompletion`, and has
`paintVfx` register the preview capture through it. Also awaits the per-host
paints with `Promise.all` instead of sequentially: N hosts cost about two
animation frames now, not 2N.

Measured on the pre-fix bundle with two `self` hosts, both output canvases
read `[0,0,0,0]` at the moment the barrier returned; they painted only
because the settle race that follows happened to be long enough. Both tests
added here fail on that bundle.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(vfx): report WebGL context loss loudly instead of silently no-op painting

One WebGL2 context per `data-vfx-chain` host, against a browser cap that is
commonly 16 and shared with `colorGrading.ts`'s per-element contexts. A lost
context makes every later call on it do nothing, per spec — so the chain kept
"painting" a blank canvas with no error, which is exactly what the module's
loud-failure contract exists to prevent.

Adds the `webglcontextlost` listener pair's first half, following
`colorGrading.ts`'s precedent: `preventDefault()`, mark the entry, report
once through `reportVfxError`. The entry is then skipped by `paintVfx`,
`capturePreviewThenPaint` and `resolveVfxCapture` — silently, since the one
loud report already happened and repeating it per frame is spam.

Restore is left unhandled on purpose, with the reasoning in the doc comment:
`initVfx`'s existing re-scan already rebuilds every GL object, and a second
narrower rebuild path for `webglcontextrestored` would duplicate it. The
shared-context redesign the review floated is likewise out of scope here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* perf(vfx): cache uniform locations at pass-build time instead of querying every paint

`setPassUniforms` asked the driver for `u_size`, `u_t`, `u_fps` and every
param's location on every paint of every pass, and `bindPass` did the same
for `u_src` on every bind. `buildPasses` already constructs each `VfxPass`
once at init, right after the program links, and a linked program's
locations never change — so they are resolved there now and read from
`pass.locations` in the hot path.

Same values, same `null`-means-optimised-out semantics (`gl.uniform*(null,
…)` is a defined no-op, which is what the per-frame query produced too), so
the existing vfx.test.ts and the browser determinism suite cover it
unchanged — both still green, the latter against a rebuilt runtime bundle.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(vfx): bound the paint wait per host so a stalled compositor can't hang the seek barrier

`paintVfx` registers `capturePreviewThenPaint` into the shared seek-completion
barrier (48aaa2bbb), and that promise settled only via `awaitCanvasPaint` — a
race between the canvas `paint` event and a double-rAF chain. Under BeginFrame
control (Linux headless-shell, `drawelement` capture) neither can fire before
the barrier is drained: `frameCapture.ts` awaits the barrier in
`prepareFrameForCapture` (~2692), while the frame's
`HeadlessExperimental.beginFrame` is issued later, in the per-frame capture
stage (~3797). Fire-and-forget that was harmless; registered it can stall every
`__hfWaitForSeekCompletion` caller, the engine's render path included.

rAF-under-BeginFrame: CONFIRMED gated, from this repo's own engine notes —
`frameCapture.ts` ~2445 ("waitForFunction uses rAF polling internally, which
won't fire in beginFrame mode") and ~4755 ("headless only fires rAF when a
frame is produced, and nothing produces one until a screenshot asks"). Not
reproduced locally: every environment here is macOS with a free-running
compositor (`beginFrameTimeTicks === 0`). `setTimeout` is not compositor-gated
there — `drawElementService.ts` ~341 describes its 250 ms paint fallback as
burning on every BeginFrame frame, which requires the timer to fire — so a
timer ceiling is a sound escape.

`awaitCanvasPaint` now resolves `"painted" | "timeout"` with a 2000 ms ceiling
(the repo's own `BEGINFRAME_PROBE_TIMEOUT_MS`; ~20x a real two-frame paint,
far short of the ~180 s CDP `protocolTimeout` a hang would burn). The race is
per host, so one stalled compositor no longer delays hosts that would have
painted; a timed-out host is skipped (no capture, no guessed pixels) and
reported loudly. The report is not suppressed in engine mode: `frameCapture.ts`
~2708 skips `__hf_page_composite_resolve` in `drawelement`/`beginframe` modes,
so there is no authoritative second attempt to defer to there.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* chore(ci): re-pin test-classification.mjs hash after registering vfxDeterminism.test.ts

An earlier commit added vfxDeterminism.test.ts to INTEGRATION_TEST_FILES;
check-test-reachability.mjs pins a sha256 of that file to force a conscious
review whenever it changes. Reviewed: runner[1]'s glob already covers the
file structurally, the classification move (unit -> integration) is correct
for a Chrome-launching test, and the pinned hash is now current.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* chore(core): regenerate position-edits-render-inline.ts for Linux esbuild output

check:position-edits-render (bun run build:position-edits-render && git diff
--exit-code) failed on both Linux CI runners (Test (runtime), Tests on
windows-latest: studio-core) but passed on macOS: esbuild's minifier named
two identically-scoped WeakMap/function bindings differently on Linux than
on the mac that last committed this artifact, and the divergence appeared
only on this branch (main's own current tip passes CI cleanly), so it is
tied to a change on this branch rather than a random flake, even though it
is not attributable to any specific line of that change.

Confirmed stable across two independent Linux CI runs (byte-identical diff
both times) and reconstructed directly from that diff rather than guessed:
the committed content, byte length (3817), and 3/3 existing artifact tests
all match. A future contributor rebuilding on macOS will see this same
diff again in the other direction until the build script's cross-platform
determinism is fixed at the esbuild-invocation level, which is out of this
PR's scope.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-23 03:14:08 -07:00
miga-heygenandMiguel Angel Simon Sierra 99221c50a5 chore: release v0.8.63 (#4312)
Co-authored-by: Miguel Angel Simon Sierra <miguel.sierra@heygen.com>
2026-09-23 05:49:08 -04:00
Miguel Ángel bc1c60ae5b fix(catalog): regenerating the texture-mask page no longer duplicates its section (#4302)
* fix(catalog): regenerating the texture-mask page no longer duplicates its Texture masks section

The page generator carries forward any section whose heading it does not
own, and it emits "## Texture masks" without owning it. Every run kept the
old copy and appended a new one; main's page had three.

* chore(catalog): drop the two duplicate Texture masks sections from the texture-mask page

* chore(catalog): run oxfmt on the texture-masks regression test
2026-09-23 01:09:08 -04:00
James RussoandClaude Opus 5.5 ec3bc93b90 docs: alphabetize supported coding agents (#4297)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 22:21:34 +00:00
Brun3y 105984cac4 feat(cli): add IBM Bob runtime support (#3930) 2026-09-22 22:01:42 +00:00
Miguel Ángel d4485b51f1 chore: release v0.8.62 (#4293) 2026-09-22 16:12:35 -04:00
Miguel ÁngelandJake Moran 0945de83c7 feat(registry): text-match-cut (#4288)
* feat(registry): add text-match-cut — one text becomes another mid-move on a single 85 % curve

Video primitive reversed from an After Effects tutorial (Editing Snapped, "The Match
Cut Technique Every After Effects User Needs"), measured per frame at 60 fps. Both
texts ride one keyframe pair, cubic-bezier(.85, 0, .15, 1) over 2 s, and hard-swap at
the speed peak (1.0 s). A `mode` variable picks the property that carries the cut:
scale down (the tutorial), scale up, tracking in, or a same-direction slide in four
directions. Optional cyan-to-blue gradient sweep on its own 87 % curve, navy or
transparent background.

* chore(registry): integrate text-match-cut with current main

---------

Co-authored-by: Jake Moran <jakemoran2011@gmail.com>
2026-09-22 12:14:46 -04:00
Vance IngallsandMiguel Angel Simon Sierra 8d2b6e7bdc chore: release v0.8.61 (#4283)
Co-authored-by: Miguel Angel Simon Sierra <miguel.sierra@heygen.com>
2026-09-22 11:42:28 -04:00
b22bc2c979 feat(registry): extended-keyframe (#4281)
* feat(registry): add extended-keyframe, the never-fully-lands arrival with motion blur

A hyperframes:component. An element covers most of its move in the first fifth of the
duration and creeps the rest to the last frame (After Effects' extended-last-keyframe
technique), exits along the vector it arrived on, and carries shutter motion blur:
slides via the bundled feOffset filter smear, scale beats via a velocity-driven blur.

  var a = attachExtendedArrival("#word", tl, { at: 0.3, from: { x: -1400 } });
  attachExtendedArrival("#next", tl, { at: a.end, from: { scale: 0.35 } });

Direction and property agnostic (x / y / scale). The ease is exposed on its own as
EK.ease() for any tween, with EK.next() for sequencing and EK.gate() as a numeric check
(single velocity peak, no rises after it, tail above zero to the last frame).

registry/registry.json, docs/docs.json and docs/public/catalog-index.json regenerated
with the two generator scripts; they also pick up drift already present on main.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* feat(registry): publish live extended keyframe payload

* fix(registry): tear down extended keyframe blur

* fix(catalog): refresh extended keyframe payload

* fix(catalog): preserve merged catalog entries

* fix(catalog): regenerate catalog index

* fix(registry): trim extended-keyframe comments

* chore(registry): retrigger checks

* fix(registry): refresh extended-keyframe artifacts

* fix(catalog): refresh extended-keyframe payload

* fix(registry): refresh extended-keyframe artifacts against current main

---------

Co-authored-by: Jake Moran <jakemoran2011@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 11:41:48 -04:00
Miguel Ángel 05d09a7452 chore(registry): remove low-use catalog items and variant tails (#4274)
* chore(registry): remove low-use catalog items and variant tails

* fix(registry): remove stale references to deleted catalog items

* style: format catalog fixture

* fix(ci): use surviving catalog preview canary

* chore(ci): allow intentional catalog deletions

* fix(ci): scope fallow audit for catalog fixtures

* chore(catalog): regenerate local search vectors

* chore(catalog): update vector revision

* fix(catalog): validate registry set delta
2026-09-22 07:04:54 -04:00
Miguel Ángel 53153d4a54 feat(registry): examples show the most-installed blocks (#4284)
* feat(registry): examples show the most-installed blocks

* fix(docs): escape block placeholder in examples

* fix(docs): escape template placeholder in examples
2026-09-22 05:46:33 -04:00
01734fae3c feat(registry): colorama-wipe (#4277)
* feat(registry): add colorama-wipe, a colour-mapped feathered wipe reveal for headlines

A hyperframes:component recreating the After Effects "shiny wipe": masked text +
Compound Blur + Colorama over a moving gradient, with a crisp duplicate fading on top.
One call per text element:

  attachColoramaWipe("#headline", tl, { at, in, hold, out, cycle, feather, tilt, blur })

adds a single linear clock tween to the host timeline and paints the effect on two
canvases over the element's box; the element is hidden (visibility) with its layout
kept. All sizes scale from the element's font size. Deterministic: hash noise keyed by
frame, no Math.random, no clocks; seeks outside the window paint an empty stage.

registry/registry.json, docs/docs.json and docs/public/catalog-index.json were
regenerated with the two generator scripts as the contributing guide asks; they also
pick up drift already present on main.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* feat(registry): publish live colorama wipe payload

* style(registry): format colorama wipe demo

* fix(registry): tear down colorama wipe on timeline kill

* fix(catalog): refresh colorama wipe payload

* fix(catalog): preserve merged catalog entries

* fix(catalog): regenerate catalog index

---------

Co-authored-by: Jake Moran <jakemoran2011@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 03:55:03 -04:00
Miguel Ángel d5e00c0e66 feat(registry): week in merges leaderboard block (#4264)
* feat(registry): add a week-in-merges leaderboard block

Authors race across the row at a speed set by their merge count, bouncing at both edges.

* chore(registry): cover week-in-merges in the catalog search index

* style(registry): format the week-in-merges block

Wrap the lines oxfmt rejects so the format check passes.

* fix(registry): regenerate the week-in-merges catalog payload

The format pass left the committed payload off the generator output.

* feat(registry): cap week-in-merges at twelve rows

The block races at most rows_max authors, highest merge count first, and writes one line for everyone left out. The default is 12, so a long list cannot shrink the rows.

* fix(registry): make week-in-merges speed follow merge count

A row now travels the leader's pace times its merges over the leader's count. Only a zero stays on the floor, so a near-tie no longer looks like last place.
2026-09-21 23:35:55 -04:00
Miguel Ángel bf6cc7e32b chore: release v0.8.59 (#4252) 2026-09-21 19:07:41 -04:00
839ae426dd feat(studio): typed audio values, clip fades, audible video drops (#4250)
* feat(studio): typed audio values, clip fades, audible video drops

Audio rows in the media inspector (Volume, Speed, Media start) take a
typed value: click the readout, type "-6 dB", "1.5x" or "2.5s", Enter.
Speed presets are hidden on <audio> clips.

Clip-edge fades: data-fade-in / data-fade-out in seconds, honoured by the
preview runtime (per-tick gain), the render mixer (afade after volume) and
Studio (Fade in / Fade out rows, and drag dots at the top corners of audio
clips and audible videos). Linear on both sides so preview and render
agree; fades that outrun the clip scale to meet inside it.

Dropped videos with an audio stream now land with data-has-audio="true"
instead of muted, so the mixer keeps their sound. The media metadata
endpoint reports hasAudio from the ffprobe call it already makes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fix(audio): one owner for fades, dB, and afade-after-volume

Illegal fade values become no-fade at fadeGain; typed inspector input
still returns null so the readout stays red. Master and group mixes
share one filter chain with volume then afade. Fade-out stays anchored
to the trimmed clip end.

* fix(studio): share audio helpers and bound typed media values

* fix(studio): reserve sibling fade duration when editing

---------

Co-authored-by: Jake Moran <jakemoran2011@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Miguel Angel Simon Sierra <miguel.sierra@heygen.com>
2026-09-21 18:45:08 -04:00
James RussoandClaude Opus 5 badf49b551 docs(changelog): weekly digest 2026-09-14 to 2026-09-21 (#4248)
* docs(changelog): weekly digest 2026-09-14 to 2026-09-21

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(changelog): embed weekly video for 2026-09-14 to 2026-09-21

Adds the rendered weekly changelog video to the Sep 14-21 digest entry,
using the file's existing DocsVideo component and CDN path convention.

Video: 52.4s, square 1080, six themed scenes cut from the digest's eight.
Gates green before upload: hyperframes check 0 errors (layout 0 issues
across 33 samples, contrast 67/67), seam gate 0 fail / 0 warn across 7
seams, captions present across all 1572 frames, all scene midpoints and
payoff frames read individually.

CDN object verified byte-for-byte after invalidation (sha256 match,
x-cache Miss).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-21 18:57:46 +01:00
Vance Ingalls c797f54542 chore: release v0.8.58 (#4242) 2026-09-20 20:14:03 -07:00
Miguel Ángel c09594fef8 fix(docs): restore the sidebar gutter on catalog pages (#4238)
* fix(docs): restore the sidebar gutter on catalog detail pages

* fix(docs): align the catalog tab row and panes with the page gutter
2026-09-20 21:17:09 -04:00
Miguel Ángel f92d017b99 feat(cli): add timeline editing verbs (#4221)
* feat(cli): add timeline editing verbs

* chore: satisfy fallow complexity gate

* test(cli): cover snap rounding at known fps

* test(cli): cover snap rounding at known fps

* test(cli): cover snap rounding at known fps

* test(cli): cover snap rounding at known fps

* fix(cli): derive split ids from stable refs

* fix(cli): remove timeline gate blockers

* fix(cli): close freshness and output gate gaps

* fix(cli): close remaining timeline review findings

* refactor(cli): simplify mutation decision flow

* refactor(cli): split trim and apply paths

* refactor(cli): isolate trim validation

* fix(cli): satisfy timeline lint gate

* style: format timeline mutation files

* fix(cli): preserve mutation result types

* fix(cli): close timeline receipt and nested bounds gaps

* fix(studio): rollback writes that fail during write

* fix(cli): bound moved clips by end time
2026-09-20 18:04:13 -04:00
Vance Ingalls f09ea7af3b chore: release v0.8.57 (#4231) 2026-09-20 14:13:17 -07:00
Miguel Ángel 243ecd1d10 feat(studio): compose preview overlay guides (#4220)
* feat(studio): compose preview overlay guides

* fix(studio): sync late preview iframe mounts

* fix(studio): make preview iframe ownership explicit
2026-09-20 14:37:50 -04:00
Miguel Ángel 0c158be165 feat(studio): edit a clip's speed ramp with a rate lane and presets (#4153)
* feat(studio): edit a clip's speed ramp with a rate lane and presets

* fix(studio): keep the live preview attribute in sync with what gets persisted

* fix(cli): snapshot picks the source frame through a rate lane and up to 10x

hyperframes snapshot clamped the constant playback rate at 5 and ignored a
rate lane in data-automation, so a sped-up or ramped clip showed the wrong
frame. It now reads the rate through the runtime's own reader and maps time
with the shared source-time function.

* docs(skills): teach speed ramps as a rate lane in one reference page

Adds the speed-ramps reference, corrects the 0.1 to 5 rate range to 0.1 to 10
and the 'speed ramps are not supported' lines in the skills, and regenerates
the skills manifest.

* docs(skills): say what fixes a ramped clip's length and how the render approximates pitch

* fix(studio): hide the speed preset until the clip has a known duration

A preset on a clip with no data-duration was stretched over a made-up one
second. The panel now offers presets only when the duration is known.

* docs(skills): fix the last stale ramp line in the editing recipes and the slice-cap wording
2026-09-20 12:21:47 -04:00
Miguel Ángel e45483aa0a chore: release v0.8.56 (#4218) 2026-09-20 10:57:46 -04:00
Vance Ingalls 96369c8acd chore: release v0.8.55 (#4216) 2026-09-20 00:45:18 -07:00