A progressively-growing feed panel (rows injected after cap tagging)
passed the rotator leaf guard - which only rejected containers with
CAPPED children - and the rotator runtime's textContent writes then
flattened 51 statically-emitted descendants to one text node. Three
layers: emission drops rotators whose IR target has element children;
the capture leaf guard rejects any element child (capped or not); the
DittoMotion runtime saves/restores cloned child nodes via
replaceChildren so even a misclassified rotator can't destroy structure.
425 tests pass (6 new), typecheck clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Capture:
- Preserve real asset extensions (.lottie no longer truncated); extract the
default animation JSON from dotLottie ZIP containers at materialization
(minimal built-in ZIP reader, no new deps)
- Reset scroll + settle before every viewport snapshot so scroll-linked
styles can't bake into captured computed values
- Marquee detection now requires content overflow (>1.35x), sustained
velocity across separated windows, scroll independence (jiggle test), and
genuine content repetition — kills scroll-settle-lerp false positives
- Sizing probe trusts authored explicit heights (px/vh/calc) over circular
parent/child reflow verdicts, fixing dropped 100vh heroes
Normalize/generate:
- Canonicalize identity transforms to "none" per viewport; emit explicit
transform resets across bands when any band has a real transform
- DittoLottie keeps the captured placeholder until DOMLoaded; failed loads
no longer blank the container
- mx-auto only for true auto-margin centering; literal per-band margins are
preserved (fixes full-bleed regressions)
- Spacing-scale snap tightened to 0.25px (3.5px stays p-[3.5px]); emit
whitespace-nowrap for wrap-vulnerable single-line text leaves
- Grid recipes no longer override captured track counts or column spans;
responsive re-flow plans apply only when geometry agrees
Quality scoring:
- Rewritten 6-dimension rubric (payload, decomposition, duplication,
semantics, hygiene, runtime) with catastrophe caps and per-dimension
reporting; thresholds are documented calibration guides
218 tests pass (74 new), typecheck clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
lottie-web renders vector animations from a JSON document at runtime. As
third-party JS it falls outside the declarative CSS path and the WAAPI / reveal /
marquee probes, so clones shipped the empty container and the animation was gone.
This adds a Lottie subset to Stage 5 motion: capture the deterministic part — the
source JSON (materialized local file, or inline animationData) plus playback
config — and emit a fixed DittoLottie client that re-mounts lottie-web on the
cid'd container.
Capture (compiler/src/capture/lottie.ts): in-page detector covering lottie-web's
registry (animationData in memory), <lottie-player>/<dotlottie-player>, Elementor
data-settings (source_json.url), and generic markup. Keyed by data-cid-cap.
motion.ts merges it into MotionCapture; capture.ts registers source URLs as assets
so the existing fallback fetch downloads + materializes them to /assets/cloned/lottie.
Generate (compiler/src/generate/lottie.ts): buildLottieSpec resolves cap->cid and
source URL->materialized local path (or embeds inline animationData), then emits
DittoLottie + wire/import helpers, mirroring DittoMotion. app.ts writes the
component, wires import+JSX, and injects lottie-web into the generated package.json.
Delivery (compiler/src/cli.ts): stripDeliveryDataCids now treats DittoLottie as a
runtime consumer, so its container keeps a semantic data-ditto-id anchor instead of
being stripped (without this the animation never finds its mount point).
Lottie-free clones stay byte-identical. Verified end-to-end: cloning a page with a
<lottie-player> scrapes the JSON, emits a wired DittoLottie, and lottie-web mounts
and plays the captured animation (rendered SVG viewBox matches the source JSON).
Unit tests cover buildLottieSpec resolution + drop rules.
Co-Authored-By: claude-flow <ruv@ruv.net>