open-design/skills/open-design-landing-deck/README.md
Tom Huang aefba56a3f
feat(skills): open-design-landing rename, kami skills, landing OG (#428)
* feat(skills): open-design-landing rename, kami skills, landing OG

- Rename editorial-collage skills to open-design-landing and -deck; refresh examples and compose script layout
- Add kami-deck and kami-landing skills with HTML examples
- Landing page: og.astro, index wiring, and style tweaks; package.json bump
- Web i18n: German and Russian copy for renamed and new skills
- Daemon test: update skill-asset-rewrite expectations for new paths
- Design systems: README and atelier-zero doc touch-ups
- Cross-skill SKILL.md reference updates

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs(landing-page): document version-slot invariant and deprecation timeline

Address P3 review notes on PR #428:
- Note the `data-github-version` wrapper invariant (version string only)
  near the canonical URL block in `app/page.tsx`.
- Expand the `formatVersion` helper comment in `app/pages/index.astro`
  with concrete `release.name` / `tag_name` example shapes for each
  branch of the regex fallback.
- Tighten the `EditorialCollageDeckInputs` deprecation in
  `skills/open-design-landing-deck/schema.ts` to a specific removal
  version (v0.4.0) and add a "Migrating from editorial-collage-deck"
  section to the skill README.

Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code)

* docs(landing-page, skills): clarify version slot script and rename migrations

- Describe GitHub version slots as driven by the inline enhancement script,
  not React hydration.
- Add editorial-collage → open-design-landing migration notes; fix README
  link copy (Astro static landing app).
- Extend deck README migration table with shared asset path renames.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(daemon): alias deprecated editorial-collage skill ids

The PR renames the editorial-collage / editorial-collage-deck skills
to open-design-landing / open-design-landing-deck, but the daemon
persists exact skill_id strings on projects and resolves them via
listSkills().find((s) => s.id === storedId). After the rename, any
project saved against an old id silently composes without the intended
skill prompt because the listing no longer exposes that id.

Add a SKILL_ID_ALIASES map in skills.ts plus a findSkillById() helper
that rewrites deprecated ids to their current canonical form, then
route every server-side lookup (skill detail, example HTML, asset
proxy, system-prompt composer) through it. Cover the alias map, the
resolver, and end-to-end resolution against a temp skills directory
with a regression test.

Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code)

* fix(kami-deck): route host od:slide messages through local go()

The host bridge classifies kami-deck as class-driven because go() toggles
.slide.active, but the visible slide is moved by deck.style.transform
which the bridge cannot drive. Listen for od:slide messages and dispatch
them through the local go() so toolbar next/prev and initialSlideIndex
restore actually shift the deck.

Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code)

* fix(kami-deck): sync deck transform with host-driven .active changes

The previous fix added a local od:slide listener but the host bridge in
apps/web/src/runtime/srcdoc.ts also listens for the same message and
calls setActive() (toggles .slide.active) without driving the deck
transform. Both listeners fired, the bridge re-read the just-toggled
active class, and overshot by one — and the bridge's restoreInitialSlide
path could move .active without a message at all, leaving the deck on
the original transform.

Stop the bridge from double-handling by calling stopImmediatePropagation
in the local listener (registered first because the bridge script is
appended to </body>), and add a MutationObserver that pulls the deck
transform onto whichever slide currently carries .active so the bridge's
direct setActive calls (notably the initial-slide restore) move the deck
too.

Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code)

* fix(i18n): align French content with renamed/new skills

PR #434 (French localization) merged into main with French copy for the
old editorial-collage / editorial-collage-deck skill ids; this branch
renamed those to open-design-landing / open-design-landing-deck and
added kami-deck and kami-landing. Update content.fr.ts to track the
rename and add French copy for the new kami skills so the
LOCALIZED_CONTENT_IDS coverage test passes once main is merged.

Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code)

* fix(open-design-landing-deck): sync deck transform with host-driven .active changes

Apply the same fix that landed in skills/kami-deck/example.html
(commits 96b255b, 8cbca30) to the open-design-landing-deck composer
runtime: the host bridge classifies this deck as class-driven because
go() toggles .slide.active, but the visible slide is moved by
deck.style.transform which the bridge can't drive. Add an od:slide
message listener that calls stopImmediatePropagation() and routes nav
through the local go(), plus a MutationObserver that pulls the deck
transform onto whichever slide carries .active so the bridge's direct
setActive calls (notably restoreInitialSlide) move the deck too.

Regenerates example.html via scripts/compose.ts; the regeneration also
picks up upstream nav-cta and brand-meta CSS additions in the sister
open-design-landing styles.css that the example had drifted from.

Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code)

* docs(open-design-landing): align deploy story with Astro landing app

