Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Read CLAUDE.md in this directory before any work; it is the single source for build, test and ship.
53 changes: 53 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# decklet

A slide engine for agents: the deck is a JSON model, the renderer is the editor, and `create` writes one self-contained `deck.html` a person can drag, retype, present and print. It ships as the `@grunion/decklet` package, a Claude Code plugin and an agent skill (`SKILL.md`).

## Build and run

- Node 22 or newer. Nothing to install for the engine or the CLI.
- Optional browser tooling for `verify`, `pdf` and `import-html`: `npm i -D playwright && npx playwright install chromium`
- The authoring loop, from the repo root:
- `node bin/new.mjs --out model.json --slides 8 --density reading`
- `node bin/validate.mjs model.json --style style.json --strict`
- `node bin/create.mjs --model model.json --style style.json --out deck.html --format slides`
- `node bin/verify.mjs deck.html --strict`
- Rebuild the explainer deck: `npm run build:deck`
- Rebuild the template pack: `npm run build:library`
- Host a deck so any browser can save edits: `node bin/serve.mjs deck.html`
- Regenerate the brand assets: `node brand/build-logos.mjs`

## Test

- Suite: `npm test` (runs `node --test test/**/*.test.mjs`; live browser tests skip when Playwright is absent)
- Live proofs: `npm run test:live`
- Narrow the browser projects for a local run: `DECKLET_PROJECTS=chromium,firefox`
- Brand assets: `node --test brand/build-logos.test.mjs`
- CI gate: `.github/workflows/test.yml`, job `gate`, on every pull request and every push to `main`. It runs `npm i -D playwright && npx playwright install --with-deps chromium webkit firefox`, then `node --test test/**/*.test.mjs`.
- Rules the gate holds (CONTRIBUTING.md):
- Every behaviour change comes with a test.
- The eight text roles stay the only type scale.
- Motion never changes what print, the contact sheet, the PDF or `verify` measure.
- One file, zero network: no webfonts, CDNs or remote images.
- `template.html` and `deck.html` stay in sync.

## Ship

- One change per pull request. The description says what changed, why, and how it was verified, with screenshots for anything visual (CONTRIBUTING.md).
- Open an issue before a large change. A runtime dependency, a build step, a network request or a second file next to `deck.html` is declined on shape.
- `deck.html` and `library.html` are generated under byte-identity gates (`test/kpi.test.mjs`, `test/library.test.mjs`). A change to `template.html`, `bin/create.mjs`, `lib/`, `templates/` or `examples/explainer` rebuilds both with `npm run build:deck` and `npm run build:library` in the same PR, and again on `main` after the merge. Never resolve a conflict in either file by hand: take either side and rebuild.
- A version bump moves `package.json`, `.claude-plugin/plugin.json`, `.claude-plugin/marketplace.json` and a `CHANGELOG.md` heading together (ROADMAP.md, "Release lockstep").
- Deploy: GitHub Pages serves the repo root from `main`, so a merge publishes https://grunion-ai.github.io/decklet/deck.html and https://grunion-ai.github.io/decklet/library.html.
- Verify the deploy: open both URLs and confirm the change is there.
- Vendored archify updates: `docs/archify.md`. The weekly `archify` workflow pushes `archify/<tag>`, and a person opens the PR by hand.

## Pointers

- Authoring contract (model, style, thresholds, anti-patterns): `SKILL.md`. Machine summary and file map: `llms.txt`.
- Where each kind of change goes: `CONTRIBUTING.md`, "Where things go".
- The build loop and the second pass: `docs/building.md`.
- Editor, HUD, persistence, PDF: `docs/editor.md`.
- Charts, connectors, figures, logos, assets, verify, examples: `docs/`.
- Plan and sequencing: `ROADMAP.md`.
- Visual system: `DESIGN.md`.
- Purpose and positioning: `SOUL.md`.
- Security reports: `SECURITY.md`.
52 changes: 52 additions & 0 deletions DESIGN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# decklet design system

decklet's own brand: the mark, the loader, the lockup and the editor HUD. The client style kits a deck is built with live in `examples/styles/` and the STYLE CONTRACT in `SKILL.md`, not here. Source of truth: `brand/README.md` and `brand/build-logos.mjs` (`PALETTE`, `MARKS`), decided 2026-08-23.

## Tokens

The palette is the grunion family.

| Token | Light | Dark | Use |
| --- | --- | --- | --- |
| `blue` | `#2563eb` | | Canonical one-colour mark, favicon, loader, app-icon tile fill, lockup mark on light |
| `sky` | | `#60a5fa` | Lockup mark on dark |
| `ink` | `#0c1b33` | | Lockup wordmark on light, ink mark on light |
| `cream` | | `#e0dcd4` | Lockup wordmark on dark, cream mark and loader on dark, mark on the app-icon tile |
| `white` | `#ffffff` | | Mark on blue |

## Type

- Wordmark: "decklet", lowercase, weight 600, letter-spacing -0.02em.
- Wordmark stack: `Outfit, Inter, system-ui, -apple-system, sans-serif`. No webfont: the lockup SVG carries the stack.

## Marks

The mark is "stack": three 16:9 slides stacked back to front, a deck drawn small. One colour on a 48-unit grid. The under-cards are cut with SVG masks (gap 2.5, favicon 3.5), so every asset is transparent-safe. All files sit in `brand/assets/`.

- `decklet-mark-mono-blue.svg`: the canonical one-colour mark.
- `decklet-mark-ink.svg`, `decklet-mark-white.svg` and `decklet-mark-mono-cream.svg`: on light, on blue and on dark.
- `decklet-tile.svg`: the app icon, a blue squircle (rx 11) carrying a cream mark.
- `decklet-favicon.svg`: 16 to 32 px.
- `decklet-lockup.svg` / `decklet-lockup-dark.svg`: mark plus wordmark, inline, the mark scaled to the wordmark's ascender height.
- `decklet-loader.svg` / `decklet-loader-cream.svg`: the canonical SMIL loader.
- `decklet-loader-light.gif` / `decklet-loader-dark.gif`: the loader for the README and for image proxies that do not run SMIL.

## Components

- Loader: each card advances one slot. The front card drops behind the deck while a new card fades in at the back, so one step leaves the picture as it started and a single 0.9 s step loops without a jump. The under-card cuts carry the same keyframes as the cards that cut them. SMIL only, so it animates inline, in `<img>` and as a CSS background.
- HUD: the control set is the manifest in `docs/editor.md`, and the gate compares it against the template, so a control is never added or dropped without that line changing. Each control is a Lucide shape carrying movingicons.dev motion: it plays once on load, a beat apart, and once per hover, never loops, and reduced motion stills it. Every control's `aria-label` carries the same words as its tooltip, shortcut included (CHANGELOG.md).
- Save button: one Lucide save glyph. Calm when saved, amber with a count when edits are not in the file yet, an amber "Not saving" pill on the tab-only route, a pulse while writing, and a green dot (`#3fb950`) when the file holds every edit (README.md, CHANGELOG.md).
- Touch: under `(pointer: coarse)` HUD and toolbar buttons are 44 px tall and a colour swatch is a 44 px target around a round 20 px dot (`docs/editor.md`).

## Regenerate

- Assets: `node brand/build-logos.mjs`
- Candidate sheet: `node brand/build-logos.mjs docs --candidates`
- Gate: `node --test brand/build-logos.test.mjs`
- PNG previews: `node brand/render-png.mjs in.svg out.png [scale]`. GIFs: `node brand/render-gif.mjs`, which steps the SVG's own SMIL clock, then runs ffmpeg. Both use Playwright Chromium, because ImageMagick drops SVG masks.

## Refusals

- No webfonts, in the lockup or anywhere in a deck.
- No background-coloured gap paint: cuts in the mark are masks.
- No looping HUD motion.
21 changes: 21 additions & 0 deletions SOUL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# decklet soul

## Purpose

decklet turns any content into an editable slide deck, delivered as one self-contained HTML file. The deck is a JSON model, the file is the editor, and a verifier checks the layout before a person sees it (README.md).

## Audience

Agents (Claude Code, Codex, Cursor, any tool-using model) that must turn content into a deck a person will then edit. The person gets a file they can open and change; the agent gets a contract it can validate before a browser is involved (README.md, "Who it is for").

## Positioning

decklet is an open-source alternative to PowerPoint, Keynote, Gamma and the PPTX-generator skills for coding agents. Next to HTML slide skills in the frontend-slides mould it adds in-place editing, an enforced brand type scale, an in-file PDF writer and a layout gate, with zero dependencies, zero network and an MIT license. Pick decklet when an agent drafts the deck and a person finishes it by hand. Pick a PPTX skill when the deliverable has to be a `.pptx`, and Slidev or Marp when the author writes markdown by hand (README.md, "How decklet compares").

## Refusals

- No runtime dependency, build step, network request or second file next to `deck.html`. A change that adds one is declined on shape, whatever its quality (CONTRIBUTING.md).
- No webfonts, CDNs or remote images. Images are data: URIs, and nothing is fetched when a deck opens (README.md, "Guarantees").
- No ninth text role and no per-element font size (CONTRIBUTING.md).
- No version history in the file: that left for weave in 0.9.0 (README.md).
- No deck content in a bug report: no word, image or token from the deck, and nothing is sent until the person presses send (README.md, "Bugs").
Loading