Repository navigation
Let elements build up across beats, plus rendering gaps found reproducing an agency promo #344
Description
Context
I rebuilt a ~56 s agency-made SaaS promo (dark navy background, blue/pink glows, kinetic typography, a tilted app mockup, floating 3D icons) with rustmotion: 25 scenes, 1920×1080, validated and rendered. Comparing the two videos side by side every 0.5 s surfaced gaps that careful scenario authoring cannot close. They are engine limitations, not authoring mistakes, so I'm grouping them here.
The main one is the first: the reference video builds up its elements over time, and rustmotion's scene model tears them down at every cut.
1. Elements cannot build up across beats (main request)
In the reference, the frame is built up:
- a sentence stays on screen while its next words arrive (
On vous a promis que→l'IA allait tout changer); - the app mockup rises at ~19 s and stays until ~29 s while the headline, a rotating benefit line, a pointer, a close-up and then six floating model logos come and go on top of it;
- the background lighting morphs continuously: glows come from the bottom corners between ~10 and 18 s and from the top elsewhere, with no cut.
In a slide view, each scene is rendered alone, and the transition blends two finished frames (transition.rs). Nothing survives a cut. The possible workarounds are all partial:
| Workaround | What it loses |
|---|---|
One long scene, with start_at/end_at on every element |
Per-beat camera keyframes, per-beat layout, and readability: a 10 s scene with 20 time-windowed children is hard to author and review |
world view |
Continuity comes from the camera travelling through space, so every beat has to live somewhere else in the world. Elements still don't stay put in the frame while others arrive |
| Duplicate the persistent element in consecutive scenes | Its animation restarts at each cut, and the fade transition makes it flicker |
Wanted: a way to declare an element (or a layer) that spans several consecutive beats and keeps its own animation clock, while each beat adds or removes elements on top of it. Two possible shapes:
- a view-level or scenario-level
layers/persisttrack; - scenes that can overlap on the v2 absolute timeline (
at) and composite on top of each other instead of replacing one another.
Background values should also interpolate between beats inside such a span (background.transition exists but only for scene-to-scene).
2. halo only draws circles
HaloZone has a single radius. The reference uses:
- a thin, wide elliptical light along the top edge;
- a dark octagonal frame (corners cut diagonally) over the glows.
Neither can be expressed. An ellipse needs radius_x/radius_y (or scale_y), plus a rotation. The chamfered frame would be possible with style.clip-path, but it is currently inert (#339).
3. No radial zoom-blur ("tunnel") transition
At ~5 s the reference exits a scene through a radial zoom blur: the content streaks outward from the centre, then the next scene appears. zoom_in scales a sharp frame buffer. The per-element motion_blur effect doesn't help either, because the effect applies to the whole frame at the cut.
Wanted: a zoom_blur (radial blur) transition with strength and an origin.
4. No chromatic fringe on a single element
The reference shows an icon card arriving with red/cyan channel separation. chromatic_wipe does this for a transition only. Wanted: an animation effect such as { "name": "chromatic_aberration", "amount": …, "duration": … } on any node.
5. pointer has no outline-only style
PointerTone is light | dark, both filled. The reference pointer is a white outline over a transparent fill. Wanted: e.g. "fill": "none" or tone: "outline".
6. No glossy 3D material for shapes and icons
The reference's 4-point sparkles and model-logo tiles look like rendered 3D: a highlight, a specular edge, a soft inner shade, and depth of field (some tiles blurred because they're out of focus). The best available approximation is a flat SVG gradient, and per-element filter: blur animated by hand. Depth of field tied to style.depth or to a camera focus distance would cover the blur part.
Priority, in my view
1 ≫ 2 > 3 > 5 > 4 > 6. Point 1 is what makes a rustmotion render read as a series of slides instead of a continuous motion design piece.
Activity
feat(timing): overlapping v2 scenes composite instead of being clamped (
fix(background): halo zones can be wide ellipses, not just circles (#351
feat(transition): add zoom_blur, the radial "tunnel" cut
feat(animation): per-element chromatic aberration (issue #344 point 4)
feat(pointer): add an outline tone with a transparent fill and white …
feat(transition): add zoom_blur, the radial "tunnel" cut (#352)
feat(animation): per-element chromatic aberration (issue #344 point 4)
feat(animation): chromatic_aberration, a red/cyan fringe on any node (#…
LeadcodeDev commentedon Sep 26, 2026
Five of the six points are on
main.atwindows composite instead of being clampedhaloonly draws circlesradius_x/radius_y/rotation, blur follows the short axiszoom_blurwithstrengthandoriginchromatic_aberrationanimation effectpointerhas no outline-only stylePointerTone::OutlineOn point 1
You listed two possible shapes. The codebase had already chosen:
build_slide_view_tasks_v2resolved every scene'satonto an absolute timeline and then threw the overlap away with "clamped to avoid an overlap this workstream does not model". That is a deferred TODO rather than a design objection, so overlapping scenes won over a separatelayerstrack — no new vocabulary, andatalready parsed it.The distinction that took the work was keeping snapping out of it.
snap: "beat"can round a cut earlier than the previous scene's end; at 24 BPM a beat is 2.5 s, soat: "@3.0s"lands half a second inside its predecessor. Reading that as intent would have mademigrate+snapsilently shorten every file it touched — caught at 15.0 s → 13.3 s. Placement now resolves twice, as written and snapped: an overlap the author wrote composites, an overlap only quantisation produced is pushed forward.A demo exercising all five
A 17.8 s scenario where a banner, a panel, an octagonal
clip-pathand an outline pointer persist across four beats while the centre text changes, each arriving with a chromatic fringe, over an elliptical halo, cutting to a second view through azoom_blur. Video and audio both 17.8 s, sound at −7.8 dB throughout.Found while building it, filed separately
#349 —
audio_spectrumandwaveformstay pinned at their minimum on a synthesised score. The two obvious ways to give a generated video a soundtrack and show it cannot currently be combined. Same shape as #339: declared, documented, accepted by the validator, inert at render.