diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..580f641 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1 @@ +Read CLAUDE.md in this directory before any work; it is the single source for build, test and ship. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..b1f16bf --- /dev/null +++ b/CLAUDE.md @@ -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/`, 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`. diff --git a/DESIGN.md b/DESIGN.md new file mode 100644 index 0000000..2b7fb3b --- /dev/null +++ b/DESIGN.md @@ -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 `` 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. diff --git a/SOUL.md b/SOUL.md new file mode 100644 index 0000000..d1d215b --- /dev/null +++ b/SOUL.md @@ -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").