Pomelo Deck Template
Reusable template for building Pomelo-branded .pptx decks with PptxGenJS, so the design system never has to be re-derived.
When to use
Any time the task is "build / redo / restyle a deck in Pomelo style" — client performance reports, pitches, proposals. If the user uploads an existing deck to restyle, keep all their data exactly and only change the layout to this system.
Setup (each session)
- Ensure files are present in the working dir:
pomelo.js,pomelo_logo.png(andexample.jsfor reference). - Install the engine if needed:
npm install -g pptxgenjsand run scripts withNODE_PATH=$(npm root -g) node build.js. - Read
example.jsfirst — it demonstrates every slide builder end to end. Copy it as your starting point.
Design system (already encoded in pomelo.js — do not hand-roll)
- Canvas: 10" × 5.625" (16:9), white background.
- Fonts: Georgia = headlines/numbers; Calibri = body, labels, tables.
- Colors: ink
1F2A2E(titles), body3D4A4E, muted8A9498(captions/page nums), coralEB6B4F(primary accent / eyebrows / numbers / arcs / logo), mint76BBA8+ green4F8B7B(secondary accent), sandE8E5DD/ light sandF7F6F3(panels & total rows), hairlineD9D7D0. - Eyebrow label: 9pt Calibri, coral, UPPERCASE,
charSpacing:3. - Slide title: Georgia ~24pt (28 on cover sections, 40 on dividers, 50 on cover).
- Motif: nested rings (outer color + white inner) bleeding off a corner.
arcsTR/arcsBL= large (cover/closing);smallArcTR= subtle (content slides). - Footer: pómelo logo bottom-right; page number
NN / TOTALbottom-left in muted gray.
API (const { PomeloDeck, TOKENS } = require('./pomelo'))
Create: const d = new PomeloDeck({ total: N, title, logo:'pomelo_logo.png' }) — total drives page numbers.
Slide builders (each returns the slide so you can add custom content):
d.cover({ kicker, title, subtitle, sub2, stats:[[num,label,sub]], footer })— stats render as a 5-up strip; long values auto-shrink.d.divider({ kicker, title, sub, accent })— section break.accent=TOKENS.CORAL(default) orTOKENS.MINT.d.content({ kicker, title, note, size, arc, page })— standard content slide with eyebrow + title + footer. Returns the slide; compose the body yourself.d.closing({ kicker, title, subtitle, footer }).
Components (call on a slide):
d.statGrid(s, [[num,label,sub,color]], { x,y,w,cols,gh,gapx,gapy,numSize })— KPI cards.d.statCell(s,x,y,w,num,label,sub,color,numSize)— single KPI.d.metricRows(s,x,y,w,[[label,val]])— label/value rows with hairlines (good beside a creative image).d.table(s, head, rows, { x,y,w,colW,fs,hfs,rowH,totalLast,boldFirst,margin })— Pomelo table (dark header, zebra rows, sand total row).d.eyebrow / d.title / d.note / d.line— primitives.
Save: await d.save('out.pptx').
Gotchas (learned the hard way — honor these)
- Long numbers wrap. In a ~1.74" stat cell, values >6 chars (e.g.
₹1,27,629,2,652,386) wrap at the default 30pt. PassnumSize:20(statGrid) — the cover handles this automatically. - Wide/long tables overflow the bottom. A full-width table fits ~13 data rows at
rowH:0.235. If a table is longer or sits below a stat grid, split it into two side-by-side tables (~4.4" wide each,colW5 cols) rather than shrinking rows into illegibility. See the n-SHIELD slide 20 pattern. - Don't over-decorate the cover. Use
arcsTRonly (skiparcsBL) when full-width content (like a stat strip) would collide with the bottom-left ring. - Preserve client data verbatim when restyling — including figures that look mathematically off. Flag them to the user separately; never silently "correct."
Workflow
- Read
example.js; copy tobuild.js. - Build slides with the builders above; reuse any client creative images at their native aspect ratio.
- Render to images for QA every time:
soffice --convert-to pdfthenpdftoppm -jpeg, orthumbnail.py. Always eyeball before delivering — check for wrapped numbers and overflowing tables. - Copy the final
.pptxto outputs and present it.