The karaoke clip rendered as an almost-black tile with one small pill, which is
weak proof on first load. Every caption component in the catalog is type on a
black ground rather than captions burned over footage, so 'Captions on footage'
was also the wrong label. Swapped to the highlight style, which holds up at
tile size, and renamed the tile 'Kinetic captions'.
Reviewed the rendered page instead of the source: the four preview tiles came
out ~110px wide in a 730px content column, with labels wrapping mid-phrase, and
the three-column workflow cards were cramped enough to hyphenate a title into
'presentation s'. Two columns is the practical maximum for this column width, so
the tiles are now a readable 2x2 and the cards are back to two across.
- Lead with the film: the video moves directly under the one-line definition,
so a stranger sees a real result before reading anything.
- Delete the mermaid flow diagram. It duplicated the Steps list underneath it
word for word; the section heading already carries the flow.
- Replace the wall of text under 'What can it make?' with four real HyperFrames
outputs playing inline (~960KB total, deliberately the small clips), then keep
the six workflow paths as compact three-column links.
- Compress the four-row Studio-vs-agent table to two lines. A newcomer needs the
principle, not a decision matrix; the detail belongs in Studio.
- One primary next step instead of three equal cards.
Make /introduction the single "What is HyperFrames?" page a stranger can be
sent, and retire the switchboard that sat in front of it.
- introduction: lead with one sentence + a sound-on result (drop `muted`),
simplify the loop diagram to request -> agent -> project -> video, cut the
fake "See how it works" scroll button, and replace the equal-weight card
walls with one clear "Start here" action.
- guides/index: remove the six-card "What do you need to do?" menu-of-menus.
The nav already routes people and /introduction is the real entry point.
Redirect /guides -> /introduction.
- developers: point the "create a video" link at /quickstart.
mint validate and mint broken-links both pass.
An expanded sub-composition child row is built from a manifest clip, which
carries none of the host element's attributes, so data-hidden never reached
it. The eye on that row therefore always reported the element visible: the
first click hid it, and every click after wrote data-hidden again instead of
removing it. The element could not be shown again, not even after a reload,
because the attribute was already in the source.
The flat store element for the same child is built with its host element, so
the child row inherits hidden, timelineLocked and timelineRole from it.
Right-clicking a motionPath waypoint in the preview overlay opened Chrome's
own context menu on top of the editor: the handler returned before
preventDefault for every node that was not an x/y keyframe. Both node kinds
now open Studio's menu. A waypoint has no percentage of its own, so Move to
Playhead is hidden and Delete acts on the path index, matching the hover x
badge; Delete is withheld entirely on a two-anchor arc, where the writer
refuses the removal and the entry would silently do nothing.
The codex image provider's fail-fast gate required an `imagegenext` row in
`codex features list`. Codex CLI 0.145 renamed that flag to `image_generation`
and dropped the old row, so the gate rejected every up-to-date CLI:
media-use: codex image upsell unavailable: codex imagegenext unavailable
(upgrade Codex CLI)
`resolve --type image --provider codex` returned that without ever attempting
a render, on hosts where image generation works fine. Codex itself now warns
`[features].imagegenext is deprecated. Use [features].image_generation`.
Resolve the flag name from the feature list instead of hardcoding it, and pass
whichever name the installed CLI exposes to `--enable`. The old name is
preferred when present, since CLIs that still list it reject the new one.
`codexUnavailableReason()` now returns `{ flag }` / `{ reason }` so the
resolved name reaches the exec.
Verified against codex-cli 0.145.0: `resolve --type image --provider codex`
generates and freezes an image. New unit tests pin both flag layouts so a
future rename fails loudly instead of silently disabling the provider.
The narrowing this branch adds missed the motion-path overlay, and every
caller that could not narrow fell back to the exact bare class the narrowing
exists to replace.
- motionPathSelection.selectorFor now goes through writeTargetSelector. It
feeds both the geometry read and the "set destination" write, so a class
sibling measured its home off the FIRST sibling and then authored
add-motion-path onto all of them. The toolbar toggle hides when no
one-element form exists rather than arming a press that is dropped.
- The five new-tween writers that fell back to the selection's own selector
now drop the commit instead. A gesture that does not persist reverts on the
next reload; a tween silently aimed at five elements does not.
- tweenTargetsElement only follows the DOM to a target that matches exactly
one element. A target the element merely shares with its siblings is a group
tween, and these callers mutate what they find, so an individual nudge was
rewriting the group's own tween and moving all five.
U3 fixed "add keyframe at playhead" widening a write to every sibling
sharing a class, but wired writeTargetSelector into only two paths. The
same bug was still reachable from the add-animation button, drag, resize,
rotate, gesture recording, and the property panel: each derived its target
from selectorFromSelection, which hands back a bare class for an id-less
element, so one edit authored a tween over all five siblings and the
timeline collapsed their rows into one.
Route every path that authors a NEW tween through the existing ladder:
- ensureElementAddressable now accepts selection.selector only when it
addresses exactly one element, so the id-minting fallback right below it
(previously unreachable whenever any selector was present) does the work.
- gsapDragCommit's five new-tween branches go through one newTweenTarget
helper; instant patches reuse the written target so the runtime moves the
element the source write names.
- useGestureCommit and useAnimatedPropertyCommit keep the existing selector
for matching/retargeting and author new tweens with a separate write
selector.
Retargets of an EXISTING tween are deliberately untouched: they keep
anim.targetSelector, so a tween aimed at a whole group stays aimed at it.
Narrowing the write alone regressed idempotency, verified by test: the
"is there already a write for this element" lookups matched targetSelector
by string, so the next nudge missed the write it had just made and appended
a second, conflicting one. The read half now falls back to the live DOM
(tweenTargetsElement, same contract as getAnimationsForElement), which also
still matches a deliberate group tween.
Tests reproduce each site through a real writer, re-parse with the real
parser, and resolve through resolveSelectorElementIds (what feeds the
keyframe cache and the lanes), plus pins for the new-tween vs
retarget-existing distinction so a future change cannot collapse the two.
Two latent defects in the announcement path this branch adds.
- lanesId was keyed by render row alone, so a second TimelineLanes on the
page (a mini-timeline beside the main one) would mint the same
timeline-lanes-track-0 and every caret's aria-controls would resolve to
whichever instance mounted first. The prefix now comes from useId, with the
colons stripped so the id stays a legal CSS selector.
- trackDisplayNumber returned trackOrder.length + 1 for a key it could not
find, which is indistinguishable from a real row: the label announced a row
the user can see is wrong and nothing upstream could tell it had guessed. It
returns null now, and trackDisplaySuffix drops the number from the label
rather than inventing one.