diff --git a/bolt-slides/.bolt/skills/slides/SKILL.md b/bolt-slides/.bolt/skills/slides/SKILL.md
index 29a0328..99b6e5b 100644
--- a/bolt-slides/.bolt/skills/slides/SKILL.md
+++ b/bolt-slides/.bolt/skills/slides/SKILL.md
@@ -92,6 +92,11 @@ Dark vs light: set `html { color-scheme }` in base.css and pick `--bg`/`--fg`
accordingly. Set fonts in `--font-head`/`--font-body` and the `@import` at the top
of `base.css`. Derive from the brand when given.
+**Tab title + icon — always, unprompted.** Shared decks show the browser tab, so
+never leave the `index.html` placeholders: set `
` to the deck's real title
+(e.g. "Acme — Series A") and swap the emoji in the favicon `` to one that
+fits the topic. Do this for every deck without being asked.
+
---
## Step 3 — Author slides (each child of `` is one slide)
@@ -288,12 +293,14 @@ trigger or that it exists — just deliver the demo.
- [ ] The engine + chrome in `src/deck/` are **left untouched**; the
dock + thumbnail rail appear, arrow keys advance AND step back through builds,
- fullscreen / overview work, annotation (D) has full tools and
+ fullscreen / sidebar (S) / grid view (G) work, annotation (A) has full tools and
persists per slide, presenter (P) opens a synced new tab, `H` hides the UI, and
the URL hash tracks the slide.
- [ ] The deck is **authored, not reskinned** — topic, structure, copy, names are the
user's, with no starter leftovers (no "Title"/"Northwind").
- [ ] If a brand/URL was given, `--primary`, fonts, and logo come from that brand.
+- [ ] `index.html` has the deck's real `` and a topic-matched favicon emoji —
+ no `Replace — your deck title` placeholder left behind.
- [ ] Only the `:root` block was edited for the theme; editing `--primary` recolors
everything incl. the dock.
- [ ] Slides compose like web sections (full-bleed/asymmetric/bento/split), not
diff --git a/bolt-slides/README.md b/bolt-slides/README.md
index 3d42c45..14ff16d 100644
--- a/bolt-slides/README.md
+++ b/bolt-slides/README.md
@@ -2,7 +2,7 @@
A Bolt skill that builds a premium, **responsive React presentation deck** — classic
paged slides you present one at a time, with a Slidev-style floating dock + thumbnail
-rail, click-builds, annotation, and presenter mode — but each slide is a
+rail, grid overview, click-builds, annotation, and presenter mode — but each slide is a
responsive web layout (no fixed canvas, no clipping) built from a rich component
library.
diff --git a/bolt-slides/index.html b/bolt-slides/index.html
index 56383bc..fb4074a 100644
--- a/bolt-slides/index.html
+++ b/bolt-slides/index.html
@@ -3,7 +3,12 @@
+
Replace — your deck title
+
diff --git a/bolt-slides/src/deck/Annotator.tsx b/bolt-slides/src/deck/Annotator.tsx
index 0e4eb09..c37e1e3 100644
--- a/bolt-slides/src/deck/Annotator.tsx
+++ b/bolt-slides/src/deck/Annotator.tsx
@@ -370,6 +370,39 @@ export default function Annotator({
redraw();
}
+ // drag-to-scroll for the bar when it overflows (phones scroll natively by
+ // touch; this covers mouse users). A 4px threshold keeps clicks working,
+ // and a capture-phase click handler swallows the click after a real drag.
+ const barRef = useRef(null);
+ const barDrag = useRef({ down: false, moved: false, x: 0, left: 0 });
+ function barDown(e: React.PointerEvent) {
+ if (e.pointerType !== 'mouse' || !barRef.current) return;
+ barDrag.current = {
+ down: true,
+ moved: false,
+ x: e.clientX,
+ left: barRef.current.scrollLeft,
+ };
+ }
+ function barMove(e: React.PointerEvent) {
+ const d = barDrag.current;
+ if (!d.down || !barRef.current) return;
+ const dx = e.clientX - d.x;
+ if (!d.moved && Math.abs(dx) < 4) return;
+ d.moved = true;
+ barRef.current.scrollLeft = d.left - dx;
+ }
+ function barUp() {
+ barDrag.current.down = false;
+ }
+ function barClickCapture(e: React.MouseEvent) {
+ if (barDrag.current.moved) {
+ e.preventDefault();
+ e.stopPropagation();
+ barDrag.current.moved = false;
+ }
+ }
+
return (
<>
{active && (
-