Deck projects
August 30, 2026 ยท View on GitHub
A deck project separates the locked semantic contract from page content:
my-deck/
deck.spec.json
theme.json
pages/
cover.json
problem.json
close.json
assets/
hero.jpg
logo.png
deck.json
Only deck.spec.json is required. theme.json is an optional frozen copy of the bound theme. Page and asset directories grow as work proceeds. deck.json is derived output from assemble, not an authoring source.
The project follows the same serial chain as the product:
intent -> narrative -> theme -> spec -> fill -> render
The spec owns semantics
{
"version": "1",
"narrative": "boardroom-report",
"theme": "acme-report",
"filename": "quarterly-review.pptx",
"meta": {
"organization": "Acme",
"date": "2026-08-30",
"confidentiality": "internal"
},
"branding": "full",
"pages": [
{
"id": "cover",
"type": "cover",
"heading": "Quarterly review",
"summary": "Decisions for the next operating cycle"
},
{
"id": "performance",
"type": "chapter",
"heading": "Performance"
},
{
"id": "growth",
"type": "content",
"kind": "data",
"heading": "Expansion drove the quarter",
"summary": "Show revenue mix and the two largest contributors",
"focus": "chart"
},
{
"id": "close",
"type": "ending",
"heading": "Decisions"
}
]
}
The spec owns narrative, theme binding, output filename, metadata, deck brand, branding posture, page order, each page's id, type, heading, and every content page's kind. summary and focus are optional fill guidance. Prefer a component type for focus.
Validate it before filling pages:
pptwise schema --spec > deck-spec.schema.json
pptwise spec validate my-deck/deck.spec.json
Validation resolves the bound theme. A content kind absent from its menu is a hard error with the available kinds. Headings and page-count ranges are also checked. Three consecutive content pages with the same kind produce an advisory.
Page files contain only fill
pages/growth.json can contain:
{
"components": [
{
"type": "chart",
"chart_type": "bar",
"series": [
{
"name": "Revenue",
"data": [
{ "x": "Expansion", "y": 62 },
{ "x": "New business", "y": 38 }
]
}
]
}
],
"footnote": "Share of quarterly growth",
"notes": "Expansion was concentrated in the enterprise segment."
}
The fillable fields are components, background, image_side, footnote, and notes. Page files cannot contain type, kind, or heading. Those are locked by the spec. An orphan file whose id is absent from the spec is also a hard error.
Fill in batches of at most four pages, then run assemble and validate. This keeps capacity and component mistakes local.
Placeholders are normal
When a spec page has no matching page file, assembly creates a semantic placeholder with its locked id, type, kind, and heading. Assemble and validate accept placeholders. Final render blocks them unless --draft is explicit.
Placeholders let the author confirm the whole page sequence before writing every page. They do not weaken the spec contract.
Assets are project-local
Files under assets/ are registered by filename. Components reference the basename as asset_id. Keep human-selected stock and generated assets under this directory or the managed .pptwise/<deck>/assets/ directory used by image commands.
Run pptwise asset-brief my-deck/ before sourcing images. It resolves the bound theme and real page face, then reports actual frames, crop posture, palette, safe zones, and generation prompts.
Assembly stores no rendering choice
pptwise assemble my-deck/
Assembly writes IR v5 to my-deck/deck.json by default. It combines spec-owned fields, page fills, and scanned assets. It does not write face ids, seeds, page arrangements, or any other rendering selection into source or derived IR.
All main consumer commands also accept the directory directly and assemble it in memory:
pptwise validate my-deck/
pptwise audit my-deck/
pptwise render my-deck/
pptwise preview my-deck/ --html
Treat deck.json as an inspection or interchange artifact. Edit the spec or page files, then regenerate it.
Theme binding and rebinding
spec.theme resolves by name from the deck directory, upward workspace themes/ directories, then factory presets. Render has no theme override.
Freeze a workspace theme by copying it to my-deck/theme.json with the same id. Project commands load it automatically, and serve watches it.
A palette fork preserves the menu byte for byte. It may replace the project binding, followed by spec validation, assembly, IR validation, audit, and render.
If the next theme menu differs, return to the theme step. Keep useful claims, facts, data, images, and copy, then revise the semantic page sequence and affected fills around the new menu. A theme change is not a repaint of an already assembled deck.
Live review
For a self-contained review file:
pptwise preview my-deck/ --html
For a browser session that refreshes when the spec, page files, assets, or deck-local theme change:
pptwise serve my-deck/ --no-open
Preview output is read-only. A reviewer describes a change, and the author edits the smallest owning source file. Content revisions belong to one page file. Order, type, kind, heading, and theme changes belong to the spec.
Disassemble an IR
pptwise disassemble deck.json -o my-deck/
Disassembly writes a version 1 spec, one content-only file for every non-placeholder page, and local asset files when possible. It refuses to overwrite an existing deck.spec.json. The resulting project still contains no persisted face choice.
Workspace names
pptwise.config.json can set a deck root. Commands that accept <target> can then resolve a bare deck name under that root. An explicit path still wins. This affects project discovery, not theme binding or page semantics.