Overview
Build clean, consistent 16:9 PowerPoint decks by calling a ready-made helper library — you supply only content; the library owns all coordinates, colors, fonts, spacing, and arrow-drawing.
Core principle: Never compute slide geometry or restyle shapes by hand.
Import deckbuilder.Deck and call its slide methods. Building raw python-pptx
shapes from scratch is the #1 cause of broken layouts, overlapping boxes,
text-only "diagrams", and wrong imports. Don't do it.
Fastest path — requirement review in ONE call (start here)
If the task is an OpenHarmony Requirements change review / Requirements review deck (the common case),
do NOT hand-assemble slides and do NOT choose builders yourself. Fill one plain
spec dict and make a single call — the library owns the page order, which builder
each page uses, and every fixed table shape (5 impact target rows, 8 risk rows, 11 delivery
columns). This is the most reliable path and removes the top mistake (picking the
wrong builder, e.g. four cards for the value page).
from deckbuilder import Deck
Deck().requirement_review_deck(spec).save("requirement_change_review.pptx")
- Copy
examples/requirement_review_oneshot.py, replace the<placeholders>, keep the structure, run it. That's the whole job. - Every field is optional — anything you leave out renders as To be assessed / TBD, never fabricated. List those TBD fields back to the user.
spec["design"]may be one dict (one design solution page) or a list of dicts (multiple, auto-paged).spec["delivery"]["items"]is one row per sub-requirement; the total row is summed for you.- The 8 fixed pages, in order: Cover · Requirement value description · Requirement design solution · Requirement change background · Requirement change impact analysis · Version delivery plan · Compatibility analysis · Risk assessment.
The full spec shape is documented in the requirement_review_deck docstring and in
examples/requirement_review_oneshot.py. Everything below is the manual / advanced
mode — the individual builders, for non-review decks or one-off custom pages.
Page → builder map (do not deviate)
For requirement review pages, each page has exactly ONE correct builder. Never use
content_slide / banded_slide for the value or design pages — that produces the
"four boxes" / rainbow-bars result. (The library will warnings.warn if you do.)
| Page | Builder | Never use |
|---|---|---|
| Requirement value description | value_slide (text left, image right) |
❌ content_slide (four cells) |
| Requirement design solution | design_slide + diagram= (text left, image right + block diagram) |
❌ content_slide / bullet list |
| Requirement change background / impact analysis / compatibility / risk | table_slide |
❌ banded_slide (colored horizontal bars) |
| Version delivery plan | table_slide (11 columns) |
❌ Hand-written column widths/font sizes |
When to Use
- Converting an OpenHarmony requirement document / spec / design proposal into a review deck — this is the primary trigger
- Requirements review / Requirements change review / Design review decks (OH-branded, fixed structure)
- Feature-proposal decks that follow the OH review flow
- Such decks needing an architecture / data-flow diagram (real boxes + arrows) or comparison / breakdown tables
When NOT to use: generic or non-OpenHarmony slide decks (this skill always
stamps the OpenHarmony logo and imposes the OH review structure — it is not a
general-purpose PPT maker); editing an existing .pptx the user already has (open it
with python-pptx directly); or when the user wants Markdown/PDF instead.
Setup (do this first)
python3 -c "import pptx" 2>/dev/null || pip install python-pptx
The library file deckbuilder.py lives in this skill's scripts/ directory,
alongside oh_logo.png (the OpenHarmony logo). Copy both (keep them together)
next to your build script, or add the scripts/ dir to sys.path —
deckbuilder.py auto-finds the logo in its own directory, so the two files must
stay side by side. Then write ONE script that imports it and calls slide methods in
order, e.g.:
import os, sys
sys.path.insert(0, os.path.join("<skill-dir>", "scripts"))
from deckbuilder import Deck
Visual style (built in — do not re-implement)
The library renders a light theme with a red accent ("red ink"): titles are near-black ink (subdued, not a loud color), a single red accent carries each page's conclusion and primary path, structure is soft neutral grey, blue is used for value-page body text and table headers, and amber is reserved for change points. Every choice below is automatic, you never set colors or coordinates:
- The conclusion is the highlight, not the title. Each page's 32pt title is calm
near-black ink (
primary); the eye is drawn instead to thetakeawayconclusion line, rendered in red (accent) right under the title. The red accent also draws the title underline and primary data-flow arrows. Everything else — secondary arrows, grid, connector bars, box borders — is soft grey (grey). Do NOT give cards/sections different accent colors — that produces a rainbow ("impure") deck. Leaveaccentunset (defaults to red). - Reserve hue changes for real meaning only:
red(a muted brick-red) for an actual risk/blocker; the built-in★变更change box (a light-amber fill with an amber badge, drawn for you when you pass"change": True).green(the logo green) exists but is rarely needed — don't sprinkle colors to "add color". - Cover & headers. Cover has a thin red spine; each content page is a 32pt Microsoft YaHei ink title on white with a thin red underline and the page number top-right.
- OpenHarmony logo, bottom-left of every page (cover included) — added
automatically from
oh_logo.png. If the file is missing it's silently skipped. - Diagrams are real drawing boxes — rounded rectangles joined by arrows.
- Tables — slate-blue header (
C6D7EC) with black bold text, white body, and black solid grid lines; fonts follow the value/design page standard (header 15pt bold, body 13.5pt). Light-red total row whenhighlight_last=True. All drawn for you.
The Only API You Need
from deckbuilder import Deck
deck = Deck() # 16:9; font defaults to "Microsoft YaHei"
# ── EASIEST: whole 需求评审 deck in one call (see "Fastest path" above) ──
deck.requirement_review_deck(spec) # spec = dict; fixed 8-page 需求变更评审
# ── or assemble pages manually (advanced / non-review decks) ──
# NOTE: every content slide below REQUIRES takeaway="结论:…" (the page's one-line
# conclusion) — pass it as a keyword. Omitting it raises ValueError. Only cover()
# takes no takeaway.
deck.cover(title, subtitle=None, meta_lines=[...])
deck.content_slide(title, cards, takeaway="结论:…", subtitle=None)
deck.banded_slide(title, sections, takeaway="结论:…", subtitle=None)
deck.bullets_slide(title, bullets, takeaway="结论:…", subtitle=None)
deck.table_slide(title, headers, rows, takeaway="结论:…", col_widths=None, highlight_last=False)
deck.flow_slide(title, stages, takeaway="结论:…", note=None, lane_label=None)
deck.layered_diagram_slide(title, layers, takeaway="结论:…", connect=None, note=None)
deck.architecture_slide(title, nodes, edges, takeaway="结论:…", note=None)
# Two-column pages (左文右图) — title is 28pt bold YaHei; takeaway is OPTIONAL here:
deck.value_slide(title="需求价值描述", background=[...], features=[...], scope=[...], image=None)
deck.design_slide(title="需求设计方案", design=[...], changes=[...], extra=None, image=None)
deck.save("output.pptx")
Every page leads with its conclusion — takeaway is REQUIRED. Pass
takeaway="结论:…" (one short sentence) to every content slide — it renders as a bold
red line with a red kicker right under the (subdued ink) title, so the
reviewer's eye lands on the point before the detail.
The title stays the topic label (五、兼容性分析); the takeaway carries the verdict
(不改变公开 API 行为,应用无需适配). Write an assertion, not a restatement of the
title. subtitle (small grey) still exists for neutral scope notes; if both are
given, takeaway wins the slot. takeaway is mandatory: a content slide built
without it raises ValueError and the deck will not save. There is no way to ship a
page without its highlight — write the one-line verdict for every slide.
Page numbers auto-increment (cover is excluded). Header band, accent colors, and
spacing are automatic. Colors are passed by name string — "accent" (red)
and "grey" (soft grey) cover almost everything; "red" for a genuine risk;
"green", "orange", "primary" exist but are rarely the right call. Default to
omitting accent (or using "accent") so the deck stays one coordinated family —
don't vary it per card just to add color.
Quick reference — what each method takes
| Method | Key argument shape |
|---|---|
requirement_review_deck |
spec={...} — whole 8-page requirement change review in one call. Preferred for review decks. Missing fields → To be assessed/TBD. See examples/requirement_review_oneshot.py |
cover |
strings + meta_lines=["Team", "2026-06-23"] |
content_slide |
cards=[{"title","bullets":[...]}] (1–6 auto-grid). Per-card accent is ignored — all cards render in one family (no rainbow). For requirement change review 4–7 use table_slide, not this |
banded_slide |
same sections=[{"title","bullets"}] shape, rendered as full-width horizontal bars stacked top→bottom. Per-section accent is ignored — all bars are one color. Avoid for requirement change review 4–7 (use table_slide); the colored horizontal bars it used to make were the #1 "impure" complaint |
bullets_slide |
bullets=["text", {"text","level":1,"accent","bold"}] |
table_slide |
headers=[...], rows=[[...],[...]], highlight_last=True for totals. col_widths are relative weights — auto-scaled to fit, never overflow |
flow_slide |
stages=[{"title","lines":[...],"change":True}] → 1 row, auto arrows |
layered_diagram_slide |
layers=[{"label","nodes":[{"title","lines","change"}]}] + optional connect |
architecture_slide |
nodes=[{"id","title","lines","row","col","change"}], edges=[{"from","to","label","dir":"f"/"both","accent"}] — labeled directional connectors for high-level module interaction |
value_slide |
background=[...], features=[...], scope=[...], image=None. Two-column requirement value description page (see below). takeaway optional |
design_slide |
design=[...], changes=[...], extra=[{"heading","lines"}], image=None. Two-column requirement design solution page (see below). takeaway optional |
Requirement value description / Requirement design solution — the two-column pages (text left, image right)
Two dedicated builders for the standard requirement review value + design pages. Title is
Microsoft YaHei, bold, 28pt (auto-shrinks only if absurdly long). Left column =
stacked sections; right column = a scene/architecture image (pass image=) or,
if omitted, a labeled placeholder card telling the user where to paste one.
Typography is fixed and built in — section heading 15pt bold, body 13.5pt,
not bold. takeaway= is OPTIONAL on these two pages (they lead with their sections,
not a one-line verdict).
value_slide — Requirement value description (3 sections)
deck.value_slide(
title="需求价值描述",
background=["…"], # 段一「背景」 — body BLUE 13.5pt
features=["…"], # 段二「特性及价值点」— body BLUE 13.5pt
scope=["…"], # 段三「需求收益(影响)范围」— body BLUE 13.5pt
image="scene.png", # 右侧场景图(可选,缺省显示占位卡)
)
- Paragraph 1 "Background" — blue body text. Requirement origin / current problems.
- Paragraph 2 "Features and value points" — blue body text.Clarify where the requirement value lies, reference: user pain points, requirement function points, scope, user scenarios, value brought. toD content must be cleardeveloper applicable scope, clearresults achieved by developers after completion; capability improvement requirements cannot be detached from the business (besides capability goals, after the capability is provided, thebusiness goals、capability opening scope); quantifiable goals: number of active users, positive review rate, new user retention, etc.;Product scope: products involved in 1+8+N.
- Section 3 "Requirement benefit (impact) scope" — blue body text. Describe the feature'sscope of use, region, specific products, Focus on feature generality, and do not allow features to be made for a single product only (except for hardware dependencies).
- Place a scenario diagram on the right halfto show the value of the feature.
design_slide — Requirement design proposal (text on the left, image on the right, can span multiple pages)
deck.design_slide(
title="需求设计方案",
design=["…"], # 1、设计方案:设计重点(交互模块及如何达成需求的规格等)
changes=["…"], # 2、变更点及影响(见下)
extra=[{"heading": "三、UI 示意", "lines": ["…"]},
{"heading": "四、裁剪说明", "lines": ["…"]}], # 可选追加段落
image="arch.png", # 右侧架构图(可选)
)
- 1. Design proposal — output the design focus of the design proposal, such as interaction modules and how to achieve the required specifications, etc.
- 2. Show change points and impacts — including but not limited to: data structure changes, external interface changes, external dependency analysis, performance and power consumption evaluation, key KPIs affecting user experience, etc.
- There can be multiple design proposals, and they can be output on multiple pages —— call once for each proposal
design_slide(automatic page turning). - If UI is involved, a specific schematic diagram is required —— place the schematic diagram as
image=on the right side, or add a "UI schematic" section inextra. - If trimming a requirement that is already online, the requester's opinion is required —— add an explanatory paragraph in
extra. - An architecture diagram can be placed on the right for supplementary display(
image=)。
Architecture diagrams (the part models get wrong)
A design/system slide MUST be a real diagram — boxes connected by arrows — not a bullet list. Three builders, all auto-layout and auto-draw arrows. Pick by intent:
flow_slide— one left-to-right pipeline (data flow through stages).layered_diagram_slide— stacked planes (e.g. control plane over data plane).architecture_slide— high-level module interaction: how a subsystem touches its peers. Use this for the "system-level architecture / overall impact on OpenHarmony" slide. Labeled, directional connectors say WHAT each link is and WHICH way it flows — far clearer than uniform arrows. See the requirement-review template for the canonical OH-module example.
Simple pipeline — one left-to-right flow. Mark changed components with
"change": True (renders a light-amber box with an amber ★变更 badge + border):
deck.flow_slide("System Design — Data Flow", [
{"title": "HID device", "lines": ["USB / BT"]},
{"title": "normalize", "lines": ["resolve binding"], "change": True},
{"title": "windows mgr", "lines": ["hit test, isolate state"], "change": True},
{"title": "UDS dispatch", "lines": ["consistent ids"]},
], takeaway="结论:变更集中在 normalize 与窗口命中两处",
note=["normalize resolves the binding before coordinate calc.",
"Light-amber ★变更 boxes are the change points."])
Layered diagram — stacked planes (e.g. control plane over data plane). Each
layer is a row; connect draws vertical arrows between nodes by [layer, node]
index:
deck.layered_diagram_slide("System Design — Framework", [
{"label": "control", "nodes": [
{"title": "Service (SA)", "lines": ["bind request"]},
{"title": "BindHelper", "lines": ["runtime state", "inner API"], "change": True}]},
{"label": "data", "nodes": [
{"title": "device", "lines": ["event"]},
{"title": "normalize", "lines": ["resolve"], "change": True},
{"title": "dispatch", "lines": ["consistent"]}]},
], connect=[[[0, 1], [1, 1]]], # BindHelper → normalize (down arrow)
takeaway="结论:BindHelper 变更下沉到 normalize 阶段",
note="Helper feeds the normalize stage.")
Requirement-CHANGE-review decks (requirement change review) — use the fixed template
Prefer the one-call path (deck.requirement_review_deck(spec) — see "Fastest path"
at the top). It builds this exact 8-page structure for you, so you can skip the
manual builder choices below. The rest of this section documents what each page
contains — useful for filling the spec, or for building pages by hand when you need
a variation.
When the user asks for a requirement change review / requirement-change-review deck, or gives a
page-by-page brief (requirement value → requirement design proposal → requirement change background → requirement change impact analysis →
version delivery plan → compatibility analysis → risk assessment), follow the 8-page structure in
requirement-review-template.md instead of inventing
an outline. examples/requirement_review_example.py is a complete, generic fill-in deck.
The fixed page order (cover counts as page 1):
- Cover —
cover - Requirement value description —
value_slide(text on the left, image on the right, unchanged) - Requirement design proposal —
design_slide(text on the left, image on the right + block diagram on the right, unchanged; can span multiple pages) - Requirement change background —
table_slide: ① description of the requirement to be trimmed/changed (original requirement/number, feature overview and impact, usage scenario, with emphasis on 2C/2D value and impact); ② decision minutes from when the original was accepted (SIG review approval record) - Requirement change impact analysis —
table_slide, 5 rows: northbound application developers / southbound developers / distributed devices / system developers (cross-subsystem dependencies) / device users - Version delivery plan —
table_slide, 11 columnshorizontal plan table: undertaking domain / undertaking type (IR/SR) / main requirement content / landing version / designer / lines of code / whether API is involved / end-to-end workload (500 lines ≈ 1 person-month) / domain PM / whether the pipeline is satisfied / whether the workload is reviewed OK by the domain PM.Break the requirement down into multiple sub-requirements, one per row, and present the workload row by row, with the last row usinghighlight_last=Truetotal - Compatibility analysis —
table_slide: Whether application compatibility is involved; compatibility includes (mechanism/permissions/API behavior/other); compatibility plan; application adaptation plan and schedule - Risk assessment —
table_slide, Fixed 2 columns, 8 rows checklist
What this page reliably gets wrong (the top two are the most-reported):
- Pages 4–8 must be
table_slide, neverbanded_slide/content_slide. The bar/card builders tempt you to color each section differently → multi-colored horizontal bars ("impure"). Build them as field tables (pages 4/5/7/8 two-column item|content; page 6 is an 11-column wide table). (The engine also forces those builders to one color now, but tables are the right layout here.) - Every
table_slidepage must passtakeaway="结论:…"— a topic title over a table with no conclusion has no highlighting. This is enforced: a slide withouttakeawayraisesValueError, so the deck will not build until every page has its verdict. (value_slide/design_slidetaketakeawayoptionally.) - Keep pages 2–3 (value/design) as the two-column text-left image-right builders — do NOT convert
them to tables. Page 3's right column is a real block diagram (
diagram=layers orimage=), never a bullet list. - Page 5 has exactly 5 impact target rows, in order: northbound application developers → southbound developers → distributed devices → system developers (cross-subsystem/component dependencies) → device users (performance/power consumption/functionality/experience).
- Page 6 Version delivery plan is a fixed 11-column wide table — break the requirement down into multiple sub-requirements, one per row,
presenting the workload row by row, with the last row
highlight_last=Truetotal; the header/body font size automatically shrinks with the number of columns, do not manually set the font size or hard-code column widths in inches;col_widthspass relative weights. - Page 8 is a fixed 2×8 checklist — these 8 rows, in order: whether there is an impact on performance/power consumption/RAM/ROM; whether there are other dependencies; whether there is a security risk; whether legal/compliance issues are involved; whether external commitments are involved; whether it is open source; whether AI is involved; privacy risk feature identification. Answer each with Yes/No/To be assessed + one sentence.
- Mark absent fields
待评估 / TBD(requirement number, SIG decision minutes, delivery version, designer, lines of code, end-to-end workload, domain PM, applicable region/product, external commitments, compliance/security conclusion) and list them back to the user — never fabricate them.
Workflow
- Install python-pptx if missing; make
scripts/deckbuilder.pyimportable (add thescripts/dir tosys.path, keepingoh_logo.pngalongside it). - If the source is a spec/doc, read it and pull the real content per slide.
Don't invent technical facts; if a number (e.g. effort) isn't given, label it
an estimate or use
TBD. - Write the build script:
- Requirements review deck → copy
examples/requirement_review_oneshot.py, fillspec,deck.requirement_review_deck(spec)→deck.save(). One call, done. - Other decks →
Deck()→ one method call per slide →deck.save().
- Requirements review deck → copy
- Wrap the build in
warnings.catch_warnings(record=True)so anytable_slidecontent-overflow warning is captured, not just printed and lost — see Verification below. - Run it. Then verify (next section). Report the output path + slide count.
Verification before claiming done
Always run this after building — it confirms the file opens, no
table_slide overflowed its content, and nothing overflows the canvas:
import warnings
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
# ... build the deck here (or re-import/re-run the build script) ...
table_warnings = [str(x.message) for x in w if "table" in str(x.message)]
from pptx import Presentation
p = Presentation("output.pptx"); W, H = p.slide_width, p.slide_height
bad = 0
for i, s in enumerate(p.slides):
for sh in s.shapes:
if sh.left is None: continue
if sh.left < 0 or sh.top < 0 or sh.left+sh.width > W+2000 or sh.top+sh.height > H+2000:
bad += 1; print("overflow on slide", i+1)
print("slides:", len(p.slides._sldIdLst), "overflow:", bad,
"table warnings:", len(table_warnings))
# both overflow == 0 AND table_warnings == [] must hold
No renderer (LibreOffice) is needed; the bounds check is the smoke test. It
catches SHAPE-level overflow (a table/box positioned or sized past the
canvas edge). table_slide() now sizes each row to the actual measured
wrapped-text height of its cells (not a flat row-count average), and leaves
the table at its true (taller) height instead of force-compressing it when
content doesn't fit — so a table with genuinely too much text pushes its
shape past BODY_BOTTOM and IS caught by the check above, rather than
silently shrinking rows until text is visually clipped. If table_slide()
cannot fit the content even at its minimum font size, it also raises a
Python UserWarning naming the table — treat that warning as a build
failure and split the rows across multiple table_slide() calls or shorten
the cell text.
takeaway is enforced — the build fails without it. A content slide built
without takeaway="结论:…" raises ValueError naming the slide, so a deck that saves
successfully already has a conclusion on every page. If your script errors with
slide '…' was built without takeaway=, add the one-line verdict to that slide and
rerun — do not work around it.
Common Mistakes
| Mistake | Fix |
|---|---|
| Hand-assembling a requirements review deck page by page (and picking a wrong builder) | Use deck.requirement_review_deck(spec) — one call, fixed 8 pages |
Making the value/design page a content_slide four-quadrant / bullet list |
Use value_slide / design_slide(text left, image right; on the design page pass on the right diagram=)— the library warns if you don't |
Building shapes with raw python-pptx and hand-picked inches |
Use Deck methods; they place everything for you |
from pptx.dgm... / guessing import paths |
The library already imports correctly — just from deckbuilder import Deck |
| Design slide is a bullet list, not a diagram | Use flow_slide or layered_diagram_slide |
Passing RGBColor(...) everywhere |
Pass color names; default to "accent"/"grey", names map to the palette |
Giving every card/section a different accent (rainbow horizontal bars) |
Don't — per-card/section colors are ignored by design; for requirement change review 4–7 use table_slide |
Pages 4–8 as colored banded_slide bars |
Use table_slide (item|content / plan wide table) — the bars invite the "impure" rainbow |
| Pages with no point — just a topic title over a table | Give every content slide a takeaway="结论:…" one-liner; it's required — a slide without it raises ValueError |
| Cramming 8+ cards on one slide | Max 6 per content_slide; split across slides |
| Putting >8 rows in one table at full font | The library auto-shrinks; still split very long tables |
| Claiming done without running it | Run the script + the overflow check, report path & slide count |
Real-World Impact
This skill was distilled from building OpenHarmony requirement change review decks (cover, requirement value
description, requirement design solution, requirement change background, requirement change impact analysis, compatibility analysis, risk assessment). The
two-column value/design pages carry a real block diagram on the right, and the change-review pages
(4–7) are clean item|content field tables — both reproducible in a few lines via
value_slide / design_slide / table_slide.