16 KiB
Execution Lock
⚠️ Skeleton for Strategist — do NOT copy verbatim into a project. When producing
<project_path>/spec_lock.md, emit only##sections with filled-in-data lines. Do NOT carry over any>blockquote guidance, HARD-rule notes, or override examples — those are author-time guidance, not runtime data. Every output line must be parseable data.Machine-readable execution contract. Executor MUST
read_filethis before every SVG page. Values not listed here must NOT appear in SVGs. For design narrative (rationale, audience, style), seedesign_spec.md.After SVG generation begins, this is the canonical source for color / font / icon / image values. Modifications should go through
scripts/update_spec.pyto keep this file and generated SVGs in sync.
canvas
- viewBox: 0 0 1280 720
- format: PPT 16:9
Strategist: fill viewBox and format for the chosen canvas. Common values:
0 0 1280 720(PPT 16:9),0 0 1024 768(PPT 4:3),0 0 1242 1660(Xiaohongshu),0 0 1080 1080(WeChat Moments),0 0 1080 1920(Story).
layout_grid
- margin_x: 60
- content_top: 150
- footer_y: 688
- gutter: 24
Deck-wide layout constants, in canvas px. Executor snaps every content page to these;
svg_quality_checker.pyhard-checks them (a content block whose left edge lands 2–15px offmargin_xis an error — "meant to align, didn't"). This section exists because hand-written absolute coordinates drift across pages without a locked baseline — the #1 source of cross-page misalignment.
margin_x— left/right content margin. Header title, content blocks, and footer on content pages all share this left edge.content_top— top edge of the body content zone on content pages (below the header band). Structural pages (cover / chapter / TOC / ending) are exempt.footer_y— footer baseline. Omit if the deck has no footer.gutter— gap between side-by-side sibling cards in a row/grid. One value deck-wide.Strategist derives values from canvas + visual_style (defaults above suit 1280×720; scale proportionally for other canvases — e.g. 4:3
margin_x: 50). A page may deliberately break the grid (full-bleed image, asymmetric breathing page) — breaking means clearing it by ≥16px or going full-bleed, never a few-px "almost".Missing section → legacy deck; checker falls back to cross-page clustering (warning-tier only). New decks MUST fill it.
- mode: pyramid
Strategist: the deck's narrative skeleton, locked at confirmation
dLayer 1. One ofpyramid/narrative/instructional/showcase/briefing— seereferences/modes/_index.md. Executor reads only the locked mode's file. Deck-wide. Or the literalcustomfor a bespoke direction no preset captures (a special cadence, a multi-mode fusion, a particular posture) — user-requested or Strategist-recommended (user confirms, like every lock). Then add a sibling- mode_behavior:paragraph (how the argument advances, title voice, page rhythm, register) that the Executor follows in place of a preset file. One deck locks one value; don't default tocustomwhen a preset fits.
visual_style
- visual_style: swiss-minimal
Strategist: the deck's visual aesthetic, locked at confirmation
dLayer 2. A preset name fromreferences/visual-styles/_index.md, or the literalcustom. Reference intent (shape / decoration / whitespace / texture) — not a whitelist, and carries no HEX (color truth stays incolors). Executor reads only the locked style's file.
custom— add a sibling- visual_style_behavior:row with a one-paragraph aesthetic description (shape language, decoration density, whitespace, typographic character, texture); no HEX, no color names. Tail-case, not a default.
colors
- bg: #FFFFFF
- primary: #......
- accent: #......
- secondary_accent: #......
- text: #......
- text_secondary: #......
- border: #......
- image_rendering: vector-illustration
- image_palette: cool-corporate
Strategist: fill only colors actually used. Add extra rows as needed; delete unused rows rather than leave as
#.......
image_renderingandimage_palette— required only whenimagessection below containsai-sourced files. Values MUST be valid names fromreferences/image-renderings/_index.mdandreferences/image-palettes/_index.md, or the literal stringcustom. Image_Generator reads these and applies them deck-wide. Omit both rows when the deck has no AI-generated images.
customescape hatch. When set tocustom, add a sibling*_behaviorrow carrying a one-paragraph prose description. Image_Generator splices the prose into the prompt in place of the preset file's fewshot snippet. Tail-case only — seeimage-renderings/_index.md§1.5 /image-palettes/_index.md§2 for invocation rules.- image_rendering: custom - image_rendering_behavior: "Hand-screened poster aesthetic — slightly misregistered halftone overlays, 3 flat ink colors with visible dot pattern at 12% opacity, no gradients, no anti-aliased edges; reads as silkscreen print." - image_palette: custom - image_palette_behavior: "Primary deep aubergine `#4C1D95` anchors ~35% of canvas; secondary warm cream `#FEF3C7` carries ~55% as breathing field; accent burnished gold `#D4AF37` in 5-10% as ceremonial accents. No fourth color."
typography
- font_family: "Microsoft YaHei", Arial, sans-serif
- title_family: Georgia, SimSun, serif
- body_family: "Microsoft YaHei", "PingFang SC", Arial, sans-serif
- emphasis_family: Georgia, SimSun, serif
- code_family: Consolas, "Courier New", monospace
- body: 24
- title: 42
- subtitle: 32
- annotation: 18
- footnote: 16
All five family lines are listed explicitly so Strategist considers every role —
code_familyandemphasis_familyare easily forgotten. In a realspec_lock.md:
- Keep any
*_familywhose role genuinely differs fromfont_family.- Omit any
*_familyequal tofont_family— Executor falls back tofont_familyfor missing roles, so writing it twice is noise. (Exception: keepcode_familyeven when equal — monospace is conceptually distinct.)code_familyapplies to code snippets only. LaTeX formulas rendered bylatex_render.pyare PNG image assets and must be listed underimages.
font_familyis the default fallback. Every declared family is a CSS font-stack string.Source: copy verbatim from the Per-role font stacks list in
design_spec.md §IV Font Plan. Stack order encodes browser-rendering intent (Latin-led vs. CJK-led) that the breakdown table cannot — strings here must match character-for-character. Seedesign_spec.md §IVfor the explainer.Sizes (
body/title/ etc.) are unitless px numbers — the execution unit and the same values recorded indesign_spec.md §IV. The system is px-only on every canvas: there is no pt layer and no conversion — the confirmed value is already px (e.g.balancedbody24, title42, subtitle32, annotation18, footnote16— clean even px). Do not writept/px/emor any unit.bodyis the required baseline anchor — all other sizes derive as clean-even ratios of it (ramp table:design_spec_reference.md §IV).Size slots are anchors, not a closed menu. Common slots (
title/subtitle/annotation) cover frequent cases. Add role-specific slots (e.g.cover_title: 88,hero_number: 56,subheading: 32,lead: 30,footnote: 16,chart_annotation: 16) for the roles the deck actually uses — common for cover-heavy decks, consulting-style hero numbers, dense pages. Mandatory — scan§IXand declare a slot for every role that recurs across pages, not just the four defaults. A report /text-mode deck almost always recurs a per-page core-message / lead line and page numbers / source credits / footnotes → declareleadandfootnotefor them.subheadingandleadsit betweensubtitleandbody(their bands overlapsubtitle) — pick by role, not size — and the core-messageleadis a primary line, always ≥body, never smaller. Leaving a recurring lead / footnote undeclared forces the Executor to improvise an unlocked size (and a core line improvised belowbodyinverts the hierarchy). Structural roles (title / body / subtitle / annotation / footnote) render at their locked size on every page — one role, one size, deck-wide. Intermediate in-band sizes are for special / feature elements only (hero number, display title, one-off emphasis); declare a recurring one as its own slot so it stays consistent too.⚠️ PPT-safe stack discipline (HARD rule). PPTX stores one
typefaceper run with no runtime fallback. Every stack MUST end with a cross-platform pre-installed font:"Microsoft YaHei", sans-serif/SimSun, serif/Arial, sans-serif/"Times New Roman", serif/Consolas, "Courier New", monospace. Non-preinstalled fonts (Inter / Google Fonts / brand typefaces) may lead the stack only when the Design Spec notes the font-install or embedding requirement.Stack length discipline. 3-4 fonts per stack is the sweet spot. Converter only writes the first Latin and first CJK font into PPTX — everything after is silently dropped. macOS-only families (
Songti SC,Menlo,Monaco,Helvetica) are auto-mapped to Windows equivalents viaFONT_FALLBACK_WIN(seescripts/svg_to_pptx/drawingml_utils.py); stacking both is redundant. Lead with Windows-preinstalled fonts (Microsoft YaHei/SimSun/Arial/Georgia/Consolas); keep at most one macOS-exclusive family (typically"PingFang SC") as a browser-preview nicety.
icons
- library: chunk-filled
- brand_library: simple-icons
- inventory: target, bolt, shield, users, chart-bar, lightbulb
libraryMUST be exactly one ofchunk-filled/tabler-filled/tabler-outline/phosphor-duotone— mixing is forbidden.brand_library: simple-iconsis optional; include only when the deck uses real company / product brand marks, otherwise omit.inventorylists approved icon names (no library prefix); Executor may only use icons from this list.
stroke_width(stroke-style libraries only) — required whenlibraryis stroke-based (currentlytabler-outline); allowed values1.5/2/3. Executor MUST apply this value to every<use data-icon="...">placeholder viastroke-width, deck-wide. Omit for non-stroke libraries (chunk-filled/tabler-filled/phosphor-duotone) — ignored there. For heavier weight switch library; do not exceed3(at 24×24 strokes merge and the icon stops reading as line art).Example for stroke-style libraries:
- library: tabler-outline - stroke_width: 2 - inventory: home, chart-bar, users, bulb
images
- cover_bg: images/cover_bg.jpg
- q3_revenue_chart: images/q3_revenue.png | no-crop
- formula_001: images/formula_001.png | no-crop
One entry per image file used. Append
| no-croponly for images that must not lose pixels (data screenshots, charts, certificates, rendered LaTeX formulas) — Executor will size the container to native ratio and usepreserveAspectRatio="xMidYMid meet". Untagged entries default to croppable (slice). Remove the section entirely if no images.
page_rhythm
- P01: anchor
- P02: dense
- P03: breathing
- P04: dense
- P05: dense
- P06: breathing
- P07: anchor
One entry per page. Key:
P<NN>(zero-padded, matching§IX Content Outlineindesign_spec.md). Value: one of the three rhythm tags. Executor reads per page and applies the tag's layout discipline — breaks the "every page looks the same" pattern.Vocabulary (exactly these three values):
anchor— Structural pages (cover / chapter opener / TOC / ending). Follow the template as-is.dense— Information-heavy pages (data, KPIs, comparisons, multi-point lists). Card grids, multi-column layouts, tables, charts all permitted.breathing— Low-density pages (single concept, hero quote, big image + caption, section transition). Avoid multi-card grid layouts (multiple parallel rounded containers as the primary structure); organize via naked text, dividers, whitespace, or full-bleed imagery. Single rounded elements (hero image corners, callouts, tags, one emphasis block) are fine. Proportions follow information weight — not a preset ratio menu.Rhythm follows narrative:
breathingpages appear where narrative genuinely pauses — section transitions, a single argument worth standalone emphasis, a deliberate stop after a dense sequence. A data briefing or consulting analysis may legitimately be nearly alldense— do not invent filler pages to pad rhythm. Validation: everybreathingpage must answer "what independent thing is this page saying?".Missing or empty section → Executor falls back to
densefor every page (legacy pre-rhythm behavior). Remove the section only for legacy decks; new decks MUST fill it.
page_layouts
- P01: 01_cover
- P03: 02a_chapter
- P04: 03a_content_abstract
One entry per page that uses a template SVG. Key:
P<NN>matching §IX. Value: the template's SVG basename without extension (e.g.,01_cover,03a_content_image_text) — Executor resolves it totemplates/<value>.svg. Modern templates ship many content-page variants (03a_content_abstract,03b_content_image_text,03c_content_three_items…); the page-type → single-file mapping inexecutor-base.md §1no longer covers them, so this section is the per-page truth.No entry for a page → that page is free design (no template inheritance). Mixed decks are supported: e.g., cover/chapter pages inherit a template while content pages are free.
Hard rule: Use both
page_layoutsandpage_chartsfor the same page only when the layout template is a compatible shell for the chart. Do not assign a conflicting layout just to fill every page: a waterfall chart should not inherit a timeline layout, and KPI cards should not inherit a circle-diagram layout unless that is the intended visual structure. When no compatible layout exists, omit the page frompage_layouts.Whole section omitted → entire deck is free design. Equivalent to no rows but cleaner; do this when zero pages reference a template.
Strategist source: copy the per-page SVG choices from
design_spec.md §VI Page Roster(or §IX outline if Roster is absent). Names must match files intemplates/exactly — typos cause silent fallback to free design.
page_charts
- P05: bar_chart
- P09: timeline_horizontal
- P12: quadrant_bubble_scatter
One entry per page that adapts a
templates/charts/chart template. Key:P<NN>matching §IX. Value: chart template basename without.svg(must match a key intemplates/charts/charts_index.json).No entry for a page → no chart on that page (or a chart that did not match any catalog template — Strategist's
no-template-matchfallback). Both cases mean Executor designs the visualization from scratch perdesign_spec.md §VII.Whole section omitted → no data-visualization pages in this deck.
⚠️ Visual floor: a content-rich deck (≥6 pages) must not leave
page_chartsempty ANDpage_layoutsempty/free-design AND carry no §VII custom-diagram rows — that means zero visual treatment was assigned and the Executor will ship a flat text-on-rectangles deck (whichsvg_quality_checker.pyhard-fails). See strategist.md "GATE — visual floor".Strategist source: copy from
design_spec.md §VII Visualization Reference List— only the rows whosereference template pathpoints to atemplates/charts/file. Pages markedno-template-matchin §VII MUST NOT appear here.
forbidden
- Mixing icon libraries
- rgba()
<style>,class,<foreignObject>,textPath,@font-face,<animate*>,<script>,<iframe>,<symbol>+<use><g opacity>(set opacity on each child element individually)- HTML named entities in text (
,—,©,–,®,…,•…) — write as raw Unicode (—,©,→, NBSP, etc.); XML reserved chars& < > " 'must be escaped as& < > " '. See shared-standards.md §1.0