
Codeck Design
- 173 installs
- 206 repo stars
- Updated June 28, 2026
- hiyeshu/codeck
Apply layout, typography, color, and brand rules when building Codeck decks so slides match product visual standards and accessibility expectations.
About
Codeck-design extends deck generation with explicit visual design guidance—spacing grids, palette usage, type scales, and branded motifs—so agent-produced presentations look intentional and consistent with the product’s UI language rather than generic bullet slides.
- Brand token enforcement
- Slide layout patterns
- Typography hierarchy
- Accessible contrast checks
- Component-aligned visuals
Codeck Design by the numbers
- 173 all-time installs (skills.sh)
- +1 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #968 of 1,880 Design & UI/UX skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/hiyeshu/codeck --skill codeck-designAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 173 |
|---|---|
| repo stars | ★ 206 |
| Last updated | June 28, 2026 |
| Repository | hiyeshu/codeck ↗ |
What it does
Apply layout, typography, color, and brand rules when building Codeck decks so slides match product visual standards and accessibility expectations.
Files
<!-- [INPUT]: Depends on deck.md, diagnosis.md, DESIGN references, and room decision state. [OUTPUT]: Provides validated DESIGN.md, custom.css, slides.html, assembled HTML, and design lane memory. [POS]: skills/codeck-design lane; converts canonical content into the visual source of truth. [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md -->
codeck design — @design lane
@design owns visual direction, validated design archive, design skeleton, HTML source, and assembled HTML.
Write boundaries:
- May write
$DECK_DIR/DESIGN.md,$DECK_DIR/custom.css,$DECK_DIR/slides.html - May write generated or processed visual assets to
$DECK_DIR/assets - May assemble the final
./{title}-r{revision}.htmlin the user's project directory - May update
$DECK_DIR/roles/design.md,$DECK_DIR/tasks/tasks.md, and$DECK_DIR/channel/YYYY-MM-DD.md - Must not rewrite
deck.mdexcept for a user-requested concrete edit routed through @orchestrator; otherwise write a proposal tothreads/threads.md - Must not edit
review.md,speech.md, or export files
Role activation
Read $DECK_DIR/diagnosis.md for the recommended design role and its structural mapping.
You are that person. Their formal logic — how they organize space, tension, rhythm — becomes your visual logic.
The role is chosen for structural match, not domain:
Content builds layer by layer, each page adding complexity → Ravel (Bolero): visual simplicity to richness, color gradually saturates, each page adds one element.
>
Content driven by contrast and opposing forces → Caravaggio: high-contrast lighting, black-white dominant, accent color used sparingly like a decisive stroke.
>
Content illuminates through structure and clarity → Bach manuscript: warm parchment ground, ink-weight hierarchy, grid precision, light as organizing principle — not dark by default.
>
Content strips away noise to reveal one truth → Dieter Rams: remove everything unnecessary, final slide is the emptiest and most powerful.
Apply their formal logic directly. Don't explain their principles — embody them in every visual choice.
If diagnosis.md doesn't exist, run /codeck entry logic first when possible. Do not ask a generic setup question.
Decision Ask Policy
Use the shared /codeck Decision Ask Policy.
Design Direction is the only Decision Ask moment in this skill. It may appear before visual generation, or when the user says "change the visual style".
Skip it when the user has already provided a clear style, reference, skeleton, or confirmed direction in MEMORY.md, roles/design.md, deck.md, or DESIGN.md.
When Design Direction is necessary, create a D-YYYYMMDD-NN decision in threads/threads.md first. Then render it through the current runtime:
1. Re-ground — "codeck design, Design Direction" 2. Current read — content structure and visual implication 3. Recommendation — one direction and why 4. Options — 2-3 mutually exclusive visual directions
Only state verified facts. For unrendered results, say "will" not "is".
If no structured AskUser UI is available and the visual direction is blocking, stop before writing DESIGN.md, custom.css, or slides.html. If the decision is non-blocking, use the recommended direction and record assumed default.
Setup
DECK_DIR="$HOME/.codeck/projects/$(basename "$(pwd)")"
CODECK_SKILL_DIR="${CODECK_SKILL_DIR:-}"
if [ -z "$CODECK_SKILL_DIR" ]; then
for d in "$HOME/.agents/skills/codeck" "$HOME/.codex/skills/codeck" "$HOME/.claude/skills/codeck"; do
if [ -d "$d/scripts" ]; then CODECK_SKILL_DIR="$d"; break; fi
done
fi
[ -n "$CODECK_SKILL_DIR" ] || { echo "codeck skill scripts not found" >&2; exit 1; }
mkdir -p "$DECK_DIR"
mkdir -p "$DECK_DIR/channel" "$DECK_DIR/tasks" "$DECK_DIR/threads" "$DECK_DIR/roles" "$DECK_DIR/assets"
bash "$CODECK_SKILL_DIR/scripts/init-room.sh" "$DECK_DIR"
bash "$CODECK_SKILL_DIR/scripts/status.sh" "$DECK_DIR"Read $DECK_DIR/MEMORY.md, active rows in $DECK_DIR/tasks/tasks.md, open rows in $DECK_DIR/threads/threads.md, and $DECK_DIR/roles/design.md. Do not read channel/YYYY-MM-DD.md unless debugging history. Read $DECK_DIR/deck.md — page structure, content points, user intent, note to designer. Ignore legacy outline.md. Read $DECK_DIR/diagnosis.md — role, domain, expression challenge.
If deck.md does not exist, route back to /codeck to create the content source. Do not ask "run outline first?"
Role transition
Read the "note to designer" at the end of deck.md. Write 1-2 sentences in your activated role's voice explaining how you'll turn the content source into visuals.
Before writing visual files, claim the work ticket:
@orchestrator
Owner: @design. Task: turn deck content into visual source and assembled HTML.
@design
I claim the design pass. I will write and validate `DESIGN.md`, then write `custom.css`, `slides.html`, build HTML, and hand off to @review.Append the exchange to today's channel file and update tasks/tasks.md.
Reference extraction (optional)
If the user provides visual references (URLs, screenshots, design specs), extract design signals before the isomorphic mapping. When the user mentions a brand by name without a URL, browse their site yourself.
How to extract:
- Color: primary by area dominance, secondary by supporting role, accent by CTA usage. Map neutral scale from lightest background to darkest text.
- Typography: identify by visual characteristics (geometric, humanist, serif class), not by guessing font names. Estimate scale ratio from heading/body size relationship.
- Spatial rhythm: assess density by element proximity, rhythm by section gap consistency.
- Material/texture: classify shadow softness, spread, layering. Note glass, grain, gradients.
- Motion: if observable, note easing curves and duration feel.
Multiple references → find the intersection. If references conflict with no clear intersection, note the dominant pattern and mention variants — let the user choose in the style reveal.
References inform the mapping, not override it. If a signal conflicts with the content structure, explain why you're diverging.
Fold extracted signals into the design skeleton and record the final structural choices in $DECK_DIR/DESIGN.md.
Image Asset Work
Image work belongs to @design. It is not a separate user command and not a fixed menu of image types.
Handle any visual asset the deck needs:
- improve user-provided images
- crop, resize, recolor, de-noise, or normalize ratio
- clean screenshots and make UI readable on stage
- redesign messy screenshots into slide-safe assets
- generate missing visuals
- compose several assets into one clearer visual
- skip raster images when HTML, CSS, or SVG is more accurate
Decision order:
1. What job must the visual do on this slide? 2. What slot and ratio does the skeleton require? 3. Does the user already provide a usable asset? 4. Can HTML, CSS, or SVG express it better than raster? 5. If raster is needed, should @design improve, adapt, generate, compose, or leave a placeholder?
Default behavior:
- Preserve the meaning of user-provided images.
- Improve fit, crop, contrast, framing, and deck-level consistency without asking.
- Do not alter factual content, people, logos, product UI, chart values, legal text, or brand identity unless the user explicitly asks.
- If a user asset is semantically important but visually weak, create a cleaned derivative and keep the source path in the record.
- If no asset exists and the slide needs one, generate or compose an asset.
- If an image would be decorative only, skip it and make typography, CSS, SVG, layout, or whitespace carry the slide.
Decision Ask is allowed only when image work changes meaning or deck direction:
- replacing a real product screenshot with a stylized version
- changing a person's appearance or identity cues
- inventing a scene that could be mistaken for documentation
- removing or altering brand, legal, or factual content
- choosing between visual approaches that change the deck's tone
Do not ask whether to crop, improve contrast, normalize ratios, clean a screenshot, create a placeholder, or use an asset already present.
Read references/asset-guide.md before asset work. Its shapes are examples, not modes. If none fit, invent the right asset shape.
Record image work in:
DESIGN.md## Image Assets— visual strategy, asset decisions, generated prompt constraintsroles/design.md## Asset Work— current lane state and generated/processed filesMEMORY.mdArtifacts — only final asset outputs that matter for rebuildsthreads/threads.md— any neededdeck.mdasset-manifest update, because@outlineownsdeck.md
Visual recipe library
Before writing DESIGN.md, read these four reference files:
references/theme-presets.md— named visual systems with palette, type, material, and motion defaultsreferences/layout-recipes.md— page-structure recipes chosen by rhetorical jobreferences/component-recipes.md— concrete component patterns for stats, callouts, rowlines, diagrams, media, and chromereferences/image-prompts.md— prompt recipes for generated, cleaned, redesigned, or composited assets
Use them as ingredients, not templates. The fixed engine remains codeck's runtime; do not copy external template code, JavaScript, or CSS shells.
Selection order:
1. Pick one theme preset or define custom-{name} only when no preset fits. 2. Pick 4-8 layout recipes that match the deck's slide purposes. 3. Pick component recipes only for repeated structures that appear in the deck. 4. Pick image prompt recipes only when raster or processed assets are actually needed; otherwise record none — {reason}.
Record all four choices in DESIGN.md:
Theme preset: {preset}
Layout recipes: {recipe-a}, {recipe-b}, ...
Component recipes: {recipe-a}, {recipe-b}, ...
Image prompt recipes: {recipe-a | none — reason}Design skeletons
Read references/skeletons.md before writing DESIGN.md.
A skeleton is the deck's page rhythm, layout grammar, and default slide family. It is not a theme, template, or asset pack.
Selection order:
1. Explicit user style, brand, reference, screenshot, or existing DESIGN.md 2. Current skeleton in $DECK_DIR/roles/design.md 3. diagnosis.md expression challenge plus the content's formal structure 4. The narrative grid skeleton, adapted to the deck's argument
Default skeleton:
| Skeleton | Use for |
|---|---|
narrative-grid | argument-led decks with clear page roles, hero/body rhythm, stable media slots, data posters, quotes, pipelines, and before/after pages |
User references modify the skeleton; they do not replace the room protocol. Extract structural rules, name the variant, and record it in DESIGN.md and roles/design.md. Do not create a new permanent skeleton file unless the user asks.
Record the selected skeleton in DESIGN.md ## Overview as Skeleton: {name} and in roles/design.md under ## Current Skeleton.
DESIGN.md: isomorphic mapping → design archive
Three steps: select the skeleton, find the isomorphic mapping (conceptual), then output DESIGN.md (specification).
Step 1: Select skeleton
Use references/skeletons.md and the current deck structure. Start from narrative-grid, then adapt the page pattern sequence to the argument.
The skeleton answers:
- Which slide families exist?
- How does density change across the deck?
- What visual element carries the argument?
- How much variation is allowed between pages?
- What must the reviewer protect?
Step 2: Isomorphic mapping
Extract the formal structure from the outline (not the content itself):
- Tension curve — narrative tension-release rhythm
- Information density — where it's dense, where it breathes
- Argument topology — linear, branching, layered, contrastive
- Emotional arc — what emotion to what emotion
Find structurally similar things in your role's knowledge domain:
A layered business proposal → Ravel's Bolero → visually simple to complex, each page adds a layer, color gradually saturates
>
A contrastive technical argument → Go attack and defense → black-white contrast dominant, each turn uses one accent color as a "move"
>
A structured explanation that builds understanding → architectural blueprint → warm off-white ground, precise lines, information revealed through spatial hierarchy, not through darkness
>
A data report moving from chaos to order → Japanese karesansui → early pages scattered, final page stripped to minimal
Even flat lists have a formal structure (accumulation, enumeration, crescendo). Always do the isomorphic mapping — it's what makes codeck decks distinctive.
Step 3: Generate DESIGN.md
Read references/design-md-spec.md — the codeck DESIGN.md format spec, based on Google design.md. YAML front matter carries machine-readable tokens; Markdown sections carry design rationale and creative intent. The spec header documents the codeck environment constraints; the AI decides how to converge.
Every token and section must be populated with deliberate decisions — no empty strings, no placeholder text. Use "none" only inside YAML when a token truly does not apply; prose sections that do not apply must say Not applicable — {concrete reason}. A complete DESIGN.md forces deliberate decisions across all dimensions; skipping fields causes downstream generation to lack information.
Minimum archive shape:
- YAML front matter with full color, typography, spacing, rounded, and component tokens from
design-md-spec.md - all 10 sections in spec order: Overview, Colors, Typography, Layout, Elevation & Depth, Shapes, Components, Visual Effects, Image Assets, Do's and Don'ts
- explicit selected theme preset, layout recipes, component recipes, and image prompt recipes
- at least one concrete rule per major component family that appears in the deck
- explicit skeleton mapping, type ratio, slide rhythm, motion policy, and asset strategy
- no placeholder language
Write to $DECK_DIR/DESIGN.md.
Run validation immediately after writing:
CODECK_DESIGN_DIR="${CODECK_DESIGN_DIR:-}"
if [ -z "$CODECK_DESIGN_DIR" ]; then
for d in "$HOME/.agents/skills/codeck-design" "$HOME/.codex/skills/codeck-design" "$HOME/.claude/skills/codeck-design"; do
if [ -d "$d/scripts" ]; then CODECK_DESIGN_DIR="$d"; break; fi
done
fi
[ -n "$CODECK_DESIGN_DIR" ] || { echo "codeck-design scripts not found" >&2; exit 1; }
bash "$CODECK_DESIGN_DIR/scripts/validate-design.sh" "$DECK_DIR/DESIGN.md"If validation fails, revise DESIGN.md directly and rerun validation. Do not write custom.css or slides.html until validation passes.
Style reveal
This is the Design Direction Decision Ask moment.
Show the user three things: (1) the content's formal structure, (2) the isomorphic match and why it is structural, not decorative, (3) concrete visual consequences.
Offer 2-3 directions. Make the recommendation explicit.
- A) Go with this (recommended)
- B) I have a different idea
- C) Show me a few directions to choose from
If the decision is non-blocking and the user does not answer, use A. Write assumed default to MEMORY.md, and write the final visual direction and selected skeleton to DESIGN.md and roles/design.md. If the decision is blocking and no structured AskUser UI is available, leave it open in threads/threads.md and stop before writing visual source.
Visual impact — quality gate
Correct and forgettable is a failure mode. Read references/visual-floor.md after DESIGN.md validates and before writing custom.css — 3 CSS benchmarks (dark cinematic, light editorial, minimal tension). Your output must be at least that level.
Pick the closest benchmark, compare element by element. If flatter, push the DESIGN.md harder before proceeding.
Generate content
Architecture: fixed engine, AI writes content and styles only
The slide engine (navigation, fragments, overview, speaker mode, progress bar, FOUC protection) is fixed code in scripts/engine.js and scripts/engine.css. Every deck uses the same engine.
AI writes two files:
| File | Contents |
|---|---|
$DECK_DIR/custom.css | :root variables + layout primitives + per-page styles + mobile |
$DECK_DIR/slides.html | <section class="slide"> sequence |
*Bash assembles the final HTML. This is the only valid path to a project-root `-rN.html`:**
CODECK_DESIGN_DIR="${CODECK_DESIGN_DIR:-}"
if [ -z "$CODECK_DESIGN_DIR" ]; then
for d in "$HOME/.agents/skills/codeck-design" "$HOME/.codex/skills/codeck-design" "$HOME/.claude/skills/codeck-design"; do
if [ -d "$d/scripts" ]; then CODECK_DESIGN_DIR="$d"; break; fi
done
fi
[ -n "$CODECK_DESIGN_DIR" ] || { echo "codeck-design scripts not found" >&2; exit 1; }
ENGINE_DIR="$CODECK_DESIGN_DIR/scripts"
bash "$ENGINE_DIR/build-html.sh" "$DECK_DIR" "{file-stem}" "{language}" "."Never hand-write the final project-root HTML. Never create a sibling project-root CSS file such as {file-stem}-deck.css. Final HTML must be self-contained and must contain the engine markers openPresenter, codeck-presenter, and BroadcastChannel; otherwise speaker mode was not assembled.
Engine capabilities (engine.js — do not reimplement)
1. Page navigation — arrow keys / space / PageDown 2. Fragment stepping — data-f="N" attribute, ArrowDown to reveal, ArrowUp to hide 3. Overview mode — Esc toggle, thumbnail grid, click to jump 4. Progress bar + page number — auto-created 5. Mobile navigation — auto-created bottom button bar 6. FOUC protection — double rAF before display 7. Speaker notes — reads data-notes attribute 8. Speaker mode — P key opens synced window (BroadcastChannel), shows current/next/notes/timer
custom.css
Read references/design-md-guide.md for full mapping rules: DESIGN.md → custom.css.
Flow: YAML front matter tokens → :root CSS variables → layout primitives → slide type styles → mobile.
Critical: --bg, --fg, --accent are engine interface variables. engine.css uses them for progress bar, overview borders, page numbers. They must be defined in :root.
Do not style engine selectors: .slide, #progress, .mobile-nav, or .presenter-*. Use slide-specific classes such as .slide-cover, .route-map, or .station-panel; the engine owns the shell.
slides.html
Before writing slides.html, read DESIGN.md ## Components and apply the component semantics from references/design-md-spec.md.
<!-- ====== 1. Cover ====== -->
<section class="slide slide-cover" data-notes="Opening: lead with the problem, not the product">
<h1 class="title-mega">Title</h1>
<p class="body-text" style="opacity:0.7">Subtitle</p>
</section>
<!-- ====== 2. Problem ====== -->
<section class="slide" data-notes="Data from the 2024 report">
<h2 class="title-large">What is the problem</h2>
<div class="grid-2">
<div class="card" data-f="1">First point</div>
<div class="card" data-f="2">Second point</div>
</div>
</section>Conventions:
- Each
<section class="slide" data-notes="...">is one page data-notes: 1-2 sentence summary of that page's key point fromdeck.md- Separate pages with comments:
<!-- ====== N. Title ====== --> - Free HTML inside — no block type restrictions
data-f="N": fragment stepping (lower N appears first)- No
<!doctype>,<html>,<head>,<body>,<main class="deck">, stylesheet links,<script>tags, progress bar, or mobile nav — engine handles all of it
Asset references
Read references/asset-guide.md for image asset work, example asset shapes, and inline/poster/extract patterns.
Generated and processed assets go in $DECK_DIR/assets/.
Naming:
{slide-number}-{semantic-name}-{work}.{ext}Examples:
03-dashboard-clean.png04-system-map-generated.png06-founder-photo-crop.jpg08-ui-redesign.png
Write + assemble
1. Write $DECK_DIR/custom.css with Write tool 2. Write $DECK_DIR/slides.html with Write tool 3. Run build-html.sh with Bash; it calls assemble.sh and rejects HTML without speaker mode
If slides.html is long and a single write fails, write the first few pages then append with Edit.
Self-review
After assembling, check the final HTML:
1. Page count — matches deck.md? 2. Comment anchors — every page has <!-- ====== N. Title ====== -->? 3. data-notes — every slide section has the attribute? 4. CSS variables — :root defines --bg, --fg, --accent, --font-body, --font-heading? 5. Mobile — custom.css has @media (max-width: 768px)? 6. Content accuracy — text comes from source material, no fabricated data? 7. No engine code — no <script> tags in slides.html? 8. Speaker mode present — final HTML contains openPresenter, codeck-presenter, and BroadcastChannel? 9. Self-contained — final HTML has no <link rel="stylesheet" ...> and no required sibling CSS file?
Fix issues directly (Edit custom.css or slides.html, then run build-html.sh). Don't ask the user.
Iteration
Do not use Decision Ask for generic iteration.
If the user asks for a visual change, edit $DECK_DIR/slides.html or $DECK_DIR/custom.css, then run build-html.sh. If the change requires deck.md, write a proposal in threads/threads.md and hand the ticket to @outline. For a new user request later, create the next revision.
End with the output path and the highest-signal note about what changed. The user can ask for concrete edits such as "make slide 3 lighter" or "switch to a warm palette".
Handoff
After assembling and self-review:
1. Update MEMORY.md Active Context, Latest Channel Summary, Task Index, and Artifacts. 2. Mark the @design task done in tasks/tasks.md. 3. If content or style needs a user decision, write it to threads/threads.md. 4. Append the handoff to today's channel file:
@design
I wrote validated `DESIGN.md`, `custom.css`, `slides.html`, and assembled the HTML. The next owner is @review.
@review
I will inspect the rendered deck through the audience lens and fix scoped source issues.Gotchas
- Google Fonts allowed, but always with fallback. Use
@import url()at the top of custom.css — assemble.sh places it inside<style>in<head>. Always include a system font fallback stack. Offline = fallback renders, no breakage. - No `<script>` in slides.html. Engine handles all JS. A stray
<script>causes double-binding, broken navigation, and mystery bugs. - `:root` variables are an API contract.
--bg,--fg,--accentare consumed by engine.css. Missing or misspelled = broken progress bar, invisible page numbers, white-on-white overview mode. - Fragment numbers must be sequential starting from 1.
data-f="1",data-f="2", etc. Gaps (1, 3, 5) cause the engine to skip steps. Duplicates cause simultaneous reveals. - Don't override engine classes.
.slide,#progress,.mobile-nav,.presenter-*belong to the engine. Overriding them produces layout corruption that's invisible until speaker mode or mobile. - Never set `position` on `.slide` or slide-type classes.
.slideisposition: absolute; inset: 0in engine.css — that's what makes it fill the viewport.position: relativeon.slide-coveretc. breaks this: the slide shrinks to content height, leaving a dead zone at the bottom. - CSS animations + `prefers-reduced-motion`. If custom.css has
@keyframes, wrap them:@media (prefers-reduced-motion: no-preference) { ... }. Skip this = accessibility failure. - Hard-coded colors in slides.html = unmaintainable. One palette change and you're hunting through 30 slides. Use CSS classes and
var()exclusively. - Cover slide defaults to centered title + subtitle. If the design role calls for symmetry (classical, minimal, editorial), centering is correct. Otherwise, break it — asymmetry signals intentional design.
- CSS negation of math functions silently fails.
-clamp(...),-min(...),-max(...)are silently discarded by browsers — no error, no warning, just wrong position. Always writecalc(-1 * clamp(...))instead. - Height breakpoints, not just width. Laptops with browser chrome show ~600px viewport height. Add
@media (max-height: 700px)and@media (max-height: 500px)to reduce title sizes and hide decorative elements. Width-only breakpoints miss the most common overflow scenario. - Content density has hard limits. Title slide: 1 heading + 1 subtitle max. Content slide: 1 heading + 6 bullets or 2 short paragraphs max. Data slide: 1 heading + 4 metric cards max. Code slide: 10 lines max. Exceeding these = viewport overflow. Split into multiple slides, never cram.
- Assemble.sh auto-increments revision. Don't manually name output files. Let the script handle
r1,r2, etc. Manual names break the revision chain.
Done
codeck design complete.
>
@design
I wrote the visual source, assembled the HTML, and handed the room to @review.
>
{One sentence — cite the DESIGN.md isomorphic mapping}
>
Output: ./{title}-r{revision}.html (in user's project directory)Intermediates: $DECK_DIR/DESIGN.mdNext: /codeck will inspect and fix.Asset References Guide
deck.md asset list marks each resource's level:
Asset Work Contract
Asset work starts from the slide need, not from an image category.
The contract:
- Preserve meaning.
- Fit the slot.
- Serve the slide.
- Record what changed.
Decision order:
1. Define the visual job: evidence, atmosphere, explanation, comparison, product proof, system structure, or emotional stake. 2. Choose the slot and ratio from the skeleton. 3. Inspect user-provided assets first. 4. Prefer HTML, CSS, or SVG when editability or factual precision matters. 5. Use raster work only when it adds clear value: photo treatment, screenshot cleanup, generated scene, composite visual, or image polish.
Default actions:
- If the user provides a usable image, improve crop, contrast, framing, and ratio without asking.
- If a screenshot is too tall, noisy, or low contrast, create a cleaned derivative.
- If a visual is missing and the slide needs one, generate or compose an asset.
- If a diagram needs exact labels or future edits, draw it in HTML/SVG instead of generating a raster image.
- If an image would only decorate, skip it.
Ask only when the asset work changes meaning, identity, facts, legal/brand content, or the deck's visual direction.
Recording
Write visual asset strategy to DESIGN.md:
## Image Assets
Strategy: {how images support this deck's argument and skeleton}
| Slide | Source | Output | Work | Slot | Ratio | Reason |
|-------|--------|--------|------|------|-------|--------|
| 3 | raw screenshot | assets/03-dashboard-clean.png | clean + crop | UI beside text | 16:10 | make the workflow readable on stage |Write lane state to roles/design.md:
## Asset Work
- Current rule: {crop / contain / generate / skip}
- Generated or processed files:
- assets/03-dashboard-clean.png — cleaned from {source}If deck.md needs an asset manifest update, write a proposal to threads/threads.md; @outline owns deck.md.
For generated assets, include prompt constraints in DESIGN.md:
| Slide | Output | Prompt seed | Negative constraints |
|-------|--------|-------------|----------------------|
| 4 | assets/04-system-map-generated.png | {short slot-aware prompt} | no slide chrome, no logo, no footer, no page number |Example Asset Shapes
These are examples, not modes. Start from the slide need, then borrow a shape if useful.
Documentary Visual
Use when the slide needs reality, atmosphere, human stakes, or a field anchor.
Good for:
- opening hook
- founder or team story
- field scene
- audience pain
- physical artifact
Avoid when:
- the slide needs exact evidence
- the scene could be mistaken for a real documented event
- a diagram would explain better
Prompt seed:
Horizontal editorial documentary image about {slide idea}. Real setting, natural light, low saturation, subtle grain, room for overlaid slide text. No logo, watermark, staged advertising, slide title, footer, page number, signature, or decorative frame. Ratio: {slot ratio}.Explanatory Diagram
Use when the slide needs to make structure visible.
Good for:
- system relationship
- before/after
- pipeline
- data flow
- concept map
- stakeholder map
Avoid when:
- HTML/SVG can draw it more accurately
- labels must be exact and editable
- the diagram is core evidence
Prompt seed:
Horizontal explanatory diagram showing {relationship or process}. Fine lines, nodes, short labels, clear spacing, restrained palette matching the deck. Text language: {language}. No slide title, header, footer, page number, logo, watermark, signature, or decorative frame. Ratio: {slot ratio}.UI Screenshot Redesign
Use when the user provides a screenshot but it is too tall, messy, low contrast, or visually inconsistent.
Good for:
- product workflow
- dashboard
- code editor
- browser workspace
- design tool screen
- before/after product state
Avoid when:
- the screenshot is legal, audit, or compliance evidence
- exact UI text must stay pixel-true
- brand identity must remain unchanged
Prompt seed:
Redesign this interface screenshot into a slide-safe horizontal UI visual. Preserve the real workflow feeling, improve hierarchy, contrast, spacing, and readability. Keep text in {language}. Do not invent brand logos or new facts. No slide title, footer, page number, signature, watermark, or decorative frame. Ratio: 16:10.Data Poster
Use when one number carries the argument.
Good for:
- key metric
- shocking contrast
- milestone
- market size
- time saved
- cost reduced
Avoid when:
- many numbers compete
- chart accuracy matters
- the number still needs source validation
Prompt seed:
Horizontal data-poster visual centered on the number {number}, meaning {meaning}. Large typographic number, short supporting annotation, fine lines, paper-like texture, restrained palette matching the deck. No slide title, footer, page number, logo, watermark, signature, or decorative frame. Ratio: 16:9.Composite Visual
Use when one slide needs to combine several existing assets into one clearer visual.
Good for:
- three screenshots into one panel
- photo plus annotation
- product state sequence
- source material collage
- timeline wall
Avoid when:
- composition hides evidence
- user assets must stay untouched
- a simple HTML layout works better
Prompt seed:
Compose these assets into one horizontal presentation visual. Keep each source recognizable, normalize scale, margin, contrast, and visual density, and leave room for HTML text. Do not add facts, logos, slide chrome, page numbers, signature, watermark, or decorative frame. Ratio: {slot ratio}.Cleaned User Image
Use when a user-provided image is semantically right but visually weak.
Good for:
- dark screenshots
- blurry exports
- uneven photo crop
- noisy background
- mixed-ratio image sets
Avoid when:
- cleanup would remove meaningful details
- crop would hide evidence
- the user requested the original untouched
Prompt seed:
Clean this image for a 16:9 presentation slide while preserving its meaning. Improve crop, exposure, contrast, and readability. Do not change factual content, people, product UI, chart values, logos, or text. No slide chrome, footer, page number, signature, watermark, or decorative frame. Ratio: {slot ratio}.If none of these examples fit, create the right asset shape. The shape is a servant, not the rule.
inline
Images use assets/ path (assemble.sh auto-base64). SVG inline directly.
<img src="assets/architecture.png" alt="System architecture" style="max-width:80%">
<svg viewBox="0 0 100 100">...</svg>poster
Video/audio/large files use cover image + play placeholder.
<div class="media-poster">
<img src="assets/demo-cover.jpg" alt="Demo video">
<div class="play-icon">▶</div>
<p class="caption">demo.mp4</p>
</div>Add .media-poster styles in custom.css (centered, rounded, semi-transparent play icon overlay).
extract
Code uses <pre><code>, data uses tables or CSS charts.
<pre><code class="lang-typescript">function resolve(state: State): Action {
return state.match(patterns);
}</code></pre>
<div class="bar" style="--val:85%">Conversion rate 85%</div>Design Self-Review Checklist
How it works
Design produces one validated archive, two source files, and one final build step. Check in order: 1. After writing DESIGN.md → Pass 0 2. After writing custom.css → Pass 1 3. After writing slides.html → Pass 2 4. After running build-html.sh → Pass 3
Auto-fix means fix it directly. Ask only for user-owned content conflicts.
Output Format
Review ({artifact}): N issues (X auto-fixed, Y need user decision)
**AUTO-FIXED:**
- [issue] → fixed
**NEEDS USER DECISION:**
- [issue] {why it cannot be resolved from sources}All clear: Review ({artifact}): all good.
---
Pass 0 — DESIGN.md
[HIGH] Archive validation
scripts/validate-design.sh "$DECK_DIR/DESIGN.md"passes- Failed → revise DESIGN.md before writing CSS/HTML
[HIGH] Full section map
- YAML front matter exists and all 10 sections are present in spec order
- Missing section → AUTO-FIX: add the section with concrete decisions, not placeholders
[HIGH] Implementation-driving detail
- Overview, Components, Visual Effects, and Do's and Don'ts each have enough specific rules to drive CSS/HTML
- Thin section → AUTO-FIX: add skeleton mapping, component semantics, motion policy, focal rules, or explicit non-applicability reason
[HIGH] Visual recipe selections
- DESIGN.md includes
Theme preset:,Layout recipes:,Component recipes:, andImage prompt recipes: - Missing recipe selection → AUTO-FIX: read theme-presets.md, layout-recipes.md, component-recipes.md, image-prompts.md and record the selected ingredients before writing CSS/HTML
---
Pass 1 — custom.css
[HIGH] :root variables complete
- Defines
--bg,--fg,--accent,--font-body,--font-heading - Missing → AUTO-FIX: add sensible defaults
[HIGH] Canvas coordinate system
- All sizing in
pxbased on 1280 × 720 canvas. Novw/vh/reminside slide styles - Violation → AUTO-FIX: convert to px equivalents (1vw ≈ 12.8px, 1vh ≈ 7.2px)
[HIGH] No position on slides
.slideand.slide-*must not havepositionset. Engine usesposition: absolute- Violation → AUTO-FIX: remove the position declaration
[MEDIUM] Font fallback
- Google Fonts must include
system-ui, sans-serif(ormonospace) fallback - Missing → AUTO-FIX: append fallback stack
[LOW] No engine style conflicts
- Does not override
.slide,#progress,.mobile-nav,.presenter-* - Conflict found → AUTO-FIX: remove or rename to custom class
.slide-*component classes are allowed, but the bare.slideengine selector is not
---
Pass 2 — slides.html
[HIGH] Slide count matches content source
- Slide count matches
deck.md - Mismatch → AUTO-FIX: add missing slides or remove extras
[HIGH] Slide structure correct
- Every slide is
<section class="slide" data-notes="..."> - Missing class or data-notes → AUTO-FIX: add them
[HIGH] Fragment-only source
- slides.html has no
<!doctype>,<html>,<head>,<body>,<main class="deck">,<link rel="stylesheet">, or document shell - Violation → INVALID: extract only the slide sections and let build-html.sh assemble the shell
[HIGH] Comment anchors
- Each slide has
<!-- ====== N. Title ====== -->comment before it - Missing → AUTO-FIX: add them
[HIGH] No engine code
- slides.html has no
<script>tags, no progress bar HTML, no mobile nav HTML - Found → AUTO-FIX: remove (the engine creates these automatically)
[MEDIUM] data-notes quality
- Not a repeat of the title; contains specific talking points
- Empty or hollow → AUTO-FIX: extract key points from
deck.md
[HIGH] Fragment continuity
- Within each slide,
data-fattributes must start at 1, increment by 1, no gaps, no duplicates - Violation → AUTO-FIX: renumber sequentially
[LOW] Data authenticity
- Data comes from source materials, not invented
- Suspicious → AUTO-FIX if source-backed; otherwise record in review.md as "needs verification" without blocking
---
Pass 3 — Final HTML
[HIGH] Assembly succeeded
- build-html.sh ran without errors, output file exists and is non-empty
- Failed → check that custom.css and slides.html both exist
[HIGH] Engine shell present
- Final HTML contains
openPresenter,codeck-presenter, andBroadcastChannel - Missing → INVALID: the deck was not assembled through the fixed engine; run build-html.sh
[HIGH] Self-contained final HTML
- Final HTML has no
<link rel="stylesheet" ...>pointing to a sibling deck CSS file - External stylesheet found → INVALID: move styles back to
$DECK_DIR/custom.cssand run build-html.sh
[HIGH] No text overflow
- No text extends outside slide boundaries
- Overflow → AUTO-FIX: reduce font size or truncate (edit custom.css and run build-html.sh)
[MEDIUM] Asset inlining complete
- No residual
assets/paths in the final HTML — all images should be base64-inlined by assemble.sh - Residual path found → check that the source file exists and run build-html.sh
[LOW] Color consistency
- Prefer CSS classes or
var()over inlinestyle="color: #xxx"— inline colors won't follow theme changes - Excessive hard-coded colors → AUTO-FIX: move them into CSS variables or classes
---
Suppressions
Do not flag:
- Unconventional design choices the user explicitly requested during iteration
codeck-design/references/
L2 | Parent: ../SKILL.md
[PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
Members
asset-guide.md: Fluid asset workflow; decides improve/adapt/generate/compose/draw/skip from slide need and slot. checklist.md: Design self-review; validates DESIGN.md, CSS, slide fragments, and final HTML guardrails. component-recipes.md: Presentation component cookbook; turns stats, callouts, rowlines, diagrams, media frames, and chrome into concrete HTML/CSS patterns. design-md-guide.md: Mapping guide from DESIGN.md tokens and prose to custom.css variables, primitives, slide styles, and motion. design-md-spec.md: DESIGN.md archive schema; requires tokens, sections, selected recipes, and implementation-driving design rationale. image-prompts.md: Prompt recipes for generated, cleaned, redesigned, composited, and diagrammatic slide assets. layout-recipes.md: Named page-structure recipes; gives rhetorical page patterns without importing template runtime. skeletons.md: Deck-level rhythm skeleton; owns page family cadence, media slot planning, tone variation, and motion recipes. theme-presets.md: Named visual system presets; supplies palette, type, material, layout, and motion defaults. visual-floor.md: Visual quality benchmarks that the generated deck must beat before CSS/HTML is considered complete.
Boundary
References provide ingredients, not final templates. The fixed codeck engine remains in ../scripts/; @design writes only DESIGN.md, custom.css, slides.html, and assets.
<!-- [INPUT]: Depends on selected theme preset, layout recipes, and DESIGN.md component semantics. [OUTPUT]: Provides implementation recipes for common presentation components. [POS]: codeck-design/references visual library; turns abstract component roles into concrete HTML/CSS patterns. [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md -->
Component Recipes
Use component recipes to make repeated structures feel designed instead of improvised. Record the selected recipes in DESIGN.md ## Components.
## Components
Component recipes: stat-tower, evidence-card, labeled-arrow, quote-cut, route-stepperInformation Components
stat-tower
Use when a number is the main claim.
- HTML shape:
.stat-tower > .stat-label + .stat-value + .stat-note - Visual: number uses display type, label uses metadata type, note is short and lower contrast.
- Motion: value appears last or scales in once.
- Guardrail: one dominant number per slide; a stat grid can have many numbers, but only one tower.
metric-strip
Use for 3-5 comparable metrics.
- HTML shape:
.metric-stripwith repeated.metric-item. - Visual: all items share width, label grammar, and number scale.
- Motion: cascade from left to right or top to bottom.
- Guardrail: no paragraph notes; use one-line notes only.
rowline
Use for compact comparisons, files, roles, decisions, constraints, or capabilities.
- HTML shape:
.rowline > .row-key + .row-body + .row-meta - Visual: key is compact and strong, body is readable, meta is small/status-like.
- Motion: line reveal or cascade.
- Guardrail: rowlines are not cards; keep borders thin and surfaces calm.
constraint-chip
Use for states, limits, requirements, or "must/must not" markers.
- HTML shape:
.constraint-chip[data-state="risk|ok|pending"] - Visual: small, high-contrast label, stable height, no tag cloud.
- Motion: appear with the evidence they annotate.
- Guardrail: more than eight chips needs grouping.
Narrative Components
quote-cut
Use when one sentence should interrupt the slide.
- HTML shape:
.quote-cut > blockquote + .quote-source - Visual: large text, strong line-height, source tiny but present.
- Motion: line-by-line reveal.
- Guardrail: do not add quotation marks as oversized decoration unless the theme needs it.
callout-note
Use for one sharp thought beside evidence.
- HTML shape:
.callout-note > .callout-kicker + .callout-body - Visual: bordered or background-separated note with enough whitespace.
- Motion: enters after the evidence.
- Guardrail: one callout per slide; otherwise none of them is a callout.
manifesto-line
Use for closing belief or thesis repetition.
- HTML shape:
.manifesto-linewith optional.manifesto-support. - Visual: display type, calm page, no extra UI chrome.
- Motion: slow reveal or static.
- Guardrail: must be sentence-level, not a slogan pile.
Diagram Components
labeled-arrow
Use only when an exchange has a name.
- HTML shape:
.flow-edgewith visible label near the edge. - Visual: thin line, arrowhead optional, label always readable.
- Motion: edge appears after both connected nodes.
- Guardrail: unlabeled arrows are invalid.
route-stepper
Use for paths, journeys, build pipelines, or demo sequences.
- HTML shape:
.route-stepperwith repeated.route-step[data-active]. - Visual: visible rail, stable step sizing, current step stronger.
- Motion: reveal one step at a time.
- Guardrail: if the path branches, use decision-tree-lite instead.
layer-band
Use for stack architecture, maturity levels, or dependency layers.
- HTML shape:
.layer-stack > .layer-band - Visual: bands align precisely; labels sit inside or left of the band.
- Motion: bottom-up build.
- Guardrail: layers must be dependency order, not random categories.
node-cluster
Use for systems with grouped actors or modules.
- HTML shape:
.node-clustercontaining.node-groupand.node. - Visual: group boundaries are subtle; edges stay sparse.
- Motion: groups first, nodes second, edges last.
- Guardrail: more than nine nodes should be simplified.
Media Components
figure-frame
Use for screenshots, UI, diagrams, charts, or photos that are evidence.
- HTML shape:
.figure-frame > img/svg + .figure-caption - Visual: contain fit for UI and diagrams; cover fit only for atmospheric photography.
- Motion: static or simple fade-in.
- Guardrail: captions identify evidence, not commentary.
evidence-card
Use when an artifact needs a label, source, and interpretation.
- HTML shape:
.evidence-card > .evidence-media + .evidence-caption + .evidence-takeaway - Visual: media dominates, caption is small, takeaway is one sentence.
- Motion: media first, takeaway second.
- Guardrail: do not use as generic decorative card.
placeholder-slot
Use when a needed asset is missing but the slot is structurally important.
- HTML shape:
.placeholder-slot[data-needed="..."] - Visual: visible outline, clear intended asset label, low visual weight.
- Motion: none.
- Guardrail: never pretend placeholder is real evidence.
Navigation And Chrome Components
chapter-chrome
Use to show act/section context.
- HTML shape:
.chapter-chromenear a stable edge. - Visual: tiny, consistent, never competes with slide title.
- Motion: usually static.
- Guardrail: do not repeat the slide title.
source-foot
Use for sources, context, or confidence labels.
- HTML shape:
.source-foot - Visual: small metadata type, fixed edge, enough contrast for projector.
- Motion: none.
- Guardrail: no long URLs unless required.
Selection Rules
- Pick component recipes that match the selected layout recipes. Do not add components just because they exist.
- Use shared class naming derived from recipes, but keep the fixed engine selectors untouched.
- Every repeated component must have stable dimensions so dynamic content does not shift the page.
- Record both component recipes and component guardrails in DESIGN.md before writing CSS.
Generation Guide — DESIGN.md → custom.css
Canvas
The engine renders every slide at 1280 × 720 px and uses transform: scale() to fit any screen. Inside a slide you are working in a fixed coordinate system — use px, not vw/vh/rem. An element that should span 40 % of the slide width is width: 512px. Font sizes, spacing, border-radius — all in px, all relative to 1280 × 720. Fill the canvas.
Priority
1. Color + typography — 80% of visual identity 2. Spacing + layout — structural rhythm 3. Shape + shadow — surface treatment 4. Overview + Do's and Don'ts — mood, composition, visual language 5. Visual Effects — visual enhancements 6. Motion — animation (add last, after layout and effects are solid)
DESIGN.md tokens → CSS Variables
Read the YAML front matter from $DECK_DIR/DESIGN.md and map tokens to :root variables in custom.css:
:root {
/* ─── Color ─── */
--bg: {colors.neutral};
--fg: {derive: light bg → dark fg, dark bg → light fg};
--accent: {colors.accent};
--accent2: {colors.secondary};
--primary: {colors.primary};
--surface-card: {colors.surface-card};
--surface-elevated: {colors.surface-elevated};
/* ─── Typography (Google Fonts + system fallback) ─── */
--font-heading: {typography.font-heading}, system-ui, sans-serif;
--font-body: {typography.font-body}, system-ui, sans-serif;
--font-mono: {typography.font-mono}, ui-monospace, monospace;
/* ─── Spacing ─── */
--space-sm: {spacing.sm};
--space-md: {spacing.md};
--space-lg: {spacing.lg};
--slide-padding: {spacing.slide-padding};
/* ─── Shape ─── */
--radius: {rounded.md};
--radius-sm: {rounded.sm};
--radius-lg: {rounded.lg};
/* ─── Shadow ─── */
--shadow-low: {from ## Elevation & Depth prose};
--shadow-md: {from ## Elevation & Depth prose};
--shadow-high: {from ## Elevation & Depth prose};
/* ─── Motion ─── */
--ease: {from ## Visual Effects prose};
--duration-micro: {from ## Visual Effects prose};
--duration-normal: {from ## Visual Effects prose};
}Critical: --bg, --fg, --accent are engine interface variables. engine.css uses these three to render the progress bar, overview borders, and page numbers. They must be defined.
Shadow and motion don't have YAML tokens — derive their CSS values from the prose in ## Elevation & Depth and ## Visual Effects sections.
DESIGN.md tokens → Layout Primitives
Generate type scale classes (.title-mega, .title-large, .title-medium, .body-text, .caption) from typography tokens, and layout primitives (.grid-2, .grid-3, .flex-col, .flex-row, .card) using the spacing and shape variables.
Type scale must be a ratio, not arbitrary values. Pick a base (--body-size, typically 20px on the 1280×720 canvas) and a ratio derived from the design role. Then: .caption = base × ratio^-1, .body-text = base, .title-medium = base × ratio, .title-large = base × ratio², .title-mega = base × ratio³. The ratio is a design decision — derive it from the DESIGN.md, don't default it.
Slide Type Styles
Map slide types from ## Components section to .slide-cover, .slide-divider, .slide-data, .slide-ending classes. Derive layout, alignment, and type scale from the DESIGN.md — don't default to centered everything.
Padding is a system, not per-slide guesswork. Define slide padding once in px (e.g. 60px 80px on the 1280×720 canvas) and share it across all slide types. Individual slides can override, but the default rhythm comes from one place.
Visual center sits at ~40-45% from top, not geometric center. Projected slides are viewed above eye level; laptop viewports lose bottom space to browser chrome. Use padding-top > padding-bottom or align-content: center with slight upward bias to place content mass in the audience's natural focal zone.
Overview + Do's and Don'ts → Subjective Decisions
These prose sections do not map to CSS directly — they guide how you write CSS and HTML. Let ## Overview mood drive color temperature, composition balance drive layout symmetry, ## Do's and Don'ts focal strategy drive per-slide emphasis.
Visual Effects → CSS Enhancements
Background effects
/* gradient-animation */
@keyframes gradient-shift {
0%, 100% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
}
.slide-cover {
background: linear-gradient(135deg, var(--primary), var(--accent));
background-size: 200% 200%;
animation: gradient-shift {speed from prose} ease infinite;
}Fragment entrance effects
The engine has four built-in entrance types, selected via data-f-type:
| Type | Attribute value | Use case |
|---|---|---|
| fade-up | default (omit) | text, lists, most content |
| scale | data-f-type="scale" | images, cards, key numbers |
| blur | data-f-type="blur" | large headings, hero copy, cinematic reveals |
| slide | data-f-type="slide" | timelines, steps, left-to-right sequences |
Usage: <div data-f="1" data-f-type="blur">...</div>
Custom types: define [data-f-type="yourname"] initial state in custom.css; the engine handles reveal automatically (.visible resets opacity, transform, filter).
[data-f-type="rotate"] { transform: rotate(-5deg) scale(0.95); }
[data-f-type="drop"] { transform: translateY(-20px); opacity: 0; }Guideline: one entrance type per slide for coherence. Across the deck, use as many types as the design role calls for — a cinematic deck might use all four plus custom types, a minimal deck might use only fade-up. The role decides, not a fixed cap.
To override the engine's transition duration and easing in custom.css:
[data-f] {
transition: opacity var(--duration-normal) var(--ease),
transform var(--duration-normal) var(--ease),
filter var(--duration-normal) var(--ease);
}Glass effect
.glass {
backdrop-filter: blur({blur_radius from prose});
background: rgba(255, 255, 255, {transparency from prose});
border: 1px solid rgba(255, 255, 255, 0.2);
}Text effects
/* gradient-fill */
.gradient-text {
background: linear-gradient(90deg, var(--accent), var(--primary));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}Responsive
The engine's transform: scale() already adapts slides to any viewport. You do not need @media breakpoints for slide content — no width breakpoints, no height breakpoints. The engine handles it.
@media queries in custom.css are only for engine UI elements (progress bar, mobile nav) which the AI does not write. Leave them to the engine.
Platform Constraints
These are engine facts, not aesthetic preferences:
- Canvas is 1280 × 720 px. All sizing in
px. Novw/vh/reminside slides. - *Don't set `position` on `.slide` or `.slide-
.** The engine usesposition: absolute` to fill the viewport. Overriding it breaks layout. - Google Fonts need fallback. Always include
system-ui, sans-serif(ormonospace) after the Google Font name. Offline viewers see system fonts, not broken blanks. - `--bg`, `--fg`, `--accent` are engine interface variables. They must be defined in
:root. The engine reads them for progress bar, overview, and page numbers.
Quality Checklist
Before delivery:
- [ ]
:rootdefines--bg,--fg,--accent(engine interface) - [ ] All sizing in
pxbased on 1280 × 720 canvas - [ ] Google Fonts have
system-uifallback - [ ] No
positionset on.slideor.slide-* - [ ] No engine classes overridden (
.slide,#progress,.mobile-nav) - [ ]
prefers-reduced-motionrespected (if animations present)
DESIGN.md Spec for codeck
Based on Google design.md format specification. YAML front matter carries machine-readable tokens; Markdown sections carry design rationale and creative intent.
codeck environment
Output: 16:9 HTML presentation. Engine JS is fixed; AI writes HTML + CSS only.
- No JS in slides — engine.js handles all interaction; slides.html contains only HTML + CSS classes
- Google Fonts allowed — use
@import url('https://fonts.googleapis.com/css2?...')at the top of custom.css (assemble.sh places it inside<style>in<head>). Always include a system font fallback stack so the deck degrades gracefully offline. - CSS + inline SVG only — all visual effects must be achievable with CSS @keyframes, CSS filters, backdrop-filter, gradients, and inline
<svg>elements - No other CDN — no script tags, no external assets besides Google Fonts
Record the full design intent in every section. For effects beyond CSS+SVG, describe the intent (the AI will find the closest CSS approximation). This preserves the design vision if the deck is later rendered in a richer environment.
---
File structure
A codeck DESIGN.md has two layers:
1. YAML front matter — machine-readable design tokens, delimited by --- fences 2. Markdown body — human-readable design rationale organized into ## sections
The tokens are the normative values. The prose provides context for how to apply them.
Token schema
---
version: alpha
name: <string>
description: <string>
colors:
primary: <Color> # deep/dominant brand color
secondary: <Color> # supporting color
accent: <Color> # interactive/highlight color
neutral: <Color> # background foundation
surface-card: <Color> # card/panel background
surface-elevated: <Color> # elevated surface (modals, popovers)
success: <Color>
warning: <Color>
error: <Color>
info: <Color>
typography:
display:
fontFamily: <string>
fontSize: <Dimension>
fontWeight: <number>
lineHeight: <number>
letterSpacing: <Dimension>
heading-1:
fontFamily: <string>
fontSize: <Dimension>
fontWeight: <number>
lineHeight: <number>
letterSpacing: <Dimension>
heading-2: ...
heading-3: ...
body: ...
body-small: ...
caption: ...
overline: ...
font-heading: <string> # heading font family name
font-body: <string> # body font family name
font-mono: <string> # monospace font family name
spacing:
base-unit: <Dimension>
sm: <Dimension>
md: <Dimension>
lg: <Dimension>
slide-padding: <string> # e.g. "60px 80px"
rounded:
sm: <Dimension>
md: <Dimension>
lg: <Dimension>
pill: <Dimension>
components:
button:
backgroundColor: <Color | token reference>
textColor: <Color | token reference>
rounded: <Dimension | token reference>
card:
backgroundColor: <Color | token reference>
rounded: <Dimension | token reference>
---Token types
| Type | Format | Example |
|---|---|---|
| Color | # + hex (sRGB) | "#1A1C1E" |
| Dimension | number + unit (px, em, rem) | 48px, -0.02em |
| Token reference | {path.to.token} | {colors.primary} |
codeck-specific tokens
Beyond the Google design.md base schema, codeck adds:
colors.surface-cardandcolors.surface-elevated— slide surface layersspacing.slide-padding— presentation-specific paddingtypography.font-heading/font-body/font-mono— shorthand family names for CSS variable generation
These are valid under the Google spec (unknown token names are accepted if values are valid).
Section order
Sections use ## headings. They can be omitted, but those present must appear in this order:
| # | Section | What it carries |
|---|---|---|
| 1 | Overview | Isomorphic mapping, mood, visual metaphor, era influence, personality, design philosophy |
| 2 | Colors | Palette type, each color's role, contrast strategy |
| 3 | Typography | Type scale ratio derivation, font selection rationale, style notes |
| 4 | Layout | Grid system, columns, alignment tendency, content density, section rhythm |
| 5 | Elevation & Depth | Shadow style, depth cues, level descriptions |
| 6 | Shapes | Border usage, divider style |
| 7 | Components | Presentation component semantics: shell, type roles, chrome, foot, kicker, callout, stats, rowlines, pillars, figures, icons, ghost text, highlights, and fragment roles |
| 8 | Visual Effects | Background effects, particles, glass, text effects, fragment entrances, motion philosophy, easing, duration scale |
| 9 | Image Assets | Asset strategy, generated/processed image decisions, prompt constraints, source preservation |
| 10 | Do's and Don'ts | Focal strategy, whitespace usage, contrast level, ornamentation, what to avoid |
Section details
## Overview — the creative soul. This is where the isomorphic mapping lives. Describe the structural analogy between the content and the design (e.g., "layered business proposal → Ravel's Bolero: simple to complex, each page adds a layer"). Include mood, visual metaphor, era influence, genre, personality traits. This section replaces design_style.aesthetic from the old schema. It must include Theme preset: {name} from theme-presets.md or Theme preset: custom-{name} — {reason}.
## Layout — grid system, columns, alignment tendency, content density, section rhythm, and page recipe mapping. It must include Layout recipes: {recipe list} from layout-recipes.md and a short mapping of recipes to slide roles.
## Components — presentation component semantics. Describe how the deck uses shell metadata, type roles, chrome, foot, kickers, tags, callouts, stats, channel/platform cards, rowlines, pillars, figures, captions, icons, ghost text, highlights, and motion-bearing fragments. These are semantic roles, not copied class names from any template. It must include Component recipes: {recipe list} from component-recipes.md.
Component rules:
- Slide shell — every slide needs a clear page role, content area, and optional metadata shell. Hero slides are for visual-dominant moments: cover, section turn, question, quote, or close. Body slides carry proof, process, explanation, and comparison.
- Theme cadence — light, dark, and hero treatments create rhythm. Do not run more than three pages with the same tone unless the content intentionally wants monotony.
- Type roles — display type is for hero titles, quotes, and big numbers. Body type is for readable explanation. Mono or metadata type is for labels, captions, page chrome, small system text, code, and structural tags. Do not mix these jobs randomly.
- Chrome and foot — chrome and foot are navigation metadata, not slide content. Chrome says where we are. Foot gives page context, source, or act marker. They should stay short and stable.
- Kicker — kicker is the page hook above the main title. It must be specific to the page and must not repeat chrome. Good kickers are short: "But", "Proof", "Phase 01", "The Turn". Bad kickers are generic: "Introduction", "Overview", or the same phrase as chrome.
- Tag — tags are small capsules for constraints, states, audiences, or short attributes. Use a handful, not a tag cloud.
- Callout — callouts carry one sharp quoted or emphasized thought. They are not generic cards. A callout needs one main sentence, optional source, and enough whitespace to feel intentional.
- Stats — stats use a fixed hierarchy: label, number, note. Use them when the number is the object. Keep the number visually dominant and the note short. Do not let more than four to six stats compete.
- Platform or channel card — use when showing channels, products, communities, or surfaces with one clear metric or status. It is a stat variant, not a generic card.
- Rowline — rowlines compare compact named items. Structure: key, explanation, metadata. Good for files, roles, steps, constraints, and capability lists. Bad for prose paragraphs.
- Pillar — pillars are for three or four conceptual supports. Each pillar must be parallel in grammar, scale, and visual weight. If they are not parallel, use rowlines or narrative text instead.
- Figure — figures are evidence or atmosphere inside a skeleton slot. Fit the slot before choosing crop. Align figures to the body area, not the title top. Use contain fit for UI, diagrams, charts, and text-bearing images. Crop photos from the bottom first. Do not bottom-pin figures.
- Caption — captions identify the figure or source. Keep them short. Captions are not a second paragraph.
- Placeholder — if an asset is missing but the slot matters, use a visible placeholder that states the intended asset. Do not pretend missing evidence exists.
- Icons — icons are structural marks, not decoration. Use them sparingly, keep a single stroke logic, and never use emoji as icons.
- Ghost text — ghost text is atmosphere. Use one oversized word, number, or symbol behind content at low contrast. It must not compete with readable content.
- Highlight — highlights mark one to three words. Do not highlight full sentences or whole paragraphs.
- Motion-bearing fragments — motion attaches to semantic blocks, not every tiny child. Use cascade for normal reveals, line reveal for quotes, directional reveal for before/after, and stepped reveal for pipelines.
## Visual Effects — codeck extension section. The Google spec preserves unknown sections without error. Describe background effects, particle systems, glassmorphism, text effects, cursor effects, SVG animations, and fragment entrance types. For effects beyond CSS+SVG, describe the intent. This section replaces visual_effects from the old schema. Also include motion philosophy, easing curves, and duration scale (micro/normal/macro) here.
## Image Assets — codeck extension section. Describe how user images, generated assets, cleaned screenshots, composites, and HTML/SVG alternatives support the deck. Start from slide need and slot, not from fixed image categories. Include source-preservation rules, ratio strategy, generated prompt constraints, and a table of generated or processed assets when applicable. This section must not override skeletons.md: the skeleton owns page rhythm, slide families, and image slots; Image Assets only records how assets serve those slots. It must include Image prompt recipes: {recipe list} from image-prompts.md, or Image prompt recipes: none — {reason}. If there is no image work, write "Not applicable — this deck uses typography, CSS, and SVG as the visual system."
## Do's and Don'ts — design guardrails. Derived from the old design_style.visual_language, composition, and imagery fields. Describe complexity level, ornamentation, whitespace usage, visual weight distribution, focal strategy, contrast level, texture usage, hierarchy method, balance type, flow direction, photo treatment, illustration style, graphic elements.
Completeness rule
Every section must be populated with deliberate decisions. No placeholder text. For sections that don't apply, write "Not applicable — [reason]" rather than omitting. Complete DESIGN.md forces deliberate decisions across all dimensions.
DESIGN.md is an archive, not a sketch. A valid archive is long enough to drive another agent's CSS/HTML without guessing. The minimum bar is:
- YAML front matter with the complete token groups in this spec
- all 10 Markdown sections in the required order
- at least 90 nonblank lines total
- explicit recipe selections:
Theme preset:,Layout recipes:,Component recipes:, andImage prompt recipes: - Overview, Components, Visual Effects, and Do's and Don'ts have at least 8 nonblank lines each
- every other required section has at least 4 nonblank lines
- no
TBD,TODO, vague placeholder, or bare "Not applicable" without a reason
Run scripts/validate-design.sh "$DECK_DIR/DESIGN.md" before writing custom.css. If validation fails, revise DESIGN.md; do not compensate by inventing missing decisions inside CSS.
Example
---
version: alpha
name: Bolero Crescendo
description: Layered business proposal — each page adds an instrument
colors:
primary: "#1B2838"
secondary: "#4A6741"
accent: "#D4A574"
neutral: "#F5F0EB"
surface-card: "#FFFFFF"
surface-elevated: "#FAFAF8"
success: "#2D7D46"
warning: "#C4841D"
error: "#B83232"
info: "#3B6FA0"
typography:
display:
fontFamily: Playfair Display
fontSize: 72px
fontWeight: 700
lineHeight: 1.05
letterSpacing: -0.02em
heading-1:
fontFamily: Playfair Display
fontSize: 48px
fontWeight: 600
lineHeight: 1.15
letterSpacing: -0.01em
body:
fontFamily: Source Sans 3
fontSize: 20px
fontWeight: 400
lineHeight: 1.6
letterSpacing: 0em
caption:
fontFamily: Source Sans 3
fontSize: 14px
fontWeight: 400
lineHeight: 1.4
letterSpacing: 0.02em
font-heading: Playfair Display
font-body: Source Sans 3
font-mono: JetBrains Mono
spacing:
base-unit: 8px
sm: 16px
md: 32px
lg: 64px
slide-padding: "60px 80px"
rounded:
sm: 4px
md: 8px
lg: 16px
pill: 999px
components:
button:
backgroundColor: "{colors.accent}"
textColor: "#FFFFFF"
rounded: "{rounded.sm}"
card:
backgroundColor: "{colors.surface-card}"
rounded: "{rounded.md}"
---
## Overview
Ravel's Bolero as visual architecture. The proposal builds like the orchestral piece — a single theme introduced simply, then each page adds a new instrument (data layer, visual complexity, color saturation) until the full orchestra plays on the closing slide.
Warm, editorial, quietly confident. The aesthetic sits between a premium annual report and a gallery exhibition catalog. No flash — the content earns attention through accumulation.
## Colors
Earth-toned palette rooted in warmth and trust. Primary deep navy for authority without coldness. Accent warm copper draws the eye to key numbers and CTAs. Neutral warm limestone — softer than white, more alive than gray.
Contrast strategy: high contrast for text (primary on neutral), medium contrast for decorative elements (secondary on neutral), accent reserved for singular focal points per slide.
## Visual Effects
Fragment entrances: fade-up for body content, blur for hero headings (cinematic reveal matching the crescendo metaphor), scale for key data points.
Motion philosophy: deliberate and unhurried. Easing: cubic-bezier(0.25, 0.1, 0.25, 1.0). Duration: micro 150ms, normal 400ms, macro 800ms.
Background: subtle warm gradient shift on cover slide (limestone to cream, 20s cycle). No particles, no glass — the Bolero metaphor is about clarity building, not decoration.
## Do's and Don'ts
Do: let whitespace increase as content density increases (breathing room scales with complexity). Use typography size contrast as primary hierarchy tool. Keep one focal point per slide.
Don't: use more than two colors on any single slide. Add decorative elements that don't serve the accumulation metaphor. Break the warm-to-warm color temperature.<!-- [INPUT]: Depends on slide need, layout media slot, source assets, and selected theme preset. [OUTPUT]: Provides prompt recipes for generated, cleaned, redesigned, or composited deck assets. [POS]: codeck-design/references visual library; complements asset-guide.md with reusable prompt shapes. [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md -->
Image Prompt Recipes
Use these prompts only when a raster asset helps the slide. Generated images are slide assets, not mini slides. They must not contain deck titles, page numbers, footers, watermarks, signatures, or decorative frames.
Record selected prompt recipes in DESIGN.md:
## Image Assets
Image prompt recipes: screenshot-redesign, system-infographic
Generated prompts:
| Slide | Recipe | Output | Constraint |Universal Constraints
Append these constraints to every generated asset prompt:
No slide title, no footer, no page number, no logo unless supplied by the user, no watermark, no signature, no decorative border, no UI chrome unless requested. Leave safe negative space for HTML text. Match the deck language for any labels. Ratio: {slot ratio}.If the asset represents a real product, dataset, person, legal text, chart value, or brand UI, do not invent or alter facts. Clean, crop, or annotate instead.
Prompt Recipes
documentary-photo
Use for human context, field work, real-world use, and atmosphere.
Editorial documentary photograph about {slide idea}. Real setting, natural light, grounded composition, restrained color palette matching {theme preset}, one clear focal subject, subtle environmental detail, room for overlaid HTML text. {universal constraints}product-context-photo
Use when a product is used in a believable setting without showing fake UI.
Realistic product-context photograph showing {user/persona} using {product category or workflow} in {setting}. Focus on situation and posture, not readable UI. Natural light, credible objects, no staged advertising feel, visual tone matching {theme preset}. {universal constraints}screenshot-cleanup
Use when the user provides a real screenshot that needs stage readability.
Clean this provided screenshot for a presentation: preserve all factual UI content, labels, values, product identity, and layout relationships. Improve contrast, crop empty browser chrome, normalize margins, sharpen text, and fit a {slot ratio} slide media slot. Do not redesign the product or change any text. {universal constraints}screenshot-redesign
Use when a messy screenshot should become a slide-safe explanatory asset, and factual UI can be abstracted.
Redesign the provided screenshot as a clean presentation-safe UI diagram. Preserve the real workflow, labels that matter, hierarchy, and product meaning. Remove noise, simplify panels, align spacing, and use the deck visual system: {theme preset}. Do not invent features, values, or brand marks. {universal constraints}system-infographic
Use for architectures, protocols, data flow, validation, and tool boundaries.
Clean vector-like system infographic explaining {system relationship}. Use labeled nodes, sparse labeled arrows, clear grouping, and a visual style matching {theme preset}. Keep labels short and in {language}. No tiny text, no decorative icons, no unlabeled arrows. {universal constraints}process-diagram
Use for linear workflows or pipelines.
Presentation-ready process diagram for {process}. Show {number} stages from {start} to {end}, each with a short label and one visual cue. Use stable spacing, one highlighted current/bottleneck stage, and the visual tone of {theme preset}. {universal constraints}comparison-visual
Use for before/after or old/new.
Side-by-side comparison visual showing {before state} versus {after state}. Keep both sides parallel in scale and grammar, with one central transformation cue. Style should match {theme preset}. Do not add unsupported claims or numbers. {universal constraints}data-poster
Use when one metric needs a visual support image, not when HTML type can do it better.
Data-poster background asset for the metric {metric}. Abstract supporting geometry only, no rendered number or title because HTML will carry the text. High contrast negative space, visual rhythm matching {theme preset}. {universal constraints}artifact-collage
Use when several source artifacts need one composite.
Compose the provided artifacts into one presentation visual. Keep each source recognizable, normalize scale and lighting, align margins, reduce clutter, and leave a clear HTML text area. Do not alter factual text, values, or UI hierarchy. {universal constraints}map-or-route
Use for trip, logistics, routing, operations, or geography-like structures.
Map-like editorial visual for {route/system}. Use abstract blocks, route rail, labels, and constraint markers rather than realistic cartography unless real map data is provided. Style matches {theme preset}. Do not invent real places or distances. {universal constraints}icon-set
Use only when repeated icons are structurally useful.
Small consistent icon set for {concept list}. Single stroke logic, no filled emoji style, no text inside icons, no brand marks, transparent background, visually compatible with {theme preset}. {universal constraints}Selection Rules
- Prefer CSS, SVG, and typography when the image would be decorative.
- Prefer
screenshot-cleanupoverscreenshot-redesignwhen factual UI matters. - Prefer
system-infographicover a stock photo for abstract technical concepts. - Generated diagrams must use short labels and cannot contain paragraphs.
- Every generated or processed asset path belongs in DESIGN.md and roles/design.md.
<!-- [INPUT]: Depends on deck.md slide purpose, skeleton rhythm, and DESIGN.md layout choices. [OUTPUT]: Provides named page recipes that guide slides.html structure without copying template code. [POS]: codeck-design/references visual library; richer than skeleton families, lighter than fixed templates. [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md -->
Layout Recipes
Use these recipes as page-structure ingredients. They are not templates, class names, or engine code. Pick by rhetorical job, then adapt spacing, tone, media slots, and motion in DESIGN.md.
Record selected recipes in DESIGN.md:
## Layout
Layout recipes: cover-signal, proof-stat-tower, process-spine, closing-manifesto
Recipe mapping:
- Slide 1 cover-signal — opens with one promise and one visual anchor.
- Slide 3 proof-stat-tower — makes the core metric unavoidable.Opening Recipes
| Recipe | Use When | Structure | Guardrail |
|---|---|---|---|
cover-signal | The deck needs a clear promise in the first five seconds. | One title, one subtitle, one anchor mark or image slot, optional source/context foot. | No feature list; no more than two text blocks. |
cover-field-note | The topic is operational, field-tested, or product-in-practice. | Small timestamp/context line, large claim, one artifact-like visual, short note. | Should feel like a dispatch, not a marketing hero. |
opening-problem-wall | The audience already feels pain but lacks structure. | Three to five compact pain fragments around one central question. | Do not solve on this slide; let tension breathe. |
opening-quote-cut | A human sentence is stronger than a thesis. | Large quote, tiny source, one supporting visual or blank space. | Quote must be source-backed or explicitly synthetic. |
Argument Recipes
| Recipe | Use When | Structure | Guardrail |
|---|---|---|---|
statement-slab | One sentence should dominate the page. | Oversized statement, narrow evidence strip, one accent line. | If it needs three paragraphs, use rowline or explain-panel instead. |
proof-stat-tower | A number is the object. | Label, giant value, one note, optional comparison baseline. | One primary number; secondary numbers stay small. |
duo-compare | Two worlds, versions, or decisions must be contrasted. | Two equal panels, same grammar, one verdict line. | Never compare non-parallel items. |
before-after-evidence | The deck shows transformation. | Before state, after state, changed mechanism in the middle or foot. | Keep before/after visual scale identical. |
constraint-wall | Tradeoffs or requirements define the story. | Grid of constraints, grouped by type, with one highlighted bottleneck. | Avoid tag soup; group into three to five clusters. |
myth-fact-split | Audience has a wrong assumption. | Left myth, right fact, bottom implication. | Fact needs support; don't make it a slogan fight. |
evidence-strip | Several artifacts prove one claim. | Horizontal or vertical strip of screenshots, quotes, logs, or examples. | Each artifact needs a one-line caption. |
lens-stack | Same object needs multiple interpretations. | Repeated object area with stacked lenses: user, system, business, risk. | The object stays stable; only lens changes. |
Explanation Recipes
| Recipe | Use When | Structure | Guardrail |
|---|---|---|---|
process-spine | The audience must understand sequence. | One visible spine, numbered stages, current stage emphasized. | More than six stages means merge or split. |
loop-diagram | The mechanism is cyclical. | Circular or orbital steps, one input, one output, one feedback note. | Do not fake circularity if the process is linear. |
system-map | Relationships matter more than steps. | Nodes grouped by ownership, edges labeled by exchange, one legend. | No unlabeled arrows. |
layer-cake | The concept builds in layers. | Horizontal stacked layers, each with role and dependency. | Lowest layer must be foundation, not chronology. |
exploded-view | A product or artifact has meaningful parts. | Center object decomposed into named parts around it. | Use for real components, not vague benefits. |
decision-tree-lite | Three or fewer branches matter. | Root question, two to three branches, explicit default path. | More than three branches needs a different slide. |
workflow-board | The story is about work moving through states. | Columns or swimlanes, cards as units of work, status chips. | Use stable card dimensions; no decorative card pile. |
Product And Demo Recipes
| Recipe | Use When | Structure | Guardrail |
|---|---|---|---|
product-frame | A UI or output needs inspection. | Large product frame, minimal title, callouts pinned to real UI zones. | UI screenshots use contain fit; never blur the evidence. |
demo-path | The audience needs the happy path. | Start state, three to five action beats, final output. | Keep actions concrete; avoid abstract verbs. |
capability-matrix | A product spans several jobs. | Rows are jobs, columns are capabilities or states, one emphasis row. | Matrix must fit without tiny text. |
user-day-slice | A persona journey matters. | Timeline of one user's day, product touchpoints, pain/relief markers. | One persona only. |
roadmap-rail | Future work matters but should not dominate. | Now / next / later rail, one confidence signal per stage. | Keep uncertainty visible. |
integration-handoff | The product connects tools or teams. | Source, transform, destination, responsibility labels. | Don't draw magic arrows; name the contract. |
Closing Recipes
| Recipe | Use When | Structure | Guardrail |
|---|---|---|---|
closing-manifesto | The deck ends with belief. | One sentence, three supporting clauses, minimal visual anchor. | No recap list. |
closing-ask | The deck needs action. | Specific ask, why now, first step, contact/context line. | Ask must be executable by the audience. |
takeaway-stack | The audience needs memory handles. | Three short takeaways, each with a concrete noun and verb. | Avoid generic "faster/better/easier" phrasing. |
open-question | The deck should leave tension alive. | Large question, one image or blank field, optional next conversation cue. | Use only when no immediate CTA is needed. |
Recipe Selection Rules
- Pick 4-8 recipes for a normal deck. A 5-slide deck should rarely use more than 5.
- Repeat one recipe intentionally if it creates rhythm; do not rotate recipes mechanically.
- The cover and close should not use the same visual weight unless the argument is circular.
- Prefer
statement-slabover generic title-body pages when one claim matters. - Prefer
process-spine,system-map, orworkflow-boardover a bullet list for mechanisms. - Prefer
product-frameorevidence-stripover decorative imagery when real artifacts exist.
Design Skeletons
The default codeck skeleton is narrative-grid.
It uses an argument-first deck structure: explicit page roles, hero/body rhythm, stable media slots, reusable page families, and a preplanned density cadence.
Use the skeleton as structure, not as copied code. Do not copy external HTML class names or runtime code. codeck keeps its own fixed engine; @design writes codeck custom.css and slides.html.
What A Skeleton Is
A skeleton is the deck's repeatable structure:
- page family inventory
- page sequence rhythm
- density curve
- tonal cadence
- image slot rules
- type role separation
- review guardrails
It is not a theme, template, asset kit, or finished style. Palette, typography, and effects still come from DESIGN.md.
Selection
Start from narrative-grid unless the user gives a reference that clearly demands a different structure.
Priority:
1. User-provided style, brand, screenshot, reference deck, website, or existing DESIGN.md 2. Current skeleton in $DECK_DIR/roles/design.md 3. diagnosis.md expression challenge and the content's formal structure 4. narrative-grid
Ask only when two skeleton choices would change the argument order. Otherwise choose and record the reason.
Record the choice in:
DESIGN.md## Overview:Skeleton: narrative-gridorSkeleton: narrative-{variant}roles/design.md## Current Skeletonchannel/YYYY-MM-DD.md: one line in the@designclaim or handoff
Pre-flight
Before writing DESIGN.md, custom.css, or slides.html, make a skeleton plan.
The plan must decide:
1. Page family for every slide. 2. Page energy for every slide: anchor, breath, work, or contrast. 3. Visual tone for every slide: light, dark, hero-light, or hero-dark. 4. Media slot and ratio for every slide that uses an image or visual asset. 5. Motion pattern for every slide that uses fragments.
Checks:
- No three consecutive slides share the same energy.
- No three consecutive slides share the same visual tone unless the content demands monotony.
- Dense
workslides have a nearbybreathoranchorslide. - Hero pages are used for turns, resets, openings, questions, and closings, not decoration.
- A repeated page family must do a different rhetorical job each time.
- Metadata and kicker are not the same sentence. Metadata names the section; kicker hooks the page.
- Large titles are sized by word length, not by wish.
- Media slots align to the body area, not the title top.
- Image grids use equal visual height.
- UI, diagrams, charts, and text-bearing images use contain fit.
- If a UI screenshot becomes a long strip, split it into panels or redesign it into a slide-safe asset.
Record the plan in DESIGN.md ## Layout and summarize the current skeleton state in roles/design.md.
Narrative Grid
Use for decks with a speaker voice: keynotes, private talks, product launches, demo days, industry talks, creator-led essays, and narrative reports.
Avoid it for dense training decks, spreadsheet-heavy board packs, compliance documentation, or slides that need many tiny tables.
Core principles:
- Structure beats decoration.
- Page roles carry the argument before decoration does.
- Hero pages create breath, reset, or emphasis.
- Body pages carry proof, process, and explanation.
- Images are assets inside slots, not standalone slides.
- Tone changes must create rhythm.
- Dense pages need sparse pages near them.
Page Families
Use these families as the default layout catalog. Pick by rhetorical job, not by decoration.
| Family | Rhetorical job | Default theme | Motion feel | Guardrail |
|---|---|---|---|---|
hero-cover | open the talk, name the thesis | hero dark | slow reveal | one title, one subtitle, one speaker/context line |
act-divider | mark a turn in the argument | hero light or hero dark, alternating | slow reveal | one idea only |
big-numbers | make data unavoidable | light, with rare dark variation | cascade | no more than four primary numbers |
quote-image | pair a claim with a concrete visual | light/dark alternating | cascade | image aligns to body area, not title top |
image-grid | compare visual evidence | light | cascade | same height or ratio across all images |
pipeline | explain a process or sequence | light | stepped reveal | steps advance one by one |
hero-question | create suspense or a reset | hero dark | slow reveal | question must fit in one breath |
big-quote | give a sentence ritual weight | dark preferred, light allowed | line reveal | quote must be short enough to read from the back row |
before-after | show a contrast or decision | light | directional | left/right labels must be parallel |
image-text-mix | handle denser explanation with a visual anchor | light/dark alternating | cascade | keep image and text in one grid system |
Rhythm Plan
Before writing slides, make a page rhythm plan. This is the part to borrow from magazine-style decks: decide the role and energy of each page before writing HTML.
Page energy levels:
anchor— title, section turn, closing ideabreath— sparse reset between dense pageswork— proof, process, data, image/text explanationcontrast— quote, before/after, tension, objection
Map energy to visual tone in DESIGN.md. A cinematic deck may use dark anchors. A technical deck may use light anchors. A warm report may barely use dark pages at all. The skeleton controls rhythm, not palette.
Rules:
- Never run more than three pages with the same energy.
- For decks with eight or more pages, include at least two anchors.
- Include at least one breath page after a dense work sequence.
- Insert an anchor every three to four pages when the story needs a turn.
- Repeat a page family only when its role changes.
- Keep data, grids, pipelines, and comparisons visually clear by default.
Eight-page starter rhythm:
| Page | Energy | Family | Job |
|---|---|---|---|
| 1 | anchor | hero-cover | open |
| 2 | work | big-numbers | data strike |
| 3 | contrast | quote-image | story or objection |
| 4 | work | pipeline | method |
| 5 | breath | act-divider | reset |
| 6 | contrast | quote-image or big-quote | tension |
| 7 | anchor | hero-question | suspense |
| 8 | anchor | big-quote or act-divider | close |
Type System
Use a three-role type system. The exact fonts come from DESIGN.md; the skeleton only defines the jobs.
- Display type for hero titles, quotes, and large numbers
- Humanist or grotesk sans-serif for body copy
- Monospace for metadata, labels, footers, code, and small navigational text
Rules:
- Do not use emoji as icons.
- Do not mix heading and body roles randomly.
- Metadata is not the kicker. Metadata names the section; kicker hooks the page.
- Large titles must fit the viewport. Size by word length, not by wish.
Image Slots
Images are always placed in stable slots.
Recommended ratios:
| Use | Ratio |
|---|---|
| main image beside text | 16:10 or 4:3 |
| full visual | 16:9 |
| UI or infographic | 16:9 or 16:10, contain fit |
| small mixed media | 3:2, 3:4, or 1:1 |
| image grid | equal heights across the group |
Rules:
- Never use a source image's odd aspect ratio as the slot ratio.
- Crop photos from the bottom first. Preserve top, left, and right.
- Use
object-fit: containfor UI, diagrams, charts, and text-bearing images. - Do not pin images to the bottom edge.
- Do not add heavy borders or shadows to images.
- Generated visuals must not include slide titles, footers, page numbers, signatures, or decorative frames.
- For image cleanup, generation, composition, or screenshot redesign, use
references/asset-guide.md. Its asset shapes are examples, not fixed modes.
Motion Mapping
Map the skeleton's motion recipes to codeck fragments and CSS animation classes:
| Page family | Motion |
|---|---|
| hero pages | slow staggered reveal |
| body pages | simple cascade |
| big-quote | line-by-line reveal |
| before-after | left side, divider, right side |
| pipeline | one step per fragment |
Motion must support reading. If motion makes the argument harder to follow, remove it.
Review Guardrails
@review should protect these choices:
- The page family matches the rhetorical job.
- The rhythm plan has enough light/dark and hero/body contrast.
- Dense pages are separated by breath pages.
- Images keep stable ratios and readable crops.
- Big numbers and quotes are large enough to work on stage.
- Metadata and kicker do different jobs.
- No generic card grid replaces a stronger page family.
Custom Variants
When a user gives a brand, screenshot, or reference deck, keep the narrative page-family logic and adapt surface choices:
narrative-technical: more blueprint linework, diagrams, code blocks, restrained motionnarrative-data: more big-numbers, tables, variance callouts, chart disciplinenarrative-product: more UI slots, before/after, workflow steps, zoom calloutsnarrative-cinematic: more hero pages, full-bleed visuals, sparse copynarrative-report: more report pages, quotes, pullouts, footnotes
Record only the selected variant, reason, and guardrails in roles/design.md. Put full design decisions in DESIGN.md.
<!-- [INPUT]: Depends on diagnosis.md tone, user references, and selected layout recipes. [OUTPUT]: Provides named visual systems with palette, type, material, and motion defaults. [POS]: codeck-design/references visual library; gives models high-quality starting palettes without freezing templates. [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md -->
Theme Presets
Theme presets are starting points, not brands. Select one preset, adapt it to the content, and record it in DESIGN.md.
## Overview
Theme preset: swiss-ink
Adaptation: keep the grid discipline, but warm the neutral background because the audience is non-technical.Presets
swiss-ink
Use for product, technical, operating-system, method, and analysis decks that need confidence and precision.
- Palette: near-white or charcoal foundation, one saturated anchor, neutral gray scale, no gradients by default.
- Type: grotesk or neo-grotesk sans for headings, same family for body, mono only for labels/code.
- Layout: hard grid, large type contrast, hairline dividers, rectangular blocks.
- Material: flat, no shadow, no glass, no glow.
- Motion: crisp line reveal, short cascade, directional slide for comparisons.
- Avoid: rounded cards, soft gradients, decorative icons, centered generic title pages.
Suggested tokens:
colors:
primary: "#111111"
secondary: "#E6E8EC"
accent: "#0047FF"
neutral: "#F7F7F2"
surface-card: "#FFFFFF"
surface-elevated: "#F0F1F4"editorial-ink
Use for narrative, industry observation, founder essays, culture, and human-centered product stories.
- Palette: paper neutral, ink dark, one muted accent, restrained warm/cool support colors.
- Type: serif display + humanist sans body, mono only for metadata.
- Layout: magazine spreads, strong image slots, generous margins, captions as first-class elements.
- Material: paper grain optional, soft image treatment, almost no shadow.
- Motion: slow fade-up, quote line reveal, image parallax simulated with CSS transforms.
- Avoid: dashboard cards, excessive chips, neon accents, fake magazine clutter.
Suggested tokens:
colors:
primary: "#1C1A17"
secondary: "#8A6F4D"
accent: "#B94E2F"
neutral: "#F4EFE5"
surface-card: "#FFFDF7"
surface-elevated: "#EFE4D3"field-board
Use for operational tools, travel/workflow planning, field research, logistics, and "real-world constraints" stories.
- Palette: off-white map stock, dark ink, safety accent, muted greens/blues for terrain or state.
- Type: sturdy sans for headings, tabular mono for coordinates/status, readable body.
- Layout: boards, tickets, route rails, constraint walls, map-like blocks.
- Material: paper, rule lines, stamps, status labels; shadows only as slight separation.
- Motion: step-by-step reveal, route draw, status flip.
- Avoid: glossy SaaS gradient, decorative map pins, fake travel photography.
Suggested tokens:
colors:
primary: "#25312B"
secondary: "#7E8B6F"
accent: "#D65A31"
neutral: "#F2EFE5"
surface-card: "#FCFAF2"
surface-elevated: "#E5DDC8"cinematic-contrast
Use for high-tension arguments, launches, before/after stories, security/risk, and emotionally charged reveals.
- Palette: black or deep graphite foundation, high-contrast text, one luminous accent, limited support color.
- Type: condensed or sharp sans display, calm sans body, labels in small mono.
- Layout: hero frames, darkness as negative space, one spotlighted object per slide.
- Material: gradients allowed as light, not background decoration; shadow is part of the scene.
- Motion: dramatic but sparse: fade-through-black, blur-in title, one macro reveal.
- Avoid: using dark mode for every deck; glowing every object; low-contrast gray text.
Suggested tokens:
colors:
primary: "#F6F1E8"
secondary: "#5F6673"
accent: "#FFB000"
neutral: "#090A0F"
surface-card: "#151820"
surface-elevated: "#20242E"system-blueprint
Use for architecture, protocols, developer tools, data flow, validation, and system boundaries.
- Palette: blueprint blue or pale drafting paper, ink lines, one warning/accent color.
- Type: clean sans headings, mono for identifiers, small captions for contracts.
- Layout: diagrams, layer-cake, system-map, exploded-view, rowlines.
- Material: fine lines, grid ticks, labels, no heavy cards.
- Motion: build diagram layer by layer; arrows appear only with labels.
- Avoid: unlabeled arrows, tiny code screenshots, pretending diagrams are decorative.
Suggested tokens:
colors:
primary: "#0E2A47"
secondary: "#AFC7DD"
accent: "#F25C54"
neutral: "#EEF5FA"
surface-card: "#FFFFFF"
surface-elevated: "#DCEAF5"soft-lab
Use for research, education, design exploration, and complex topics that need calm attention.
- Palette: light neutral, low-saturation scientific colors, one clear accent, generous contrast.
- Type: readable sans, optional serif display for chapter breaks.
- Layout: explain-panels, evidence strips, diagrams, annotated figures.
- Material: light surfaces, subtle dividers, no heavy shadows.
- Motion: gentle cascade and controlled fragment steps.
- Avoid: beige monotony, oversized hero treatment on every slide, vague pastel blobs.
Suggested tokens:
colors:
primary: "#22313F"
secondary: "#7A8E99"
accent: "#2F80ED"
neutral: "#F6F7F2"
surface-card: "#FFFFFF"
surface-elevated: "#E9EFEF"Selection Rules
- Pick one preset unless the user gave a stronger brand reference.
- Change at most two core palette roles without recording why.
- Preserve the preset's material logic. Do not put glass cards into
swiss-inkor neon glows intoeditorial-ink. - If none fit, define
custom-{short-name}in DESIGN.md and explain which preset it most closely rejects.
Visual Floor — Minimum Acceptable Impact
Not presets. Benchmarks to beat.
After generating DESIGN.md and before writing custom.css, compare your planned output against these. If your design is flatter than the closest benchmark, go back to the DESIGN.md and push harder.
---
Benchmark A: Light Editorial
Calibration reference, not a style to apply. Your design comes from the isomorphic mapping — use this only to check if your output has enough visual weight.
:root {
--bg: #faf8f5;
--fg: #1a1a1a;
--accent: #c41e3a;
--accent2: #2d5a27;
--surface-card: #ffffff;
--surface-elevated: #f0ede8;
--font-heading: 'Cormorant Garamond', 'Georgia', serif;
--font-body: 'Source Sans 3', system-ui, sans-serif;
}
/* Background: warm paper, not clinical white */
body {
background:
radial-gradient(ellipse at 50% 0%, rgba(196, 30, 58, 0.03) 0%, transparent 60%),
var(--bg);
}
/* Heading: oversized serif with tight tracking — magazine, not PowerPoint */
.title-mega {
font-size: 80px;
font-weight: 700;
letter-spacing: -0.04em;
line-height: 0.9;
color: var(--fg);
}
/* Accent line — a single decisive stroke, not a full border */
.slide-divider::before {
content: '';
width: 64px;
height: 4px;
background: var(--accent);
display: block;
margin-bottom: 24px;
}
/* Card: elevated with hard shadow — not the default soft diffuse */
.card {
background: var(--surface-card);
border-radius: 4px;
padding: 32px;
box-shadow: 8px 8px 0 var(--surface-elevated);
border: 1px solid rgba(0, 0, 0, 0.08);
}
/* Data emphasis: the number is the hero, not the label */
.metric-value {
font-size: 72px;
font-weight: 800;
color: var(--accent);
line-height: 1;
letter-spacing: -0.03em;
}
.metric-label {
font-size: 14px;
text-transform: uppercase;
letter-spacing: 0.15em;
color: rgba(26, 26, 26, 0.5);
margin-top: 8px;
}What makes this the floor:
- Serif heading with extreme tracking (-0.04em) — editorial, not corporate
- Accent line is a mark, not decoration — gives the page a focal anchor
- Hard shadow on cards — has personality vs generic soft blur
- Data metric is 72px — it dominates, not sits politely next to its label
---
Benchmark B: Neutral Tension
Calibration reference, not a style to apply. Your design comes from the isomorphic mapping — use this only to check if your output has enough visual weight.
:root {
--bg: #e8e4df;
--fg: #1c1917;
--accent: #1c1917;
--surface-card: transparent;
--font-heading: 'Instrument Sans', system-ui, sans-serif;
--font-body: 'Instrument Sans', system-ui, sans-serif;
}
/* Warm stone. The surface has weight, not color. */
body { background: var(--bg); }
/* Title: enormous, left-aligned, hugging the bottom edge */
.slide-cover {
justify-content: flex-end;
align-items: flex-start;
padding: 0 80px 64px 80px;
}
.slide-cover .title-mega {
font-size: 120px;
font-weight: 200;
letter-spacing: -0.05em;
line-height: 0.85;
color: var(--fg);
}
/* Content slides: one statement, massive, centered vertically */
.slide-statement .body-text {
font-size: 48px;
font-weight: 300;
line-height: 1.3;
max-width: 700px;
color: rgba(28, 25, 23, 0.75);
}
/* The only accent: a thin horizontal rule that means "pause here" */
.divider {
width: 48px;
height: 1px;
background: rgba(28, 25, 23, 0.25);
margin: 40px 0;
}
/* Final slide: lighten to near-white, single small line */
.slide-ending {
background: #f5f3f0;
}
.slide-ending .body-text {
font-size: 20px;
color: rgba(28, 25, 23, 0.35);
}What makes this the floor:
- 120px ultra-light title at bottom-left — asymmetry creates tension from nothing
- Body text at 48px on content slides — each slide is one thought, unavoidable
- Divider is 48px x 1px — restrained to the point of being a whisper
- Final slide lightens the background and shrinks the text — the deck dissolves into silence
- Zero decoration. The whitespace does all the work. Warm stone instead of void.
---
Benchmark C: Dark Cinematic
Calibration reference, not a style to apply. Your design comes from the isomorphic mapping — use this only to check if your output has enough visual weight.
:root {
--bg: #08080a;
--fg: #e8e6e3;
--accent: #ff6b35;
--accent2: #3d8bfd;
--surface-card: rgba(255, 255, 255, 0.04);
--surface-elevated: rgba(255, 255, 255, 0.08);
--font-heading: 'Clash Display', system-ui, sans-serif;
--font-body: 'General Sans', system-ui, sans-serif;
}
/* @import url('https://fonts.googleapis.com/css2?family=Clash+Display:wght@600;800&family=General+Sans:wght@400;500&display=swap'); */
/* Background: animated gradient that breathes, not static */
body {
background:
radial-gradient(ellipse at 20% 0%, rgba(255, 107, 53, 0.08) 0%, transparent 50%),
radial-gradient(ellipse at 80% 100%, rgba(61, 139, 253, 0.06) 0%, transparent 50%),
var(--bg);
}
/* Cover title: massive, gradient-filled, unmissable */
.slide-cover .title-mega {
font-size: 88px;
font-weight: 800;
letter-spacing: -0.03em;
line-height: 0.95;
background: linear-gradient(135deg, var(--fg) 0%, var(--accent) 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
/* Cards: glass surface with glow border */
.card {
background: var(--surface-card);
border: 1px solid rgba(255, 255, 255, 0.06);
border-radius: 16px;
padding: 32px;
backdrop-filter: blur(20px);
box-shadow:
0 0 0 1px rgba(255, 255, 255, 0.03),
0 8px 40px rgba(0, 0, 0, 0.4);
}
/* Noise texture for analog warmth */
body::after {
content: '';
position: fixed;
inset: 0;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.03'/%3E%3C/svg%3E");
pointer-events: none;
z-index: 9999;
mix-blend-mode: overlay;
}What makes this the floor, not the ceiling:
- Background has color temperature (warm top-left, cool bottom-right) — not flat black
- Title uses gradient fill — not plain white text
- Cards have glass + glow — not just a background color swap
- Noise overlay adds tactile quality — most AI output skips this
---
How to use these benchmarks
After writing DESIGN.md, before writing custom.css:
1. Pick the closest benchmark to your DNA's mood and content structure 2. Check the water level — does your output have at least this much visual weight overall? Don't compare item-by-item. A deck can beat the benchmark with different strengths (e.g. strong typography + simple background instead of layered background + plain type) 3. If your design feels flat compared to the benchmark, push the DNA harder: more contrast, more scale difference, more surface depth, more decisive color 4. Then diverge — your output follows the isomorphic mapping, not the benchmark. The benchmark is a minimum altitude, not a flight path
The rule: structurally unique (from the mapping), visually at least this impactful (from the floor).
---
Deck-level techniques
Single-page quality is necessary but not sufficient. These techniques operate across pages — they're what separates a deck from 12 copies of the same slide.
Color temperature drift
Shift --bg per page to follow the emotional arc. Don't change the palette — change the temperature. Works on any base tone — light, neutral, or dark.
/* Light deck: cool open → warm peak → settled close */
.slide:nth-child(-n+3) { --bg: #f0f2f5; }
.slide:nth-child(n+5):nth-child(-n+8) { --bg: #faf5ef; }
.slide:nth-child(n+10) { --bg: #f5f4f2; }
/* Dark deck: cool open → warm peak → settled close */
.slide:nth-child(-n+3) { --bg: #0a0f1a; }
.slide:nth-child(n+5):nth-child(-n+8) { --bg: #1a0f0a; }
.slide:nth-child(n+10) { --bg: #0f1218; }Density inversion
Every 3-4 pages, flip from dense to sparse or vice versa. A page packed with 4 metric cards followed by a page with one sentence and 80% whitespace. This is forte → piano. Without it, every page feels the same volume.
Breathing pages
Some slides exist to make the audience feel, not think. A single word. A color inversion. A number at 200px with nothing else. These slides have no bullet points, no cards — just one element and space. Insert at least one per deck section.
Morph within a slide
The engine sets data-step="N" on each slide as fragments advance. CSS can use this to morph existing elements between states — position, size, color, opacity — using transitions. No JavaScript needed.
<section class="slide slide-reveal">
<h1 class="title-mega">Revenue</h1>
<div class="chart-area" data-f="1">
<div class="chart">...</div>
</div>
</section>/* Initial: title centered and large */
.slide-reveal .title-mega {
font-size: 80px;
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}
/* After step 1: title shrinks to top-left, chart appears */
.slide-reveal[data-step="1"] .title-mega {
font-size: 28px;
top: 8%; left: 5%;
transform: none;
}The title animates from center to corner as the chart fades in. One slide, two states, pure CSS. Works for any property that supports transitions — size, position, color, opacity, blur.
Type as illustration
When you can't use images, type itself becomes the visual element.
/* Giant character as page texture */
.slide-question::before {
content: '?';
position: absolute;
right: -5%;
bottom: -10%;
font-size: 400px;
font-weight: 900;
opacity: 0.04;
line-height: 1;
color: var(--fg);
}A 400px ? as background texture. A 3x with -webkit-text-stroke as a data page watermark. The letter is not content — it's atmosphere.
mix-blend-mode for light and depth
One pseudo-element with a radial gradient and mix-blend-mode: overlay creates the illusion of light falling on the surface. Zero-cost depth.
.slide-cover::before {
content: '';
position: absolute;
inset: 0;
background: radial-gradient(ellipse at 30% 0%, var(--accent), transparent 60%);
mix-blend-mode: overlay;
opacity: 0.4;
pointer-events: none;
}Inline SVG generative texture
<svg> with feTurbulence generates noise, grain, and organic patterns — resolution-independent, under 500 bytes. Use as a slide ::after overlay for tactile warmth.
<svg width="0" height="0" style="position:absolute">
<filter id="grain">
<feTurbulence type="fractalNoise" baseFrequency="0.8" numOctaves="4"/>
<feColorMatrix type="saturate" values="0"/>
</filter>
</svg>.slide::after {
content: '';
position: absolute;
inset: 0;
filter: url(#grain);
opacity: 0.03;
mix-blend-mode: overlay;
pointer-events: none;
}#!/usr/bin/env bash
# ─── codeck assemble ───
# Assemble engine + AI content into one self-contained HTML file.
# Usage: assemble.sh <deck_dir> <title> [lang]
# Writes to stdout; callers redirect to a file.
set -euo pipefail
DECK_DIR="$1"
TITLE="$2"
LANG="${3:-zh-CN}"
ENGINE_DIR="$(cd "$(dirname "$0")" && pwd)"
_base64_one_line() {
local file="$1"
if base64 --help 2>&1 | grep -q -- '-w'; then
base64 -w0 "$file"
elif base64 -i "$file" >/dev/null 2>&1; then
base64 -i "$file" | tr -d '\n'
elif command -v openssl >/dev/null 2>&1; then
openssl base64 -A -in "$file"
else
base64 "$file" | tr -d '\n'
fi
}
# Check required files.
[ -f "${DECK_DIR}/slides.html" ] || { echo "ERROR: ${DECK_DIR}/slides.html not found" >&2; exit 1; }
[ -f "${DECK_DIR}/custom.css" ] || { echo "ERROR: ${DECK_DIR}/custom.css not found" >&2; exit 1; }
# ─── Assemble to temp file ───
TMPFILE=$(mktemp)
trap 'rm -f "$TMPFILE"' EXIT
{
cat <<EOF
<!DOCTYPE html>
<html lang="${LANG}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${TITLE}</title>
<style>
EOF
cat "${ENGINE_DIR}/engine.css"
printf '\n/* ====== Design system + slide styles ====== */\n'
cat "${DECK_DIR}/custom.css"
cat <<'EOF'
</style>
</head>
<body>
<div id="app" style="opacity:0">
EOF
cat "${DECK_DIR}/slides.html"
cat <<'EOF'
</div>
<script>
EOF
cat "${ENGINE_DIR}/engine.js"
cat <<'EOF'
</script>
</body>
</html>
EOF
} > "$TMPFILE"
# ─── Inline assets (assets/ → base64 data URI) ───
# References to assets/xxx.png in slides.html become data:image/png;base64,...
# This keeps the final HTML self-contained.
if [ -d "${DECK_DIR}/assets" ]; then
for asset in "${DECK_DIR}"/assets/*; do
[ -f "$asset" ] || continue
filename=$(basename "$asset")
# Infer MIME type.
case "${filename##*.}" in
png) mime="image/png" ;;
jpg|jpeg) mime="image/jpeg" ;;
gif) mime="image/gif" ;;
svg) mime="image/svg+xml" ;;
webp) mime="image/webp" ;;
ico) mime="image/x-icon" ;;
*) continue ;; # Skip non-images.
esac
b64=$(_base64_one_line "$asset")
datauri="data:${mime};base64,${b64}"
# Replace assets/filename references in HTML (src="assets/..." or url(assets/...)).
LC_ALL=C sed -i "s|assets/${filename}|${datauri}|g" "$TMPFILE" 2>/dev/null || \
LC_ALL=C sed -i '' "s|assets/${filename}|${datauri}|g" "$TMPFILE" 2>/dev/null || true
done
fi
cat "$TMPFILE"
#!/usr/bin/env bash
# [INPUT]: accepts a deck room, file stem, language, and optional output directory.
# [OUTPUT]: writes one validated engine-assembled HTML file and prints its path.
# [POS]: codeck-design/scripts final-build guard; wraps assemble.sh so speaker mode cannot be skipped.
# [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
set -euo pipefail
DECK_DIR="${1:?Usage: build-html.sh <deck_dir> <file_stem> [lang] [out_dir]}"
FILE_STEM="${2:?Usage: build-html.sh <deck_dir> <file_stem> [lang] [out_dir]}"
LANG="${3:-zh-CN}"
OUT_DIR="${4:-.}"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
case "$FILE_STEM" in
*/*|*\\*|"") echo "ERROR: file_stem must be a plain filename stem" >&2; exit 1 ;;
esac
mkdir -p "$OUT_DIR"
slides="$DECK_DIR/slides.html"
css="$DECK_DIR/custom.css"
[ -f "$slides" ] || { echo "ERROR: missing slides source: $slides" >&2; exit 1; }
[ -f "$css" ] || { echo "ERROR: missing css source: $css" >&2; exit 1; }
grep -Eiq '<!doctype|<html[[:space:]>]|<head[[:space:]>]|<body[[:space:]>]|</html>|</body>' "$slides" && {
echo "ERROR: slides.html must contain slide sections only, not a full HTML document" >&2
exit 1
}
grep -Eiq '<script[[:space:]>]|<link[^>]*rel=["'\'']stylesheet' "$slides" && {
echo "ERROR: slides.html must not contain scripts or stylesheet links; the fixed engine owns runtime and CSS assembly" >&2
exit 1
}
grep -Eq '(^|[[:space:]])\.slide([[:space:],:{.#]|$)|(^|[[:space:]])#progress([[:space:],:{.#]|$)|(^|[[:space:]])\.mobile-nav([[:space:],:{.#]|$)|(^|[[:space:]])\.presenter-' "$css" && {
echo "ERROR: custom.css must not override engine selectors (.slide, #progress, .mobile-nav, .presenter-*)" >&2
exit 1
}
last_rev="$(
find "$OUT_DIR" -maxdepth 1 -type f -name "${FILE_STEM}-r*.html" -print 2>/dev/null \
| sed -E "s|^.*/${FILE_STEM}-r([0-9]+)\\.html$|\\1|" \
| awk '/^[0-9]+$/ { if ($1 > max) max = $1 } END { print max + 0 }'
)"
rev=$((last_rev + 1))
out="${OUT_DIR%/}/${FILE_STEM}-r${rev}.html"
bash "$SCRIPT_DIR/assemble.sh" "$DECK_DIR" "$FILE_STEM" "$LANG" > "$out"
[ -s "$out" ] || { echo "ERROR: assembled HTML is empty: $out" >&2; exit 1; }
grep -q 'openPresenter' "$out" || { echo "ERROR: missing speaker mode engine marker: openPresenter" >&2; exit 1; }
grep -q 'codeck-presenter' "$out" || { echo "ERROR: missing speaker mode window marker: codeck-presenter" >&2; exit 1; }
grep -q 'BroadcastChannel' "$out" || { echo "ERROR: missing presenter sync marker: BroadcastChannel" >&2; exit 1; }
grep -qi '<link[^>]*rel=["'\'']stylesheet' "$out" && {
echo "ERROR: final HTML must be self-contained; external stylesheet link found" >&2
exit 1
}
printf '%s\n' "$out"
codeck-design/scripts/
L2 | Parent: ../../CLAUDE.md
engine.js: Fixed slide runtime; owns navigation, fragments, overview, speaker mode, presenter sync, toolbar, and notes assembly. engine.css: Fixed runtime chrome; owns slide shell, toolbar, overview, mobile controls, presenter layout, and engine-level responsive behavior. assemble.sh: Low-level assembler; inlines engine.css, custom.css, slides.html, engine.js, and image assets into one HTML stream. validate-design.sh: Design archive validator; blocks CSS/HTML generation when DESIGN.md lacks YAML tokens, required sections, visual recipe selections, or implementation-driving detail. build-html.sh: Final build guard; auto-increments project-root revisions, calls assemble.sh, and rejects output without speaker-mode markers or self-contained CSS.
[PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
#!/usr/bin/env bash
# [INPUT]: accepts one DESIGN.md path produced by the design lane.
# [OUTPUT]: exits non-zero when the design archive is too thin or structurally invalid.
# [POS]: codeck-design/scripts design-archive guard; blocks CSS/HTML generation without real decisions.
# [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
set -euo pipefail
DESIGN_MD="${1:?Usage: validate-design.sh <DESIGN.md>}"
[ -f "$DESIGN_MD" ] || { echo "ERROR: DESIGN.md not found: $DESIGN_MD" >&2; exit 1; }
fail() {
echo "ERROR: $*" >&2
exit 1
}
nonblank=$(awk 'NF { n++ } END { print n + 0 }' "$DESIGN_MD")
[ "$nonblank" -ge 90 ] || fail "DESIGN.md is too short: ${nonblank} nonblank lines; expected at least 90"
fences=$(grep -c '^---[[:space:]]*$' "$DESIGN_MD" || true)
[ "$fences" -ge 2 ] || fail "DESIGN.md must start with YAML front matter delimited by ---"
for token in \
'version:' 'name:' 'description:' \
'colors:' 'primary:' 'secondary:' 'accent:' 'neutral:' 'surface-card:' 'surface-elevated:' \
'typography:' 'display:' 'heading-1:' 'heading-2:' 'body:' 'caption:' 'font-heading:' 'font-body:' \
'spacing:' 'base-unit:' 'slide-padding:' \
'rounded:' 'components:'
do
grep -q "^[[:space:]]*$token" "$DESIGN_MD" || fail "missing YAML token: $token"
done
required_sections=(
"Overview"
"Colors"
"Typography"
"Layout"
"Elevation & Depth"
"Shapes"
"Components"
"Visual Effects"
"Image Assets"
"Do's and Don'ts"
)
for section in "${required_sections[@]}"; do
grep -qx "## $section" "$DESIGN_MD" || fail "missing section: ## $section"
done
for marker in \
'Theme preset:' \
'Layout recipes:' \
'Component recipes:' \
'Image prompt recipes:'
do
grep -q "$marker" "$DESIGN_MD" || fail "missing visual recipe selection: $marker"
done
awk '
/^## / {
if (section != "") counts[section] = count
section = substr($0, 4)
count = 0
next
}
section != "" && NF { count++ }
END {
if (section != "") counts[section] = count
split("Overview|Colors|Typography|Layout|Elevation & Depth|Shapes|Components|Visual Effects|Image Assets|Do'\''s and Don'\''ts", required, "|")
for (i = 1; i <= length(required); i++) {
s = required[i]
min = 4
if (s == "Overview" || s == "Components" || s == "Visual Effects" || s == "Do'\''s and Don'\''ts") min = 8
if ((counts[s] + 0) < min) {
printf("ERROR: section ## %s is too thin: %d nonblank lines; expected at least %d\n", s, counts[s] + 0, min) > "/dev/stderr"
exit 1
}
}
}
' "$DESIGN_MD"
grep -Eiq '\b(TBD|TODO|placeholder|lorem ipsum|待定|占位)\b' "$DESIGN_MD" && \
fail "DESIGN.md contains placeholder language"
grep -Eq 'Not applicable[[:space:]]*(\.|$)' "$DESIGN_MD" && \
fail "Not applicable entries must include a concrete reason"
grep -Eiq 'Theme preset:[[:space:]]*(none|n/a|not applicable)' "$DESIGN_MD" && \
fail "Theme preset must name a preset or custom-* reason"
grep -Eiq 'Layout recipes:[[:space:]]*(none|n/a|not applicable)' "$DESIGN_MD" && \
fail "Layout recipes must name at least one recipe"
grep -Eiq 'Component recipes:[[:space:]]*(none|n/a|not applicable)' "$DESIGN_MD" && \
fail "Component recipes must name at least one recipe"
printf 'DESIGN.md valid: %s\n' "$DESIGN_MD"