Skip to content

Close the gaps left after the #344 and #359–#387 batch #438

Description

@LeadcodeDev

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

  1. Regression: no icon renders since the icon cache rework (#365) #425 — regression: no icon renders (blocks every scenario using icon).
  2. Animations touching only border_radius, clip_path_progress or font_size are never applied #426 — animations touching only border_radius, clip_path_progress or font_size are 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).
  3. Camera: a world larger than the frame, per-segment easing, handheld shake, camera-aware validation #428 and Motion blur: pointer paths, in-flow ghost placement, velocity-oriented smear, smooth whip, camera motion blur #427 — free camera and motion blur: the user's main blockers.
  4. Text: letter_spacing on rich_text/gradient_text, animated tracking layout, static opacity vs animated opacity, caret after typed text #430, char_* presets: rotate_from, scale/baseline jitter, reflow (undelivered parts of #363) #429, Path drawing: draw_start on finished svg strokes, arrow/connector, draw_offset, svg d morph, dot at progress 0 #431, Transitions: feathered wipes leak at fixed edges, clip-path blob, iris pill, warnings for ignored fields #432, Pointer: waypoints without a click, readable hand/grab glyphs #433, Materials, 3D and backgrounds: inflated banding, globe arcs over time, layout-surface orientation, halo interpolation, box-shadow under transparent boxes #434, Validator and vocabulary consistency: arrow/connector bounds, overflow hints, gradient stops, duplicate warnings #437.
  5. Documentation errors found while verifying the latest features #436 — documentation, then Encoding default and release: 8-bit H.264 by default, publish main #435 — encoding default and release.

Sub-issues

Out of scope for now (to discuss)

  • Sound effects generated from events (clicks, keystrokes): a synthesised score already exists.
  • Free per-frame computed animation (springs, arcs, grouping): expressions and node() cover part of it.

Rules for every sub-issue

  • Test first: a test that fails on main, a render test with pixel assertions for anything visual.
  • Verified end to end (scenario, validate, render, image inspected) before the PR is merged.
  • Docs, rules and schema updated with any vocabulary change; a field the validator accepts must have an effect.
  • One PR per sub-issue. No AI attribution in commits, PRs or comments.

Activity

  1. LeadcodeDev commented on Sep 29, 2026

    @LeadcodeDev
    OwnerAuthor

    #425 is merged (#439). The attribute rewrite left width="84"" behind, so no icon has parsed since #390; the existing tests asserted contains("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 --frame also 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.

  2. LeadcodeDev commented on Sep 29, 2026

    @LeadcodeDev
    OwnerAuthor

    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_builder lib rich_text gradient_text css/animation css/cascade · svg shape arrow connector animator schema/video validate_schema · paint_pass dot_map render/background render/scene
    2 #429 · #432 · #437 animator intrinsic rich_text text · transition paint_pass validate_schema · geometry gradient_text cli/validate encode/tasks
    3 #427 then #428, one agent, two PRs box_builder transition render/scene pointer · render/scene geometry schema/shake engine/shake

    #426 and #430 are merged into one workstream. They are the same architectural bug under two names: with_cascaded_style folds resolved CSS into a typographic component's clone through inherit_from, which only fills fields that are None, so a component declaring its own static letter-spacing or font-size never 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 every Cargo.toml.

    SKILL.md alone 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

  3. LeadcodeDev commented on Sep 29, 2026

    @LeadcodeDev
    OwnerAuthor

    #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.

  4. LeadcodeDev commented on Sep 29, 2026

    @LeadcodeDev
    OwnerAuthor

    #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_rect was 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. validate had the matching defect on its own side — the camera fold read the static x/y/zoom fields, so a purely keyframe-driven camera folded as if it never moved.

    Handheld shake needed no code at all. scene.shake already composes additively in camera_pose_at, and effective_camera already synthesises an identity camera when only shake is 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.md rather than left to be discovered: the camera fold accounts for x, y and zoom only, so an element brought into frame purely by camera.rotation or an animated origin is still reported as an overflow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions