# Snapdeck

> >

- **Type:** Skill
- **Install:** `agentstack add skill-hacka0wi-snapdeck-snapdeck`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [hacka0wi](https://agentstack.voostack.com/s/hacka0wi)
- **Installs:** 0
- **Category:** [Web & Browser](https://agentstack.voostack.com/c/web-and-browser)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [hacka0wi](https://github.com/hacka0wi)
- **Source:** https://github.com/hacka0wi/SnapDeck/tree/main/plugins/snapdeck/skills/snapdeck

## Install

```sh
agentstack add skill-hacka0wi-snapdeck-snapdeck
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# SnapDeck — live web app → polished PowerPoint

This skill produces decks the way a good design pipeline does: **author each slide as
HTML/CSS, render it to a 1920×1080-class PNG with headless Chrome, and drop the PNGs into the
deck full-bleed.** Do NOT lay slides out with python-pptx textboxes/shapes — pixel control
(shadows, gradients, fonts, framed screenshots) is the whole point.

Two kinds of slide:
- **Design slides** (title, dividers, diagrams, tables, code) — HTML/CSS → PNG. Network-free.
- **Screenshot slides** — REAL captures of the running app, placed full-bleed with optional
  numbered callouts. Captured via headless Chrome driving the live app (CDP).

## Pipeline (3 stages)

```
1. CAPTURE   scripts/capture.js   live app → shots/.png + shots/.rects.json
2. GENERATE  scripts/slides.py    content + shots → slides/.html      (design system)
   RENDER    scripts/render.js    slides/*.html → slides/*.png  (headless Chrome, dsf 2)
3. ASSEMBLE  scripts/assemble.py  ordered slides/*.png → out.pptx (16:9, full-bleed)
```

Work in a scratch dir (e.g. the session scratchpad), `npm i puppeteer-core` once, and use the
**system Chrome** via `executablePath` (not a bundled Chromium). Run capture/render with the
sandbox disabled (they need network + to launch Chrome).

## Prerequisites
- System Google Chrome (`/Applications/Google Chrome.app/Contents/MacOS/Google Chrome` on macOS).
- Node: `npm i puppeteer-core` in the work dir.
- Python: `python3 -m pip install python-pptx Pillow`. On macOS, a broken Homebrew `python3`
  (3.14 pyexpat) is common — use `python3.11` if `import pptx` fails.

## Capturing the live app (the hard, valuable part)

`scripts/capture.js` is config-driven. Key techniques baked in — keep them:

1. **Skip login by injecting the session.** Most SPAs keep auth in `localStorage`. Read the
   value from a browser you're already logged into (e.g. via the Chrome MCP `javascript_tool`:
   `localStorage.getItem('auth-storage')`) and write it to `auth.json`. capture.js sets it with
   `page.evaluateOnNewDocument` BEFORE any page script runs, so every navigation is authed.
   (httpOnly auth cookies are not needed — the client AuthGuard reads localStorage.)
2. **Force LIGHT mode** (decks must be light). The app theme often re-asserts on hydration, so
   set it BOTH ways and AFTER load: `localStorage[themeKey]=light`, `emulateMediaFeatures
   prefers-color-scheme:light`, and `document.documentElement.setAttribute('data-theme','light')`
   right before each screenshot. Verify each shot is light before using it.
3. **Open modals/rows with a REAL mouse click** at the element's bounding-box centre
   (`page.mouse.click(x,y)`). `el.click()` frequently does NOT trigger row/card handlers.
4. **Open forms/tabs by button/tab text**, preferring the smallest top-right-most match
   (avoids clicking a wrapper div that merely contains the text).
5. **Read element rects** (`getBoundingClientRect` in CSS px at the capture viewport) for every
   element you'll point a callout at — labels→their input, menu items, buttons, table rows.
   Store them in `.rects.json` so the generator can place crisp markers deterministically.
6. **Below-the-fold fields** need a `scrollIntoView` then a second capture/rects file.
7. **Never trigger destructive actions** to get a screenshot (delete, encrypt a real column,
   submit a form against prod). Capture the screen that SHOWS the control; don't click it.

Capture viewport: 1600×1000 at `deviceScaleFactor:2` (→ 3200×2000 PNG). This is 16:10; see the
full-bleed crop note below.

## Design system (lock every value; adapt per brand)
- Font: **Prompt** (via Google Fonts `@import`; headless Chrome fetches it). Latin/technical
  terms highlighted in accent blue (`.hl`); Thai heading then `(English term)`.
- Colours: navy `#16264f` text, accent `#2563eb`, success `#0f9950`, old/red `#d93a3a`.
- No score numbers, no `✓` glyphs (reads as AI filler). Headings lead with the useful action.
- Footer: small, neutral (set to the deck's product). Page numbers optional.

## Screenshot-slide layout (what the user converged on)
- **Full-bleed**: the screenshot fills the entire slide. No white border, no frame.
- A **compact frosted card** top-left = pill + title ONLY (no step legend) so it never covers
  form fields.
- **Numbered circle markers** placed BESIDE the target element (to its right; flip left if it
  would run off-slide). **No ring/box outlines** — number only, never overlapping content.
- Full-bleed crop math: a 16:10 capture into a 16:9 slide with `object-fit:cover;
  object-position:top` shows the **top 90%** of the image. So marker% = `x/1600`, `y/900`
  (use `VYH=900`, not 1000). Elements you annotate must be within the top 900 logical px.
- "Result" screens with no steps → caption card (pill + title + one-line description), no markers.

## Assembling
`scripts/assemble.py` builds a fresh 16:9 deck (13.333×7.5 in) and adds each PNG full-bleed
(`add_picture(png,0,0,width=W,height=H)`) in an explicit `ORDER` list. When restyling an
existing deck, first extract its embedded images + titles (python-pptx `shape.image.blob`,
`shape.text_frame`) to reuse content, then regenerate every slide as a PNG and assemble fresh.

## QA
Thumbnail-grid the result (`pptx` skill's `scripts/thumbnail.py`) and eyeball: every slide light
mode, markers beside (not on) content, cards not covering key fields, consistent footer, correct
order. Re-render only the slides you change.

## Files
- `scripts/lib.js` — puppeteer helpers (session inject, force-light, click-by-text, rect read).
- `scripts/capture.js` — config-driven live capture (edit the `CFG`/`AUTH`/`ORIGIN` at top).
- `scripts/slides.py` — full-bleed HTML generator: `steps_slide()` (markers) + `caption_slide()`.
- `scripts/render.js` — render `slides/*.html` → PNG at 1280×720 dsf 2.
- `scripts/assemble.py` — ordered PNGs → `.pptx`.
- `example-config.json` — a worked capture config.

These are templates: copy into your work dir and adapt the CONFIG blocks (origin, Chrome path,
auth/theme keys, per-page targets, slide content, order) to the target app.

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [hacka0wi](https://github.com/hacka0wi)
- **Source:** [hacka0wi/SnapDeck](https://github.com/hacka0wi/SnapDeck)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-hacka0wi-snapdeck-snapdeck
- Seller: https://agentstack.voostack.com/s/hacka0wi
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
