Skip to content

v0.2.0: markdown decks, presenter view, print mode

Latest

Choose a tag to compare

@hyperb1iss hyperb1iss released this 01 Sep 22:42
· 2 commits to main since this release
e8d07fd

Release Notes v0.2.0

Released: 2026-09-01

Prezzer grows from a deck renderer into a full presentation workflow: author slides in Markdown, run a real presenter console in a second window, export PDFs straight from the browser, and iterate with a proper dev server. The whole toolchain moves to Bun 1.4 with workspace dependency catalogs, and the deck-authoring skill gets a curated reference layer so coding agents can build decks without guessing.

🌟 Highlights

✨ Markdown decks

Author text-heavy slides as .md files and import them directly: import slides from './slides.md' feeds straight into <Deck slides={slides} />. The prezzer/bun-plugin loader parses at build time, renders HTML with Bun.markdown.html, and emits a module that calls markdownSlides() from prezzer/markdown. Slides split on ---, beats split on <!-- beat -->, and frontmatter carries id, title, act, transition, deep, badge, and notes. Dividers and beat markers inside fenced code blocks stay content, never boundaries. Markdown and JSX slides mix freely in the same array.

🎭 Presenter view

Press p to open the same artifact in a second window with ?presenter=1. The two windows sync over postMessage across the window.open pair rather than BroadcastChannel, so it works from file:// with no server. The console shows speaker notes, the next slide title, live previews of current and next slides, a click-to-reset timer, wall clock, and a sync indicator. Every presenter keypress dispatches a remote command back to the audience window, so the presenter is a true remote control and the deck window stays the source of truth.

🖨️ Print mode

Add ?print to the deck URL and the browser becomes the PDF exporter. Deck detects the query parameter and renders one 16:9 page per slide, each fully revealed at its final beat, with @page rules sized to the 1920×1080 canvas and zero margins. Entrance animations skip globally so nothing prints mid-transition. No import or separate build target: it is the same single HTML file.

prezzer dev

A real dev server with hot reload, built on Bun 1.4 directory routes. Defaults to http://127.0.0.1:1609 (loopback only), honors BUN_PORT / PORT / NODE_PORT, and walks up to 10 successive ports when the default is busy. Use --port and --host to override; an explicit --port fails fast instead of drifting. public/ is served in dev with ETag, 304, and Range support, plus symlink and traversal guards.

🤖 Agent-ready deck authoring

skills/prezzer/SKILL.md now sits on top of eight curated reference documents: api.md, authoring.md, chrome.md, markdown.md, motion.md, theming.md, verification.md, and widgets.md. The README gained an agent fast path, and AGENTS.md (symlinked as CLAUDE.md) documents the invariants that break silently, like the per-package bunfig.toml mirror every workspace member with tests needs.

✨ Engine

  • Help overlay: ? opens an aria-modal dialog documenting the full key vocabulary: space//pgdn to advance, /pgup to step back, shift to skip whole slides, 1 to 9 to jump, home/end for first/last, g grid, n notes, f fullscreen, d deny mode, a autoplay, p presenter, esc to close.
  • Exclusive modals: useKeyboardShortcuts takes a modalOpen flag. While an overlay owns the screen, deck keys are swallowed so a stray space cannot advance the deck behind a dialog. Only esc, g, and ? pass through, so overlays can close or swap.
  • Beat audit: BeatAudit plus the useBeatAudit hook wired into Beat warn when a mounted <Beat at={n}> exceeds the slide's declared beats, naming the slide and the count it should declare. Catches reveals that can never fire.
  • Grid overview keyboard navigation: arrow keys move between cards with row math derived from the live auto-fit layout, digit typeahead builds a slide number with a visible hint, enter jumps, g or esc closes. Cards carry aria-current="page" and the dialog has a screen-reader-only heading.
  • StaticDeckProvider: a frozen deck context with no-op navigation, exported from prezzer alongside DeckContext and DeckContextValue. It backs presenter previews and print pages, and is the composition surface for shells that source state outside DeckProvider.
  • hashSync prop: DeckProvider accepts hashSync={false} to stop mirroring position into location.hash when embedding a deck in a host page.
  • Interactive element passthrough: links, buttons, form controls, media, and anything marked data-prezzer-interactive keep their own keyboard events instead of losing them to deck navigation.
  • History-safe deep links: position mirrors into location.hash via history.replaceState, so presenting a long deck no longer buries the Back button under one history entry per beat, and a hand-typed hash that clamps rewrites to the position actually shown. Touch navigation ignores pinch gestures and pauses under open overlays, and fullscreen state reads through useSyncExternalStore.

