Painting the body's color onto a transparent source html flips CSS 2.1
background propagation: body's background stops propagating to the canvas
and paints above negative-z descendants, burying full-bleed z<0 hero
backdrops under an opaque page background. Emit the html rule only when
the source html actually painted one; fall back to #ffffff only when both
html and body are transparent. Applies to the Next globals, Tailwind, and
multi-route Vite paths via shared helpers.
6 new tests; suite at 322 green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- DittoWire/Accordion/DropdownMenu runtime templates: AbortController-based
listener cleanup, idempotent effects, orphan panel removal on unmount
- Emit a single src/lib/utils.ts cn() instead of a copy per component file
- Collapse captured whitespace runs under white-space:normal (pre* preserved)
- Tag source-injected font-metric probe nodes at capture; drop them from IR
- Snap sub-pixel arbitrary lengths (integer within 0.1px, else 1 decimal)
- Emit SITE_ORIGIN (src/lib/site.ts, env-overridable): sitemap/robots/
canonical/og:url/JSON-LD resolve against the clone's own origin instead of
the source domain
- Pin lottie-web in generated package.json whenever DittoLottie is emitted
144 tests pass (21 new), typecheck clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two follow-ups to the single-page Lottie support:
1. Multi-page (clone-site). generateSiteApp emitted only DittoWire; it now wires
DittoLottie per route exactly like wires — builds the route's lottie spec,
emits the import + JSX, writes DittoLottie.tsx once, and injects lottie-web
into the site package.json when any route replays an animation (the write
moved after the route loop so the dep reflects actual usage). cloneSite now
captures motion on full route captures (motion: full) so lotties are observed;
light sibling probes skip it. Per-route gating verified: a route with no
animation gets no DittoLottie.
2. Inline animationData. When a lottie is only in memory (data-driven init, no
fetchable URL), capture now writes the JSON to the assets store as a real,
content-hashed .json so it materializes to /assets/cloned/lottie like any
source — instead of embedding the blob in the page spec. buildLottieSpec then
resolves it to a local path; the spec carries path, not animationData.
Verified end-to-end: a 2-page fixture emits DittoLottie only on the animated
route with lottie-web added; a data-driven inline fixture materializes
fd7c…json and the spec references it by path.
Co-Authored-By: claude-flow <ruv@ruv.net>