wepr-slides · git:20260815.9b3eae3 · 2026-08-15 · sha256 c5fe66aec138d311
wepr-slides git:20260815.9b3eae3B
Immutable. This exact content is served forever at /api/v1/blob/c5fe66aec138d311.
---
name: wepr-slides
description: 创建和编辑单文件 .bento.html 演示文档,文档内容以 JSON 形式保存在“#bento-doc”脚本块中。适用于从零制作演示文稿、根据现有资料生成方案,或优化已有 .bento.html 文件;可用于客户方案、报价展示、策略汇报和复盘材料。
---
# Authoring Bento decks
Use `$wepr-presentation-workbench` first when the user has not chosen between editable PPTX and single-file HTML, or when the task needs narrative planning, template selection, presenter notes, client-deck structure, and cross-format delivery QA. This skill owns only the Bento HTML route.
For WEPR proposals, strategy decks, quotation presentations, quarterly reviews,
and client reports, first read `references/wepr-delivery.md`. Keep claims,
figures, pricing, platform scope, and source dates consistent with the approved
source document or spreadsheet.
A Bento deck is one self-contained `.bento.html` file. The document is plain
JSON in a single block:
```html
<script type="application/bento+json" id="bento-doc"> { "format":"bento/slides", ... } </script>
```
You edit **that block only**, in place. Escape every `<` in the JSON as
`\u003c` so it can never contain a literal `</script>`. Leave the rest of the
file (the compressed runtime) untouched. In a chat context instead, the user
copies the JSON out (*Save ▾ → Copy document JSON*) and pastes your
replacement back (*Save ▾ → Replace from JSON…*); `window.bento.loadDoc(json)`
does it from the console.
## Starting from nothing
The user does NOT need Bento installed — the app ships inside every deck.
When there is no `.bento.html` to edit, fetch the latest signed release
yourself and author into it:
```bash
# name the file after the deck's topic, e.g. Q4_Review.bento.html
curl -fsSL https://bento.page/releases/slides/Bento_Slides.bento.html -o "<Topic>.bento.html"
```
(Windows without curl: `iwr https://bento.page/releases/slides/Bento_Slides.bento.html -OutFile <Topic>.bento.html`.)
Then verify the download contains `id="bento-doc"`, and **replace** that
block's JSON (it ships with a showcase deck — discard it) with your document.
Use `python3 scripts/wepr_deck.py inject <deck.bento.html> <document.json>`
for deterministic replacement and `python3 scripts/wepr_deck.py validate
<deck.bento.html>` before delivery. Current shells may contain an empty
`#bento-doc` block; that is valid and ready for injection.
Rules for a fresh document:
- **Fetch https://bento.page/agents.md BEFORE authoring** and start from its
"Minimal valid document" skeleton. `size` and `theme` (including
`theme.fontFamily`) are **required** — the app will not boot without them.
- **Fully specify element fields** as the skeleton shows (shapes need
`stroke`/`strokeWidth`; text needs `fontFamily`/`align`/`valign`) — missing
fields render wrong or not at all.
- **Omit `docId` and `collab` entirely**: the app mints a fresh identity and
dormant collaboration credentials on first open.
When done, offer to open it (`open` / `xdg-open` / `start`) — the file boots
straight into the editor with the finished deck. Aim for one pass from
request to opened deck.
## Workflow
1. **Find the document.** Locate the `#bento-doc` block; parse its JSON. Note
`doc.size` (canonical 1280×720), `doc.theme`, existing element `id`s, and
whether `doc.template`/`doc.readonly` are set.
2. **Read the source material the user gave you** and classify each piece —
is it a stat? a table? a process? a definition to expand? a photo?
3. **Map material → feature (do NOT default to bullet text).** This is the
step that makes it a Bento deck rather than a slideshow of paragraphs:
- numbers to compare visually (trend, magnitude, share) → a **chart** element
- a comparison / spec / pricing / feature grid → a **table** element
(`columns` weights + `rows` of `cells` + a `style` object)
- consecutive slides about the **same thing changing** → **morph**: give
shared elements the same `id` on both slides + `transition:"morph"` on
the later one (Bento's signature move — reach for it liberally)
- a point to **drill into** → a **state slide** (`stateOf` + element `link`)
- a **hero / full-slide image** → full-bleed image + scrim rect + text,
with **ken-burns** drift
- a **sequence / flow / timeline** → a line/`path` with a `dash-march`
loop, or morph a highlight through the steps
- a **headline number** → big text + `fx:{countUp:true}`
- **every cover / divider** → at least one ambient motion
- **repeated chrome / logo** → keep its `id` stable across slides so it
morphs in place
- a **demo clip / recording / soundbite** → a **media** element
(`kind: video|audio`); embed short clips as a data URI, link big ones by
URL to keep the file small
4. **Author** using the schema. Keep the full schema and copy-paste recipes
open: **fetch https://bento.page/agents.md** (it has the element shapes,
the morph/chart/state/ken-burns snippets, and the gotchas). Respect one
accent colour, ≤2 typefaces, 96px side margins (right-most x ≤ 1184),
and write **speaker notes** on each slide.
5. **Self-audit before finishing:**
- [ ] any numbers rendered as text that should be a **chart**?
- [ ] do consecutive slides on one subject share **ids + `transition:"morph"`**?
- [ ] at least one **motion moment** (ken-burns / loop / count-up), esp. the cover?
- [ ] a drill-down that would work better as a **state slide**?
- [ ] one accent colour, ≤2 typefaces, 96px margins?
- [ ] speaker notes on every slide?
6. **Write back** the edited `#bento-doc` block (escaping `<`), or return the
replacement JSON. Never regenerate the whole HTML file.
7. **Validate** with `scripts/wepr_deck.py validate`, then open the file in a
browser and review every slide, interaction, chart, note, and margin.
## Critical gotchas
- **Charts:** bar/line series `data` must be **plain numbers** (`{value,…}`
item objects coerce to 0 — only pie takes `{name,value}`); colour by
series, not per bar; `option` is pure JSON, template formatters only
(`{b}`/`{c}`/`{d}`), never functions.
- **Morph needs deterministic, stable ids** shared across the slides that
should animate together. Different ids = no morph (elements just cut).
- **Images/fonts must be embedded** as data URIs in `doc.assets` and
referenced by `"asset:<key>"` — the file stays self-contained.
- **Media:** a `media` element (`kind: video|audio`) embeds short clips as a
data URI in `src` (self-contained) or references a URL for big files (keeps
the deck small). `autoplay` runs only in present mode and needs `muted:true`
for video. Don't embed large videos — they bloat the file.
- **Never regenerate `docId`** when editing an existing deck; it is the
document's identity. (Fresh decks omit it — the app mints one.)
- `template:true` → every open mints a fresh deck; `readonly:true` → the
file boots straight into the show with no editor.
Working examples of every technique: open any template at
https://bento.page and read its `#bento-doc` block.