feat: PresentationDeck engine + deck primitives with a behavioral eval suite#2
Merged
Conversation
theclaymethod
force-pushed
the
feat/presentation-deck
branch
from
July 15, 2026 18:38
75cf063 to
dc7c886
Compare
A second deck engine for presented (not scrolled) decks, generalized from a production deck: fixed 1920x1080 stage scaled to fit (ResizeObserver + letterbox), collapsible slide rail with dot-column collapsed state, keyboard nav, 80px edge click zones, and drill-down primitives (DrillCard/DrillChip/ DrillSheet with a click-anywhere-to-close guard, LayerExplorer, Ladder/ FanoutDiagram, PullQuote, Metric/StatRow, Stepper, CodePanel, icons, shine). Everything consumes --ve-* preset tokens (no color or font literals ship in the module); slide tones reuse the data-ve-tone -> --ve-slide-* mapping. Pure logic (fitStage math, dismiss guard, tint/solidTint) lives in presentation-core.ts so node:test and the eval harness import it directly. Re-exported through components.tsx; the roster-sync guard now also parses PascalCase re-exports. Demo deck at examples/visual-explainer-mdx/presentation-deck.tsx is wired into ve:check. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…deck evals/run-presentation.mjs (npm run ve:eval-presentation) is the engine's behavioral contract, run as a documented sibling of evals/run.mjs: it exports the demo deck through the standard ve:export path and replays headlessly - interaction: click-anywhere-to-close guard matrix (button/a/input/select/ textarea/[data-interactive] stay open; passive prose closes; Escape and the X always close), keyboard-nav matrix with counter assertions, drill CTA contract (every trigger opens via click/Enter/Space; primary solid fill vs secondary outline computed styles), LayerExplorer selection, reduced motion - geometry: stage transform equals fitStage() across four viewports, letterboxing on mismatched ratios, rail collapse/expand widths - tokens: a second preset changes computed surface/CTA/font values, and an allowlist-based scan asserts the shipped module contains NO color or font literals at all (every visual value must arrive via a --ve-* token) Each eval was verified to fail by breaking the behavior (guard return, scale min->max, a hardcoded CTA color) and reverting. Unit tests cover the pure logic (scale-to-fit math, dismiss guard via linkedom, tint/solidTint). Both wired into CI (npm test in static job, ve:eval-presentation in evals job). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The bundled Tailwind CSS always carries SlideDeck's scroll-snap utilities, so the slides-profile heuristic misclassified every PresentationDeck artifact and then failed deck-scroll-snap-axis against a deck that never scrolls. Artifacts carrying data-ve-presentation now verify as pages (both in lib/profile.mjs and the browser-dev tool's local detector). The demo artifact verifies clean: errors=0. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
docs/presentation-deck.md explains when to reach for each deck engine, the primitive inventory, and the eval-pinned behavioral contract. CONTRIBUTING gains a section requiring npm test + ve:eval-presentation for engine changes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…fonts
Long Metric values wrapped under mono-display presets ("1920×1080" broke
into two lines, reading as a different number). The value now renders
white-space: nowrap with a character-count size clamp (values longer than 8
chars shrink proportionally) so it fits at any preset's glyph width. Added a
metric-value-no-wrap eval that measures every [data-ve-metric-value] on both
preset exports — terminal's fully monospace display font is the worst case —
and fails on wrap or cell overflow (verified against the pre-fix behavior).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… CTA ink Three merge-blockers, each pinned by a new falsifiable eval: - Keyboard guard: modifier chords (meta/ctrl/alt) are never intercepted, and focus inside input/textarea/select/[contenteditable] now owns EVERY key (arrows move the caret, Space types a space) instead of only Space/Enter. Eval: keyboard-guard-typing-and-modifiers (verified failing pre-fix: the old handler navigated on Meta+ArrowRight and swallowed typed spaces). - Sheet-gated navigation: the 80px edge click zones (z-50) sit above an open drill sheet (z-40); both they and the nav keys are now gated while a sheet is open, so a click or keystroke can never blow past the sheet and change slides. Escape closes the sheet first, then navigation resumes. Eval: nav-gated-while-sheet-open. - Light-tone CTA ink: global.css remaps --ve-accent to the ink color on light-tone slides, so a primary chip filled with it rendered ink-on-ink (measured 1.06:1 contrast). Light tone now flips --ve-pres-cta-ink to the slide surface exactly like the accent tone. Demo slide 3 (light) gains a primary DrillChip + tone-remapping sheet; eval light-tone-primary-cta-contrast asserts >= 3:1 computed contrast. Also folded after the rebase onto 0.8.0 main: registry-open VisualPreset kept alongside the presentation re-exports, combined npm test script, deduped CI test step, CHANGELOG entries folded into 0.8.0. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
theclaymethod
force-pushed
the
feat/presentation-deck
branch
from
July 15, 2026 19:43
a06979f to
591877f
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A second deck engine for presented (not scrolled) decks, generalized from a production deck built with this pipeline — plus an eval suite that IS its behavioral contract.
PresentationDeck/PresentationSlide(visual-explainer-mdx/presentation.tsx): fixed 1920×1080 stage scaled to fit via ResizeObserver (min(w/1920, h/1080), letterboxed on the new--ve-deck-letterboxtoken), collapsible slide rail (auto-collapse → dot column, hover expand, active indicator), keyboard nav (arrows/Space/PageUp/PageDown/Home/End), 80px edge click zones, mono slide counter,cubic-bezier(0.22,1,0.36,1)transitions.DrillCard(corner-anchored expansion over neighbors viatransform-origin),DrillChip(CTA discipline: primary = solid accent fill, secondary = outline),DrillSheet(Escape/X + click-anywhere-to-close guarded byclosest('button, a, input, select, textarea, [data-interactive], [data-drill-target]')),LayerExplorer.LadderDiagram/FanoutDiagram(grid paper with opaque solid-over-grid fills — the CSS equivalent ofsolidTint()),PullQuote,Metric/StatRow,HairlineList,Stepper,CodePanel,MonoLabel/DisplayText,IconChip+ geometric icons,ShineOverlay/trackShine, hover-lift CSS.--ve-*tokens; slide tones reuseSlide'sdata-ve-tone→--ve-slide-*mapping, so all existing presets skin the deck untouched (independent of the design-system-registry PR).prefers-reduced-motioncollapses all deck motion.SlideDeck/Slideexports are untouched; the new components re-export throughvisual-explainer-mdx/components.tsxand the roster-sync guard now parses re-exports.The eval suite is the spec
evals/run-presentation.mjs(npm run ve:eval-presentation, documented sibling ofevals/run.mjs, wired into the CI evals job) exports the demo through the standardve:exportpath and replays the contract headlessly — 18 evals:fitStage()at 1440×900 / 1920×1080 / 1024×768 / 800×1000, letterbox on mismatched ratio, rail 260↔44px collapse/hover-expand + rail navigation, Metric no-wrap/no-overflow under the widest display font--ve-*token. The only allowlisted literals are two documented neutralvar(..., fallback)values and one docstring exampleFalsification check: each eval class was verified to fail by sabotaging the behavior and reverting — guard
return true→ dismiss-matrix failed;fitStagemin→max → letterbox failed; a hardcoded CTA color → CTA-style, preset-reskin, and literal-scan evals failed.Unit tests (
npm test, in CI): scale-to-fit math, dismiss guard via linkedom,tint/solidTint(21 tests incl. existing diagram-layout suite).Verifier
One scoped fix: the bundled Tailwind CSS always contains SlideDeck's scroll-snap utilities, so
detectProfileclassified every fixed-stage artifact asslidesand then faileddeck-scroll-snap-axisagainst a deck that never scrolls.data-ve-presentationartifacts now verify as pages.ve-verifyon the demo artifact: profile=page, errors=0 (1 warn: sub-44px hit targets, inherent to a scaled presenter stage).ve:eval(all 130+ seeded-violation fixtures) stays green with the detection change.Demo
examples/visual-explainer-mdx/presentation-deck.tsx— 4 slides exercising engine + primitives, wired intove:check. The slide-2 drill sheet doubles as the interaction fixture (one of every guarded element class).preset="terminal"— asserted by thepreset-reskinevalTest plan
npm test— 21/21npm run ve:check— roster sync (incl. re-exports), all 15 example exports + SSR content probes, integrity fixturesnpm run ve:eval— all seeded violations + clean fixtures pass with the profile-detection changenpm run ve:eval-presentation— 17/17; each eval demonstrated falsifiablenpm run check:manifestsve-verifyon the exported demo: errors=0Docs
docs/presentation-deck.md(PresentationDeck vs SlideDeck), README, CHANGELOG (Unreleased), CONTRIBUTING (engine changes must run both suites), SKILL.md component roster.🤖 Generated with Claude Code