Conversation
…s (BOU-2910) Slides are now React components authored per deck in src/slides/ and referenced from deck.json by filename (import.meta.glob registry in src/slide/registry.tsx). The 30-layout catalog (src/layouts, src/components, src/data/layoutProps.ts) and its ~2,400 lines of layout-only CSS are gone. The studio, dock, rail, grid, notes, Present, speaker view, PDF/JSON download and deck.json persistence are unchanged and render component slides through the same SlideView path. SKILL.md, .bolt/prompt and README now describe the deck.json <-> component contract and the shell; the layout menu and styling rules are dropped. The single design constraint is that every slide must be responsive. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
|
The first pass removed the layout catalog but left the look behind: the dark/blue token theme, the spotlight + grain + vignette atmosphere on every slide, the fluid type atoms (.kicker/.headline/.accent-text), the Inter @import, applyFont defaulting to Inter, and a skill example + seed slide that used all of it. Bolt copied that and produced the same blue-on-black text decks. - base.css: atmosphere and type atoms removed; only reset, slide box, .cols and the ==accent== marker remain. - tokens.css: reduced to the variables the shell reads (--bg, --fg, --accent, fonts, gutters) with neutral defaults. - applyFont imposes nothing when deck.font is unset. - Fallback slides and the seed slide use plain inline styles. - SKILL.md: no-house-style contract, a design section (palette, type, imagery, composition are the agent's to decide per deck), example code without atoms. README and .bolt/prompt updated. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…n by default Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…creens Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…tage-centered alignment Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…; data-viz and legibility rules SlideView measures its own box: up to 1600px wide the slide reflows; above that the whole slide is scaled up proportionally, so ultrawide screens show the 1600px composition larger instead of stretched thin. The scaled box is a CSS container named 'slide', so cqw/cqh and @container queries measure the stage (also fixing thumbnails and the PDF, which never matched vw). Skill: design for 390->1600 and fill the stage at 1600; use cqw/cqh and @container instead of vw/vh and media queries; a data/charts section (the number is the hero, charts at presentation scale, labels never inside data-sized shapes, no dashboard furniture); kicker above headline; a legibility floor to check before finishing. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…as a failure SlideView measures every live slide after its entrance settles and logs a console error naming the slide file and how far its content (text/media elements only) leaves the stage. Bolt surfaces console errors to the agent, so an overflowing slide becomes a failure to fix rather than advice to follow. Thumbnails and export are not measured. Skill: 'nothing out of view — ever', the error to look for, tactics in order (cut copy, split the slide, use the width, shrink media before text), and the shortest-stage budget; the legibility floor references the check. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Width-only scaling shrank the inner stage's height whenever a window got wider at a fixed height (2400x900 became a 1600x600 stage), pushing content that fit at 900 tall out of view. The scale is now min(w/1600, h/900), so the stage is never narrower than 1600 or shorter than 900; extra width is room, not size. Stage constants and the fallback style move to src/slide/stage.ts (Fast Refresh lint). Skill: height is the scarce axis — tie vertical sizes to cqh, not cqw. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…nnot push content out of view Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…not shrink The shell never scales a slide down (upscale is clamped at 1), but the skill's cqw-first sizing led the agent to shrink desktop compositions on phones. SlideView now provides a StageCtx with the stage's width, height, upscale and a narrow flag (< 700px); slide components read it with useStage() from @/slide/stage to restack in JSX. Skill: below ~700px the slide is a different one-column layout, clamp() minimums are real phone reading sizes, and the narrow check must read like a phone page. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… on a narrow stage Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
useStage() now also reports compact (< 1100px, iPad portrait/landscape and small windows) and portrait (taller than wide). Skill: phone, tablet and portrait tiers each get a layout; the canonical text-beside-chart example stacks on narrow or portrait stages; the self-check covers 390x844, 820x1180, 1180x820 and 1600x900. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ames a shell change Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…e user names a shell change" This reverts commit fbb640d.
geotrev
left a comment
There was a problem hiding this comment.
Requesting changes for two regressions in the default experience. In speaker view, the seed slide's text is near-white on white. In the rail, grid and presenter thumbnails, slide text inherits line-height: 0 and collapses. Both happen because the deleted base type rules were never replaced on .slide-view. Separately, the new default accent is invisible in the dark notes and presenter chrome, and CI prettier is red.
Checked on 1bf6c8d8: tsc -b, eslint and vite build pass locally. I rendered studio, Present (3200×1800, 2900×1200, 390×844) and speaker view in headless Chromium. The missing-component fallback works, and Present upscaling and tiers behave as documented.
Not covered by an inline comment:
- Dead layout-era code is left behind:
serializeCodeRoot(.cw-code/.cw-body) incopy/richDom.ts:84–100,DeckFieldKind 'code'indeckPath.ts, the.slide::beforereduced-motion rule (base.css:1382), and stale CountUp / chart comments invisualEditSync.ts. - Possibly intentional, please confirm:
theme-coloris now white while the studio stays dark, andhtml { color-scheme: dark }was removed, so native scrollbars in.note-wyg/.pres-stageare now light. - Not verified: PDF export with fonts loaded through a slide's own
<style>@import. exporter.tsx:150–158 only scans<style>/<link>in the main document.
| p { | ||
| margin: 0; | ||
| line-height: 1.5; |
There was a problem hiding this comment.
Major: speaker view shows a blank current slide, and thumbnail text collapses.
This PR deletes the base h1–h3 / p rules (line-height, color: var(--fg)), and nothing on .slide-view replaces them. Free-form slides now inherit typography from whatever surface hosts them:
.noir-thumb-frame { line-height: 0 }(base.css:397) wraps the rail, the grid and both presenter previews. Wrapped text there renders withline-height: 0. In the rail, the seedwelcome.tsxparagraph hasoffsetHeight: 0and draws over the headline (checked in headless Chromium)..pres { color: var(--ed-text) }is near-white, and the new default--bgis#fff. The presenter's "Current slide" box renders the seedh1asrgb(249,246,249)on white, so the slide looks empty.
This contradicts SKILL.md:347 ("--fg (text color the slide box inherits)").
Fix: reset typography on the slide root, e.g. .slide-view { color: var(--fg); font-family: var(--font-body); line-height: normal; text-align: start; }. That also covers the thumbnail <button>s, which currently pass UA button font, size and colour into the slide.
| --fg: #f2f5f9; | ||
| --fg-muted: #9aa3b2; | ||
| --fg-faint: #5f6a7b; | ||
| --accent: #111111; |
There was a problem hiding this comment.
Major: the default accent #111111 is invisible in the dark chrome.
The notes editor and the presenter sit on --ed-bg (rgb(17,17,20)) and still use --accent / --primary:
.pres-progress-fill: measuredrgb(17,17,17)onrgb(17,17,20)==accent==/{c:accent}text in notes (.accent-text, rich.tsx:29).note-list li::marker, the.note-quoteborder, and the colour-button underline (notes.tsx:587)
Every deck without an explicit accent loses these.
Fix: point the chrome at --ed-brand / --ui-accent, or keep a default accent with real chroma.
| if (!m.count) return; | ||
|
|
||
| const sides = [ | ||
| m.bottom > OUT_OF_VIEW_TOLERANCE && `${Math.round(m.bottom / upscale)}px below`, |
There was a problem hiding this comment.
Major: CI is red. The prettier check fails on this file: lines 249–252 are too long, and there is a double blank line at 129–130.
Fix: run npm run format.
| import Build from '@/deck/Build'; | ||
| import type { SlideComponent } from '@/slide/registry'; | ||
|
|
||
| const Opening: SlideComponent = ({ slide }) => ( |
There was a problem hiding this comment.
Major: the contract example fails lint. const Opening: SlideComponent = ({ slide }) => (…) never uses slide. Copied into src/slides/, it fails npm run lint with @typescript-eslint/no-unused-vars (verified). The agent is told to treat lint as a gate, so the canonical template should pass it.
Fix: use () => ( and mention that { slide } is available when needed.
| useOutOfViewGuard(stageRef, slide, live, upscale); | ||
| const textScale = | ||
| slide.props?.scale === 'xl' ? 1.3 : slide.props?.scale === 'lg' ? 1.15 : 1; | ||
| const zoom = textScale * upscale; |
There was a problem hiding this comment.
Minor: props.scale makes useStage() disagree with cqw / @container.
zoom = textScale * upscale sizes the container box at 100/zoom%. But useStageUpscale reports outer / upscale and ignores textScale.
Verified: with scale: "xl" on a 1280-wide stage, the container is 985px and @container slide (max-width: 1099px) matches. useStage() reports width: 1280, compact: false. CSS and JSX branches therefore pick different tiers, and the documented "never narrower than 1600" box becomes 1231×692.
Fix: derive StageSize from the container's size (outer / zoom), and keep upscale as a separate field.
| ] | ||
| .filter(Boolean) | ||
| .join(', '); | ||
| const w = Math.round(m.box.width / upscale); |
There was a problem hiding this comment.
Minor: the out-of-view message reports wrong sizes in the studio.
The guard divides getBoundingClientRect() by upscale, but the studio canvas also CSS-scales the stage. Verified: a 1280×800 slide in the studio logs "79px below on a 984×615 stage". The real values are about 104px on 1280×800 (Present reports correctly). The agent uses this message to resize content.
Fix: compute the factor as box.width / stage.offsetWidth, and apply the same correction for textScale.
| <SlideScope.Provider value={{ slideId: slide.id, slide }}> | ||
| <div | ||
| ref={stageRef} | ||
| className={'slide-view' + (slideHasImage(slide) ? ' has-image' : '')} |
There was a problem hiding this comment.
Minor: has-image is now a dead class, so text on image backgrounds defaults to dark-on-dark.
The .slide-view.has-image … rules that lightened text were deleted. The shell still paints a dark scrim (dim of at least 0.4), and the default --fg is now #111.
Fix: drop the class and tell SKILL.md readers to set light text on image backgrounds, or add .slide-view.has-image { color: #fff }.
| stack. Three-up grids become two-up. | ||
| - **Portrait** (taller than wide — any iPad held upright, every phone): | ||
| anything side by side stacks; height is plentiful, width is not. | ||
| Restack with `@container slide (max-width: 700px)` / `(max-width: |
There was a problem hiding this comment.
Minor: the tier guidance disagrees with stage.ts.
@container (max-width: 700px)/(max-width: 1100px)are inclusive, whilenarrow/compactare< 700/< 1100.(orientation: portrait)matchesh ≥ w, whileportraitish > w. CSS and JSX disagree at exactly 700 or 1100 wide, and on square stages.- Line 66 lists iPad landscape 1180 under the
< 1100tier, butcompactis false there. - Line 110 recommends a
900pxfallback, which is not a tier, and the.colsutility it suggests uses a window@mediaquery that line 75 calls "wrong here". - Line 49: the code gives a 2008×900 stage for 2900×1300, not 2013.
Fix: document max-width: 699.98px / 1099.98px, or change the hook to <=. Fix the examples to match.
| `--primary` (the `==accent==` marker; deck-level `accent` overrides them), | ||
| `--font-head` / `--font-body` (deck-level `font` overrides them), and | ||
| `--gutter` / `--gutter-y` (what `<Slide>` pads with). Their defaults are | ||
| neutral on purpose. Set them to the deck's design, or ignore them and |
There was a problem hiding this comment.
Minor: the docs contradict each other on src/styles/ and on sizing.
- Lines 32–34 list
src/styles/as shell ("Leave it alone"). Line 351 says to set the tokens to the deck's design, and.bolt/promptsays "theme insrc/styles/tokens.css". - Lines 130/201 recommend
5–8cqwheadlines and8–14cqwfigures, while lines 135–138 say vertical sizes must not followcqw. On a 3200×900 stage (upscale 1),14cqwis 448px.
Fix: carve out tokens.css explicitly, and cap the cqw sizes, e.g. min(14cqw, 30cqh).
| @@ -1,5 +1,3 @@ | |||
| @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap'); | |||
There was a problem hiding this comment.
Minor: Inter is no longer loaded, but it is still referenced.
Removing this @import affects two places:
--font-ui: 'Inter', …(chrome-tokens.css) now falls back to system-ui across the studio chrome.- The
interpairing in fonts.ts has noimport(it is the "bundled default"), so"font": "inter"silently renders the system font.
Also, nothing in slide content uses --font-head any more, only notes headings. A deck-level font therefore no longer changes slide headings, which contradicts SKILL.md:349.
Fix: load Inter for the chrome and pairing, or drop the inter pairing. Then document that slides opt in with var(--font-head).
Closes BOU-2910
What
bolt-slides:src/layouts/,src/components/,src/data/layoutProps.ts, and ~2,400 lines of layout-only CSS inbase.css.src/slides/, referenced fromdeck.jsonby filename. A newsrc/slide/registry.tsxglobs that folder;SlideViewrenders through it, so the rail, grid, Present, speaker view and PDF export keep working unchanged. A missing file renders a clear fallback slide instead of crashing.deck.jsonships a single seed slide (welcome.tsx) that the agent replaces.SKILL.md,.bolt/promptandREADME.mdrewritten: shell description, the deck.json ↔ component contract, bootstrap, optional helpers (Slide,Reveal,Build, tokens, in-place text edit). The layout menu, entry conditions, arc and typography rules are gone. The one design rule left is every slide must be responsive.Unchanged
Studio (side panel, grid, reorder / duplicate / delete, notes), dock, Present, speaker view, PDF / JSON download, deck.json persistence, theming tokens.
Verification
npm run typecheck,npm run lint,npm run buildpass.origin/mainrenders identically at that size, so it is pre-existing engine behavior.Note
deck.json'slayoutfield keeps its name (it now means the component filename) to avoid touching the store, export and studio paths that read it.🤖 Generated with Claude Code