Repository navigation
Close the gaps left after the #344 and #359–#387 batch #438
Description
Activity
- added sub-issues
on Sep 29, 2026 #425 is merged (#439). The attribute rewrite left
width="84""behind, so no icon has parsed since #390; the existing tests assertedcontains("width=\"84\""), which is true of the broken string too. Render tests with pixel assertions now cover it — 0 coloured pixels on the revert.render --framealso exits 1 on an unresolvable icon like the other paths, and a cache filled under the old{slug}-{colour}-{w}x{h}naming is migrated rather than refetched.Its fourth item — an offline gate for icons — is #440 rather than part of that PR: #320 has since landed
--allow-remote-fonts, and the icon gate should follow that decision rather than precede it.Decomposition, file partition and frozen contracts
Recorded here so a session with no shared memory can resume it.
Waves
Wave Workstreams, in parallel Owned files 1 #426 + #430 (merged) · #431 · #434 box_builderlibrich_textgradient_textcss/animationcss/cascade·svgshapearrowconnectoranimatorschema/videovalidate_schema·paint_passdot_maprender/backgroundrender/scene2 #429 · #432 · #437 animatorintrinsicrich_texttext·transitionpaint_passvalidate_schema·geometrygradient_textcli/validateencode/tasks3 #427 then #428, one agent, two PRs box_buildertransitionrender/scenepointer·render/scenegeometryschema/shakeengine/shake#426 and #430 are merged into one workstream. They are the same architectural bug under two names:
with_cascaded_stylefolds resolved CSS into a typographic component's clone throughinherit_from, which only fills fields that areNone, so a component declaring its own staticletter-spacingorfont-sizenever sees the animated override at measurement time — only at paint time. Two workstreams editing that one mechanism is a decomposition error, so they are one.#427 and #428 share the camera logic in
render/scene.rs, so they get one writer and two pull requests rather than two writers and a merge conflict.Orchestrator-owned — no sub-agent writes these
crates/rustmotion/skills/SKILL.md,crates/rustmotion/skills/rules/*.md,crates/rustmotion-core/src/css/style.rs,crates/rustmotion-core/src/schema/scenario.rs, and everyCargo.toml.SKILL.mdalone was contended by seven of the twelve issues, because each one's definition of done says vocabulary changes update it. Agents report the exact text they want and where; the deltas are applied in one pass, as #436.Regime
Agents edit disjoint files in one shared checkout and run no git command at all — the orchestrator commits each workstream to its own branch by staging only that workstream's paths. Each agent gets its own
CARGO_TARGET_DIR, since cargo's lock on the target directory otherwise serialises the parallelism the partition just earned. Agents run targeted tests on their own crates only: a full-workspace run in a shared tree tests siblings' unfinished work, so it fails for reasons they cannot act on. The full suite is the orchestrator's, after each integration.Three findings that changed the plan
- Camera: a world larger than the frame, per-segment easing, handheld shake, camera-aware validation #428 item 4 is not already shipped.
SceneShakecarriesimpacts: Vec<ShakeImpact>withdecay,frequencyandrotation: discrete beat-synced hits, not a continuous handheld wobble. The mechanism for a second signal additive overcameraexists; the mode does not. That puts the work inschema/shake.rsandengine/shake.rs, which nobody else writes, and takes item 4 out of the contention onrender/scene.rs. - Transitions: feathered wipes leak at fixed edges, clip-path blob, iris pill, warnings for ignored fields #432 item 4 is one constant.
IRIS_PILL_CORNER_FRACTION = 0.2attransition.rs:655, used ashalf_w.min(half_h) * 0.2at line 692. A stadium needs it near 1.0. - Path drawing: draw_start on finished svg strokes, arrow/connector, draw_offset, svg d morph, dot at progress 0 #431 item 6 is a copy job.
line.rsalready extracts a segment withPathMeasure;arrow.rsandconnector.rsstill use the dash[draw_len, total_len - draw_len + 0.01], and a zero-length dash with a round cap paints a solid dot. Port the existing fix rather than designing one.
- Camera: a world larger than the frame, per-segment easing, handheld shake, camera-aware validation #428 item 4 is not already shipped.
#427 is done — PR #452, green on all four CI jobs. The six items, each verified end to end (scenario,
validate, render, image inspected) as its definition of done asks.Camera motion blur is the one that needed a number before it could be decided, since #362 was parked on exactly that. Measured at 1920×1080 on real content, slope over 180 frames so startup drops out: 4.1 ms/frame without, 8.8 ms/frame at
samples: 8— 2.2× end to end rather than 8×, because encode and frame setup are paid once per frame whatever the render costs. A frame whose camera pose does not change across the shutter window takes the ordinary single-render path, so a held shot is free.#428 is now in progress on top of it, with a head start: the first item's root cause is diagnosed and written into that issue's thread — the content is not missing, the viewport clip is issued after the camera transform and travels with it, so a pan wider than the frame clips everything away. #451 filed that separately and is closed as a duplicate.
#428 is done — PR #453, stacked on #452 while that one waits for its merge.
All four items verified end to end with the issue's own scenarios. The first one was not a missing feature:
clip_rectwas issued after the camera transform, and Skia bakes a clip into device space using the matrix in force at that moment, so the clip travelled with the camera and a pan wider than the frame clipped everything away.validatehad the matching defect on its own side — the camera fold read the staticx/y/zoomfields, so a purely keyframe-driven camera folded as if it never moved.Handheld shake needed no code at all.
scene.shakealready composes additively incamera_pose_at, andeffective_cameraalready synthesises an identity camera when onlyshakeis set. Measured across an impact: −40 px at its peak on top of an ongoing pan, +4 the frame after, 0 before. Two regression tests pin that instead of a second mechanism.With this, every sub-issue of the batch is closed except #435's second half, which is the crates.io release and is a decision rather than work.
One pre-existing gap now written into
geometry-safety.mdrather than left to be discovered: the camera fold accounts forx,yandzoomonly, so an element brought into frame purely bycamera.rotationor an animatedoriginis still reported as an overflow.
Tracking issue for the gaps left after #344 and #359–#387 were closed.
Every closed issue was re-verified against
main(0.7.1,ef0b69e) by re-running its reproductions and rendering its requested features. Several fixes do not reach the render, some sub-requests were never delivered, and a user who built a real one-take product film with 0.7.0 reported further blockers. Each sub-issue below is self-contained: context, items with reproductions, known root causes and a definition of done.Suggested order
icon).border_radius,clip_path_progressorfont_sizeare dropped (one root cause behind Animating border_radius validates and has no effect #373, Animate clip-path: interpolate polygon, inset, circle and ellipse in keyframes #384 and a user report).Sub-issues
Out of scope for now (to discuss)
node()cover part of it.Rules for every sub-issue
main, a render test with pixel assertions for anything visual.validate, render, image inspected) before the PR is merged.