- Update SKILL contract: apps/landing-page is Astro static; clarify
  nextjs-app output_format as a historical enum label and <out>/nextjs
  as a legacy folder name.
- Replace optional-deploy section with fork + pnpm --filter landing-page build.
- Fix styles.css header and regenerate landing + deck example.html so
  inlined comments match.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(deck-runtime): bypass interaction lock for host/observer slide sync

The slide deck runtimes for kami-deck and open-design-landing-deck
gate go() behind a 700ms `lock` so wheel/key/touch input bursts can't
overshoot the transform transition. But applying the same gate to the
host bridge's od:slide messages and the MutationObserver watching
`.slide.active` creates a startup race: go(0) at the end of init sets
lock=true, and any host-driven `.active` change inside that window
(notably restoreInitialSlide) fires the observer, which calls go(i),
which exits at the lock guard — leaving the visible deck on slide 1
while the host counter advances to N.

Split the actual state update into an unthrottled `applySlide(n)`
helper that updates transform, `.active`, dot nav, and the progress
bar. Keep `lock` only on the user-input path through `go()`. Route
the message listener, the MutationObserver, and the initial render
through `applySlide` directly so host-driven sync always reaches the
deck transform regardless of the throttle state.

Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code)

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-04 19:22:46 +08:00

4.2 KiB

open-design-landing-deck

Sister skill to open-design-landing. Produces a single-file slide deck in the Atelier Zero design language — warm-paper background, italic-serif emphasis, coral terminating dots, surreal collage plates — paginated as a horizontal magazine swipe deck (←/→ · wheel · touch · ESC overview), the same nav model as guizang-ppt.

Read first — agent contract, schema, and self-check live in SKILL.md. This README is the human quick-start.

30-second tour

# 1. Compose the worked example.
npx tsx scripts/compose.ts inputs.example.json example.html

# 2. Open it.
open example.html

The deck assumes 16 collage assets at ../open-design-landing/assets/ (the sister skill ships them). Use ←/→ · Space · PageUp/PageDown · Home/End to navigate, ESC for the overview grid.

What you get

  • N viewport-sized slides (the worked example has 11) laid out horizontally on a transform: translateX(...) flex track.
  • Per-slide chrome strip (top + bottom): brand mark · deck title · location · live NN / TT counter.
  • Coral progress bar at the bottom that fills as you advance.
  • Dot indicator near the bottom (click to jump).
  • ESC overview grid with scaled thumbnails.
  • 7 slide kinds: cover, section, content, stats, quote, cta, end. Mix freely.
  • Same 16-slot image library as the landing-page sister skill — no extra prompting or rendering.

Files

skills/open-design-landing-deck/
├── SKILL.md                 # ← agent contract (read this first)
├── README.md                # ← you are here
├── schema.ts                # typed slide variants + brand block (re-exports from sister)
├── inputs.example.json      # Open Design 11-slide pitch deck
├── example.html             # canonical rendering
└── scripts/
    └── compose.ts           # inputs.json + sister styles.css → index.html

Authoring a deck

  1. Copy inputs.example.json to your project as inputs.json.

  2. Edit brand (or copy from a sister-skill inputs.json you already have).

  3. Set deck_title (the kicker shown in the chrome strip).

  4. Build the slides array. Each entry is one of seven kinds — see schema.ts for the full type. A typical pitch:

    1.  cover     — title plate
    2.  section   — chapter divider
    3-5. content  — manifesto, capabilities, method
    6.  stats     — the numbers
    7.  section   — chapter divider
    8.  content   — selected work
    9.  quote     — customer testimonial
    10. cta       — primary action
    11. end       — kicker word
    
  5. Run the composer:

    npx tsx scripts/compose.ts inputs.json out/index.html
    

Image strategy

The deck inherits the sister skill's 16-slot image library. Set inputs.imagery.assets_path to wherever those PNGs live; the example uses '../open-design-landing/assets/'.

To regenerate or stub:

# Generate via gpt-image-2 (fal.ai)
FAL_KEY=fal-... npx tsx ../open-design-landing/scripts/imagegen.ts \
  ../open-design-landing/inputs.example.json \
  --out=../open-design-landing/assets/

# Or paper-textured SVG placeholders
npx tsx ../open-design-landing/scripts/placeholder.ts ../open-design-landing/assets/

Migrating from editorial-collage-deck

This skill replaces the older editorial-collage-deck skill. The renames are mechanical:

Old New
skill folder editorial-collage-deck/ open-design-landing-deck/
shared assets ../editorial-collage/assets/ ../open-design-landing/assets/
TS type EditorialCollageDeckInputs OpenDesignLandingDeckInputs

The EditorialCollageDeckInputs alias re-exported from schema.ts is a temporary bridge: it is kept for the v0.3.x line and removed in the next minor release (v0.4.0). Update imports before then.

See also