🎨 Theme and chrome

  • withAlpha(color, alpha): new export from prezzer/theme that derives translucent colors with color-mix(in srgb, ...). The old approach appended hex suffixes like ${color}88, which silently broke on anything that was not a 6-digit hex. Chrome overlays now tint from the active theme instead of hardcoded values.
  • Display fonts: the scaffold template actually loads the SilkCircuit display faces now, and the demo deck self-hosts Clash Display, Satoshi, and Geist Mono so its offline claim holds.
  • SlideDef.badge typed as RolloutStatus | (string & {}), giving autocomplete for GA, IN FLIGHT, COMING SOON, DEV ONLY, and NOT ROLLED OUT while still accepting any string.

🔧 CLI and build

  • Trustworthy asset inlining: the bake matches public/ assets against literal paths in the output (including URL-encoded forms), replaces longest-token-first so /a.png cannot corrupt /a.png.license, and consumes query strings rather than appending them to the data URI.
  • Honest warnings: the build warns when a public/ asset never appears literally in the output ("runtime-built paths break offline") and when the artifact still references remote stylesheets, scripts, or fonts. Hidden files and bundler-resolved imports are excluded, so the warning means something.
  • Build output: completion now reports the artifact path, size, duration, and whether it is truly offline: ✓ dist/index.html · 45.2 KB · 1.23s · one file, works offline. Colors are gated on Bun.enableANSIColors so piped output stays clean.
  • --no-minify on build for readable output while diagnosing a bake; --outdir still defaults to dist with guards against escaping the project or clobbering the deck entry.
  • prezzer --version (also -v and version) prints the engine version.

📝 Examples and docs

  • Demo deck: examples/demo is Prezzer presenting itself, deployed to GitHub Pages by the new .github/workflows/pages.yml. Fonts are self-hosted under examples/demo/public/fonts.
  • README rebuilt around the feature set, quick start, and the agent fast path, with screenshots of the hello deck in docs/images/.
  • Several passes of adversarial and cross-model verification corrected claims in the README, the skill, and the audit docs so the documentation matches the shipped behavior, including hash indexing and act grouping.

👷 Toolchain

  • Bun 1.4 is now the floor (engines, packageManager, and every CI workflow pinned to 1.4.0).
  • Dependency catalogs: the root package.json declares a catalog block and every workspace member references "catalog:", so React, Motion, Tailwind, and TypeScript versions move in one place.
  • Isolated linker: bunfig.toml pins [install] linker = "isolated" for strict dependency isolation and faster warm installs.
  • Motion 13 with happy-dom 20 in tests. test/setup.ts sets MotionGlobalConfig.skipAnimations = true, cutting the suite from roughly 20s to under a second and removing flaky AbortError rejections.
  • New tests cover the dev CLI, the markdown loader, print rendering, presenter sync, and publish manifests. .editorconfig, .vscode/extensions.json, and aligned Biome and TypeScript configs round out the contributor setup.

🔥 Breaking changes

  • Bun 1.4 required. Anything below 1.4.0 will not install or build. Update local toolchains and CI images.
  • Five motion exports removed from prezzer: slideTransitions, slideVariants, typewriter, toolBurst, and toolStaggerContainer. These were fossils from the deck Prezzer was extracted from and had no replacements. Pick transitions per slide via the transition field on SlideDef, and build custom variants in your own deck.
  • Hex-suffix alpha is gone from theme helpers. If you copied the ${color}40 pattern out of engine internals, switch to withAlpha(color, 0.25).

📦 Upgrade notes

  1. Install Bun 1.4 or later, then reinstall: bun install. The isolated linker changes node_modules layout, so remove it first if the install behaves oddly.
  2. Search your deck for slideTransitions, slideVariants, typewriter, toolBurst, and toolStaggerContainer and replace them before upgrading.
  3. To author in Markdown, add "prezzer/bun-plugin" to plugins in your deck's bunfig.toml and declare *.md in assets.d.ts as a default-exported SlideDef[].
  4. If you have a workspace package with tests, mirror the two-line bunfig.toml preload of test/setup.ts or DOM access will fail.
  5. prezzer dev binds to 127.0.0.1 by default. Pass --host 0.0.0.0 if you were relying on network access from another device.
  6. Point coding agents at skills/prezzer/SKILL.md; it links the reference layer covering the API, authoring, chrome, markdown, motion, theming, widgets, and verification.