feat(snowflake): Milo substrate flavor + prototype interaction layer#162
Open
vhargrave wants to merge 4 commits into
Open
feat(snowflake): Milo substrate flavor + prototype interaction layer#162vhargrave wants to merge 4 commits into
vhargrave wants to merge 4 commits into
Conversation
Snowflake's EDS substrate replaces head.html + scripts/scripts.js, which on a Milo repo rips out the Milo runtime that loads the live global-navigation + footer from gnav-source/footer-source metadata. The captured gnav then renders as a static, fully-expanded blob. Add a Milo flavor: - assets/substrate-milo/: minimal manifest + blocks/snowflake overlay block (reuses the EDS overlay logic as a Milo block) + VERSION. Installs ONLY the block; Milo keeps head.html/scripts.js/styles.css. - install-substrate.mjs: auto-detect Milo (milolibs/setLibs) or --milo/--flavor; stamp substrateFlavor in .snowflake/config.json. - phases 0/1/3/4: Milo deltas — skip header/footer fragment capture, preserve chrome metadata, emit a Milo DA page (metadata block + one snowflake block). Milo owns the chrome; the snowflake block draws the body from /templates/<t>.html. Verified: real install leaves Milo files byte-identical; headless overlay-block test passes 10/10. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The overlay block injects pre-decorated DOM that Milo does not re-decorate, so per-block CSS never auto-loads (foundation:c2 only loads base styles.css). Phase 3.1 wrongly told the agent to drop body stylesheets, leaving the overlaid body unstyled. Keep ALL block CSS links; drop only global-navigation/footer CSS. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Milo overlay injects pre-decorated, frozen DOM, so captured carousels, auto-rotating marquees, tabs, and accordions render but don't move (the source block JS isn't running on the snowflake'd page). Add a tiny, dependency-free activator to the snowflake overlay block that revives them via an explicit proto-* contract, plus the matching mechanics CSS (scoped under [data-overlay]). Block-agnostic: snowflake just carries the contract markup through; the activator runs at runtime after <main> is overlaid. Phase 3-generate documents the contract and, critically, the capture-mode limit: Figma-sourced prototypes converge to a single static reference image, so off-screen slides never exist — single-frame widgets are left static, never fabricated. The contract is for URL/HTML captures that serialize the full rendered DOM. Verified end-to-end through the real decorate() path (headless): carousel (dots/arrows/swipe/autoplay), marquee autoplay+nav, tabs, accordion. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ve-appearance
Milo's styles.css hides every `main > div` (`main > div { display: none }`) until
it's decorated into a revealed .section. The snowflake overlay replaces Milo's
decorated sections with the template's own top-level containers via
`main.innerHTML = ...`; Milo never re-decorates them, so they stayed display:none
and the prototype rendered blank (gnav only). Reveal them explicitly after inject.
Verified: forcing display:block on the live page's main>div rendered the full
design (hero, nav, bg photo, cards, CTAs, section heading).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add a Milo substrate flavor to the snowflake skill
Problem
On a Milo target repo (e.g.
adobecom/da-playground), the snowflake skill produces a broken page: the global nav renders as a ~4806px, fully-expanded, unstyled blob.Root cause:
install-substrate.mjsreplaceshead.html+scripts/scripts.js(and the header/footer blocks) with the EDS overlay substrate. On a Milo repo that rips out the Milo runtime — the thing that loads the liveglobal-navigation+ footer fromgnav-source/footer-sourcemetadata. With Milo gone, the capture step freezes the rendered gnav DOM into a static fragment, and with noglobal-navigation.jsto collapse it, every mega-menu paints expanded.Fix — a second substrate flavor, auto-detected
The EDS flavor is unchanged. A new Milo flavor is selected automatically when the target boots milolibs (
head.htmlcontainsmilolibs, orscripts/scripts.jscallssetLibs()); override with--flavor=milo|eds/--milo/--eds.The Milo flavor is minimal and additive: it installs only
blocks/snowflake/{js,css}and leaves Milo'shead.html,scripts/scripts.js, andstyles/styles.cssbyte-identical. Milo keeps ownership of the chrome (live gnav/footer from metadata); the bespoke body is drawn by thesnowflakeoverlay block, which Milo loads from the project'scodeRoot. The block reuses the EDS overlay logic verbatim (readBlockSlots/writeSlot5-case /<link>lifting / slot application) — just relocated fromscripts.jsinto a block so it coexists with Milo instead of replacing it.What's in the PR
assets/substrate-milo/—MANIFEST.json(minimalreplace: blocks/snowflake only),blocks/snowflake/{js,css},VERSION.scripts/install-substrate.mjs— flavor auto-detection +--flavor/--milo/--eds; resolves the bundle dir by flavor; stampssubstrateFlavorin.snowflake/config.json. Existing backup/idempotency/drift logic untouched (it's manifest-driven).phases/0,1,3,4— Milo deltas: document flavor detection; capture chrome metadata (not chrome DOM); emit a Milo DA page (empty<header>/<footer>, onesnowflakeblock, ametadatablock re-emittingfoundation/gnav-source/footer-source/unav/universal-nav+template+title); Wire copies onlytemplates/<t>.html+styles/<t>.css, no fragments, no head/scripts changes.Verification
blocks/snowflake/*+ ignore patches added;substrateFlavor: "milo"stamped. EDS flavor still selectable (no regression).<main>from the template, applies slot overrides, keeps template defaults, injects static sections, consumes the authoring block, lifts the template's<link>s, injects per-template CSS, and leaves<header>/<footer>untouched.Prototype interaction layer
The overlay injects pre-decorated, frozen DOM, so interactive widgets (carousel/slider, auto-rotating marquee, tabs, accordion) render but don't move. The
snowflakeblock ships a tiny dependency-free activator that revives them via an explicitproto-*contract (.proto-carousel/.proto-marquee/.proto-tabs/.proto-accordion), with mechanics-only CSS scoped under[data-overlay]. Phase 3 instructs the generate step to rewrite captured widgets to the contract only when the capture retained every state — true for URL/HTML captures, which serialize the full rendered DOM. This is block-agnostic: snowflake just carries the contract markup through; it never decorates or understands a Milo block.Capture-mode limit (important): a Figma-sourced prototype converges to a single static reference image, so off-screen slides never exist. Single-frame widgets are left static and never fabricated — the contract is for full-DOM captures, not Figma. This is prototype-grade motion (slide/advance/toggle), not a 1:1 reimplementation of each C2 block's physics; a true-Milo-blocks conversion remains a separate effort.
Notes / out of scope
unav: onneedsimsClientIdin the host's Milo config to fully hydrate profile/cart; the gnav itself renders regardless.Builds on the snowflake skill merged in #154. Based against
main; touches only the newsubstrate-milo/bundle plus additive Milo deltas toinstall-substrate.mjsand phases 0/1/3/4 — all of which are unchanged inmainsince this work began, so it merges cleanly. (Note: open PR #161 reworks the substrate mechanism; if it lands first this will be rebased.)