Deck & Doc Builder
A battle-tested workflow for producing beautiful, consistent slide decks and Google Docs as code, iterating fast, and shipping them straight into Google Drive without the link ever changing.
The golden rule: generate → render to image → look at it → fix → upload. Never claim a slide looks right without rendering it and viewing the PNG.
When to use
- "Make/update a deck / PPT / briefing / one-pager" (customer, exec, internal).
- "Turn these notes / meeting minutes into a clean Google Doc."
- "Put this into our Drive folder" / "update the slides I shared earlier."
- Anything where layout quality + brand consistency matter.
The loop (do this every iteration)
- Generate the artifact with code (never hand-place by guessing):
- Slides: a python-pptx script using
scripts/deck_helpers.py. - Docs: rich HTML → uploaded as a Google Doc (see
reference.md).
- Slides: a python-pptx script using
- Render to PNG and LOOK:
scripts/render.sh deck.pptx 3 5renders pages 3–5. Read the PNGs. Check overflow, alignment, color, crops, fit. - Fix the code and re-render until it's right.
- Upload / update to Drive with
scripts/gslides.py:- First time: create (returns a fileId; save it to a dotfile).
- Every later iteration: PATCH the same fileId → the share link is stable.
- Render the uploaded result once more (export Slides/Doc → PDF → PNG) to confirm Google's conversion matches your intent.
Render is cheap and the only source of truth. A tight loop of small edits + re-render beats trying to get it perfect blind.
Slides: the design system (scripts/deck_helpers.py)
- 16:9 canvas
13.333" × 7.5", blank layout, everything absolutely positioned. - Google palette (BLUE/RED/YELLOW/GREEN + grey ramp) as named constants.
- Core helpers (see file for signatures):
txt(...)— textbox;**bold**markers inside the string toggle bold,\nsplits paragraphs. This is the workhorse.card(...)rounded rectangle,bar(...)solid rect (also used as accent strips / thin connector lines),hline(...)connector,dots(...)the Google 4-dot motif,pic(...)image with crop-to-fill (no distortion),video(...)embedded mp4 with poster,scrim(...)dark alpha overlay,title(...)page title with optional 21:9 hero image + scrim,notes(...).
- Patterns that read well: KPI cards row, horizontal bar chart drawn with
bar(), alternating timeline, 2×N card grid, comparison table drawn withtxt+hline, a colored callout band at the bottom for the "so what". - Keep one slide = one idea. Put the takeaway in a colored band.
Charts
- For accurate data (pie/donut/bars that must match a table), draw with
matplotlib and embed the PNG — do not eyeball. Use a CJK font
(
Noto Sans CJK) for Chinese labels. Save as a square transparent PNG sopic()crop-to-fill doesn't clip outer labels. Seereference.md. - Make the chart numbers equal the table numbers. Inconsistent totals are the #1 thing reviewers catch.
Imagery
- Generate decorative/concept images with Nano Banana 2
(
gemini-3.1-flash-imageon Vertex). Prompt for clean, no-text, no-logo, brand-neutral visuals. Good for hero strips, concept diagrams, section art. Code inreference.md. - Real product/brand images beat generated ones — pull from the user's Drive or the official site when authenticity matters.
- User-pasted images (screenshots they drop in chat) are NOT on disk as
files — they're base64 in the session JSONL. Extract them with the snippet in
reference.md(match by theWxHshown on the attachment chip). Don't say "I can't access the image"; go get it.
Google Drive / Workspace (scripts/gslides.py)
- Auth: ADC at
~/.config/gcloud/application_default_credentials.jsonmust have drive + presentations scope; every request needs theX-Goog-User-Projectheader. (See "Setup" below.) - PPTX → Google Slides: resumable upload with
mimeType: application/vnd.google-apps.presentation(Drive auto-converts). - HTML → Google Doc: same,
application/vnd.google-apps.document. Google Docs import respects colored headings,bgcolortable cells, callout boxes (single-cell tables), and base64data:images — verified. This is how you get a pretty Doc, not a plain one. - Link-stable iteration: keep the fileId and PATCH it on every update
(
uploadType=resumable,method=PATCH). The URL stays the same so anyone you shared it with always sees the latest. - Export for self-check: export the Slides/Doc to PDF, then PNG, and look.
Content principles (for briefings)
- State outcomes plainly; verify before saying "done" (render it).
- Don't over-commit on the customer's behalf; ground vague claims in real, sourced numbers, and label estimates as estimates.
- Match the audience: internal vs customer-facing decks have different rules about citing sources, pricing, and roadmap specificity — confirm which.
- Strong logic > volume. Prefer a "problem → ask → how we help → decision" mapping table over long prose.
Setup (first run / new user)
- Auth (ADC). This skill uploads / creates / PATCHes files, so
driveandpresentationsmust be FULL (write) scopes — the.readonlyvariants cannot write. (Nodocumentsscope needed: Google Docs are created/updated via Drive's HTML→Doc import, which only needsdrivewrite.)gcloud auth application-default login --scopes=openid,email,\ https://www.googleapis.com/auth/cloud-platform,\ https://www.googleapis.com/auth/drive,\ https://www.googleapis.com/auth/presentationsdrive(write) creates/updates both Slides and Docs;presentations(write) is for any Slides-API edits;cloud-platformcovers Vertex (Nano Banana) and Slides/Docs API reads. - Project defaults to
cloud-llm-preview1for both Drive calls (X_GOOG_USER_PROJECTingslides.py) and Nano Banana (VertexPROJECTinreference.md). If you can access that project, change nothing; else set yours. pip install python-pptx pillow matplotlib; havelibreoffice+poppler(pdftoppm,pdfinfo) on PATH for the render loop.
Files in this skill
scripts/deck_helpers.py— the python-pptx design-system library (import it).scripts/gslides.py— Workspace: token, upload→Slides/Doc, PATCH, export PDF.scripts/render.sh— pptx/pdf → PNG pages for visual self-check.reference.md— Nano Banana gen, matplotlib donut, pasted-image extraction, Google-Doc HTML styling recipes, gotchas.