From 2ba424367dc4eb176350a09ddfb66683ca8dd753 Mon Sep 17 00:00:00 2001 From: Henry Lach Date: Mon, 18 May 2026 19:51:58 -0400 Subject: [PATCH 1/3] feat(overview): sticky eyebrow + bigger green nav + keyboard & swipe nav Three layered improvements to the slide-deck navigation UX, all landing in one PR since they reinforce each other. 1. Sticky eyebrow header .eyebrow now uses position: sticky; top: 0 so the title, wordmark, and prev/index/next controls dock to the top of the viewport on both desktop and mobile once the page is scrolled. Sticky (vs fixed) keeps it in normal flow until it hits the viewport top, so there's no body padding-top compensation and no content jumping. Background fills with --bg, plus a 1px border-bottom for separation. 2. Larger, green nav controls .page-nav font-size doubles (calc(var(--fs-lg) * 2)) so the prev / index / next glyphs read as primary actions instead of subtle hints. Color switches from --text-faint to --green (matching the eyebrow title color), with hover bumping to --text and a tiny translateY for tactile feedback. Each control now has a 44x44 minimum hit area via min-width / min-height / padding, satisfying touch-target guidance on phones. Disabled state stays gray + low-opacity so first-page-prev and last-page-next still read as inactive. 3. Keyboard + swipe navigation (nav.js) New shared script, loaded by every page: keyboard : ArrowLeft / ArrowRight synthesize a click on the existing prev / next anchors. Ignores modifier-key shortcuts and editable targets so it never hijacks normal browser shortcuts or form input. touch : horizontal swipes (>= 70px X movement, and at least 2x more X than Y) fire prev / next. UNLESS the swipe started inside a horizontally scrollable container (e.g. page-09 git-graph, page-08 wave cards), in which case the inner pan keeps working. Walked via scrollWidth > clientWidth check up the DOM ancestor chain. The script is loaded by an unconditional diff --git a/docs/taskplane-overview/02-light-factory-vs-dark.html b/docs/taskplane-overview/02-light-factory-vs-dark.html index 0ac64a19..d7505b1e 100644 --- a/docs/taskplane-overview/02-light-factory-vs-dark.html +++ b/docs/taskplane-overview/02-light-factory-vs-dark.html @@ -146,5 +146,6 @@

Light factory vs dark factory

autonomy is fine — inspectable autonomy is the goal + diff --git a/docs/taskplane-overview/03-agent-quartet.html b/docs/taskplane-overview/03-agent-quartet.html index e28e262d..105c243e 100644 --- a/docs/taskplane-overview/03-agent-quartet.html +++ b/docs/taskplane-overview/03-agent-quartet.html @@ -201,5 +201,6 @@

The agent quartet

supervisor spawns worker per lane worker calls reviewer at step boundaries wave completes merger combines lanes next wave + diff --git a/docs/taskplane-overview/04-task-packet-anatomy.html b/docs/taskplane-overview/04-task-packet-anatomy.html index 245b3cec..02a63d48 100644 --- a/docs/taskplane-overview/04-task-packet-anatomy.html +++ b/docs/taskplane-overview/04-task-packet-anatomy.html @@ -198,5 +198,6 @@

Anatomy of a Taskplane task packet

+ diff --git a/docs/taskplane-overview/05-determinism-spectrum.html b/docs/taskplane-overview/05-determinism-spectrum.html index 6fb1e596..55075578 100644 --- a/docs/taskplane-overview/05-determinism-spectrum.html +++ b/docs/taskplane-overview/05-determinism-spectrum.html @@ -194,5 +194,6 @@

Where Taskplane sits on the determinism spectrum

only the contents of the model's tokens differ. + diff --git a/docs/taskplane-overview/06-cross-model-review.html b/docs/taskplane-overview/06-cross-model-review.html index a275854f..f0ebc274 100644 --- a/docs/taskplane-overview/06-cross-model-review.html +++ b/docs/taskplane-overview/06-cross-model-review.html @@ -281,5 +281,6 @@

Cross-model reviews

+ diff --git a/docs/taskplane-overview/07-mailbox-protocol.html b/docs/taskplane-overview/07-mailbox-protocol.html index 1d82c2ed..1db4b9f0 100644 --- a/docs/taskplane-overview/07-mailbox-protocol.html +++ b/docs/taskplane-overview/07-mailbox-protocol.html @@ -224,5 +224,6 @@

The file-based mailbox

+ diff --git a/docs/taskplane-overview/08-waves-lanes-worktrees.html b/docs/taskplane-overview/08-waves-lanes-worktrees.html index a59067f8..bdfa67ca 100644 --- a/docs/taskplane-overview/08-waves-lanes-worktrees.html +++ b/docs/taskplane-overview/08-waves-lanes-worktrees.html @@ -318,5 +318,6 @@

Batch, waves, lanes, worktrees, tasks

+ diff --git a/docs/taskplane-overview/09-branching-lifecycle.html b/docs/taskplane-overview/09-branching-lifecycle.html index 47d531a2..208b278e 100644 --- a/docs/taskplane-overview/09-branching-lifecycle.html +++ b/docs/taskplane-overview/09-branching-lifecycle.html @@ -276,5 +276,6 @@

How Taskplane uses branches

your working branch is sacred — never touched until /orch-integrate + diff --git a/docs/taskplane-overview/10-semantic-merge.html b/docs/taskplane-overview/10-semantic-merge.html index e376e404..b21555d4 100644 --- a/docs/taskplane-overview/10-semantic-merge.html +++ b/docs/taskplane-overview/10-semantic-merge.html @@ -220,5 +220,6 @@

Semantic merge vs git merge

merge health monitor polls every 2 min · stale at 10 · stuck at 20 · emits events, never kills autonomously + diff --git a/docs/taskplane-overview/11-polyrepo-segments.html b/docs/taskplane-overview/11-polyrepo-segments.html index d82b82f5..350b1826 100644 --- a/docs/taskplane-overview/11-polyrepo-segments.html +++ b/docs/taskplane-overview/11-polyrepo-segments.html @@ -295,5 +295,6 @@

Polyrepo: tasks decompose into segments

+ diff --git a/docs/taskplane-overview/12-dashboard-visibility.html b/docs/taskplane-overview/12-dashboard-visibility.html index 954b99ac..e177132f 100644 --- a/docs/taskplane-overview/12-dashboard-visibility.html +++ b/docs/taskplane-overview/12-dashboard-visibility.html @@ -257,5 +257,6 @@

Why a web dashboard, not a CLI

one tab. all the truth. no babysitting required. + diff --git a/docs/taskplane-overview/13-why-pi.html b/docs/taskplane-overview/13-why-pi.html index bab6bba5..896dc206 100644 --- a/docs/taskplane-overview/13-why-pi.html +++ b/docs/taskplane-overview/13-why-pi.html @@ -145,5 +145,6 @@

Why pi?

extensible  +  model-agnostic  +  open  ·  the right foundation for what Taskplane needed + diff --git a/docs/taskplane-overview/14-pi-capabilities.html b/docs/taskplane-overview/14-pi-capabilities.html index 51ef0576..3f58a8ed 100644 --- a/docs/taskplane-overview/14-pi-capabilities.html +++ b/docs/taskplane-overview/14-pi-capabilities.html @@ -158,5 +158,6 @@

What pi actually gives you

Every primitive on this page maps to something concrete in the orchestration system. Skills give you the task-creation entry point. Custom tools give you reviews. RPC steering gives you the mailbox. Subprocess agents give you parallel lanes. Composable prompts give you the supervisor / worker / reviewer / merger quartet without forking a thing. + diff --git a/docs/taskplane-overview/15-how-to-get-started.html b/docs/taskplane-overview/15-how-to-get-started.html index 10764cdc..84b4037f 100644 --- a/docs/taskplane-overview/15-how-to-get-started.html +++ b/docs/taskplane-overview/15-how-to-get-started.html @@ -217,5 +217,6 @@

Getting started: install and test

+ diff --git a/docs/taskplane-overview/16-real-work-playbook.html b/docs/taskplane-overview/16-real-work-playbook.html index 7922c833..2159efa3 100644 --- a/docs/taskplane-overview/16-real-work-playbook.html +++ b/docs/taskplane-overview/16-real-work-playbook.html @@ -291,5 +291,6 @@

How to get started on real work

A clear, well-scoped PROMPT.md is the difference between an agent that delivers and one that drifts. Time spent here compounds across every lane in every wave. + diff --git a/docs/taskplane-overview/17-sage-companion.html b/docs/taskplane-overview/17-sage-companion.html index a1d760d9..82df9269 100644 --- a/docs/taskplane-overview/17-sage-companion.html +++ b/docs/taskplane-overview/17-sage-companion.html @@ -297,5 +297,6 @@

Sage — the post-batch quality gate

Taskplane runs the batch.  Sage reviews it.  ·  separate extensions, one workflow + diff --git a/docs/taskplane-overview/index.html b/docs/taskplane-overview/index.html index 1534992b..d13d7bed 100644 --- a/docs/taskplane-overview/index.html +++ b/docs/taskplane-overview/index.html @@ -216,5 +216,6 @@

Table of Contents

+ diff --git a/docs/taskplane-overview/nav.js b/docs/taskplane-overview/nav.js new file mode 100644 index 00000000..68acd496 --- /dev/null +++ b/docs/taskplane-overview/nav.js @@ -0,0 +1,84 @@ +// Taskplane Overview · page-deck navigation +// ---------------------------------------------------------------------------- +// Two input modes layered on the existing prev/index/next links inside +// .page-nav, so they stay the single source of navigation truth: +// +// * Desktop : ArrowLeft / ArrowRight on the keyboard fire the prev/next links. +// * Touch : horizontal swipes fire the prev/next links — UNLESS the swipe +// started inside a horizontally scrollable container (e.g. the +// page-09 git-graph card or the page-08 wave cards), in which +// case the inner scroll takes priority. +// +// The script is a no-op on the index page (no .page-nav element). +// ---------------------------------------------------------------------------- + +(function () { + 'use strict'; + + function navLink(label) { + return document.querySelector('.page-nav a[aria-label="' + label + '"]'); + } + + // --- Keyboard ---------------------------------------------------------- + document.addEventListener('keydown', function (e) { + // Don't hijack arrows when the user is typing somewhere editable. + var tag = (e.target.tagName || '').toLowerCase(); + if (tag === 'input' || tag === 'textarea' || e.target.isContentEditable) { + return; + } + // Ignore when modifier keys are held — those are likely browser shortcuts. + if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) return; + + var link = null; + if (e.key === 'ArrowLeft') link = navLink('Previous'); + if (e.key === 'ArrowRight') link = navLink('Next'); + if (link) { + e.preventDefault(); + link.click(); + } + }); + + // --- Touch (swipe) ----------------------------------------------------- + var startX = null; + var startY = null; + + // Walk up the DOM looking for a horizontally scrollable ancestor. If one + // exists, the user is probably trying to pan that inner content, so we + // surrender the swipe. + function startedInsideHorizontalScroll(el) { + while (el && el !== document.body && el !== document.documentElement) { + if (el.scrollWidth > el.clientWidth + 1) return true; + el = el.parentElement; + } + return false; + } + + document.addEventListener('touchstart', function (e) { + if (startedInsideHorizontalScroll(e.target)) { + startX = null; + return; + } + var t = e.changedTouches[0]; + startX = t.screenX; + startY = t.screenY; + }, { passive: true }); + + document.addEventListener('touchend', function (e) { + if (startX === null) return; + var t = e.changedTouches[0]; + var dx = t.screenX - startX; + var dy = t.screenY - startY; + startX = null; + startY = null; + + // Threshold: at least 70px horizontal movement, and the gesture must + // be predominantly horizontal (2x more X than Y). Anything mushier is + // treated as a tap / vertical scroll and ignored. + var absDx = Math.abs(dx); + var absDy = Math.abs(dy); + if (absDx < 70 || absDx < absDy * 2) return; + + var link = dx > 0 ? navLink('Previous') : navLink('Next'); + if (link) link.click(); + }, { passive: true }); +})(); diff --git a/docs/taskplane-overview/shared.css b/docs/taskplane-overview/shared.css index eaa6503a..138cf3cd 100644 --- a/docs/taskplane-overview/shared.css +++ b/docs/taskplane-overview/shared.css @@ -165,7 +165,7 @@ body { font-size: var(--fs-eyebrow); letter-spacing: 0.12em; text-transform: uppercase; - margin-bottom: 12px; + margin-bottom: 16px; /* Three-column grid: title (left) · wordmark (center) · nav (right). 1fr / auto / 1fr keeps the wordmark perfectly centered regardless of how wide the title or nav columns end up. */ @@ -173,6 +173,16 @@ body { grid-template-columns: 1fr auto 1fr; align-items: center; gap: 16px; + + /* Docked at the top of the viewport so the nav buttons are always + reachable. position: sticky keeps the eyebrow in normal flow until + the page scrolls past it, then pins it to top: 0. */ + position: sticky; + top: 0; + z-index: 10; + background: var(--bg); + border-bottom: 1px solid var(--border); + padding-block: 10px; } .eyebrow > :first-child { justify-self: start; } .eyebrow > .page-nav { justify-self: end; } @@ -186,27 +196,40 @@ body { justify-self: center; } -/* Subtle per-page navigation: prev / index / next. Placed inside .eyebrow. */ +/* Per-page navigation: prev / index / next. Lives inside .eyebrow. + Sized large (~2x the title) and tinted green so the controls read as + primary actions on every viewport, with 44x44 hit areas for touch. */ .page-nav { display: inline-flex; align-items: center; - gap: 14px; + gap: 8px; letter-spacing: normal; text-transform: none; - font-size: var(--fs-lg); + font-size: calc(var(--fs-lg) * 2); line-height: 1; } .page-nav a, .page-nav span { - color: var(--text-faint); + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 44px; + min-height: 44px; + padding: 4px 6px; + color: var(--green); text-decoration: none; - transition: color 0.15s ease; + transition: color 0.15s ease, transform 0.15s ease; } .page-nav a:hover { - color: var(--green); + color: var(--text); + transform: translateY(-1px); +} +.page-nav a:active { + transform: translateY(0); } .page-nav .disabled { - opacity: 0.3; + color: var(--text-faint); + opacity: 0.35; cursor: default; } From 3801b09a766dfee5d50d6491a26d95424e40dd80 Mon Sep 17 00:00:00 2001 From: Henry Lach Date: Mon, 18 May 2026 19:58:35 -0400 Subject: [PATCH 2/3] fix(overview): remove body top padding so sticky eyebrow docks from page load Previously, body had padding-top: var(--page-pad-y) (24-48px depending on viewport breakpoint). On a fresh page load the eyebrow sat below that padding band and only docked to top: 0 once the user scrolled past it. The visual effect was a noticeable 'jump' where extra whitespace above the eyebrow disappeared once scroll started. Zeroing just the top edge of body padding (keeping --page-pad-x on the sides and --page-pad-y on the bottom) puts the eyebrow flush against the viewport top from the moment the page renders. Sticky positioning then keeps it there throughout scroll, so the docked state is the only state the user ever sees. --- docs/taskplane-overview/shared.css | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/taskplane-overview/shared.css b/docs/taskplane-overview/shared.css index 138cf3cd..691c0d98 100644 --- a/docs/taskplane-overview/shared.css +++ b/docs/taskplane-overview/shared.css @@ -143,7 +143,10 @@ body { body { min-height: 100vh; - padding: var(--page-pad-y) var(--page-pad-x); + /* No top padding: the sticky .eyebrow sits flush against the viewport + top from page load, so it's always in its docked position. Side and + bottom padding remain. */ + padding: 0 var(--page-pad-x) var(--page-pad-y); } From ec3819277fc60f6677ce827174079b183ef3b3cd Mon Sep 17 00:00:00 2001 From: Henry Lach Date: Mon, 18 May 2026 20:09:49 -0400 Subject: [PATCH 3/3] fix(overview): trim body padding-bottom on page 8 to fit 16:9 desktop Page 8 is the tallest layout in the deck (3 wave cards with nested lane grids + a row of summary rule cards). With the shared 48px body padding-bottom it spills just past one 16:9 viewport height on standard desktop monitors, surfacing a vertical scrollbar that isn't desirable for a slide-style presentation page. Page-specific override sets body padding-bottom: 20px on this page only, which is enough to fit the content within one viewport at the default desktop scale without sacrificing breathing room beneath the rules cards. Other pages retain the shared --page-pad-y bottom padding. --- docs/taskplane-overview/08-waves-lanes-worktrees.html | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/taskplane-overview/08-waves-lanes-worktrees.html b/docs/taskplane-overview/08-waves-lanes-worktrees.html index bdfa67ca..aa35f1ce 100644 --- a/docs/taskplane-overview/08-waves-lanes-worktrees.html +++ b/docs/taskplane-overview/08-waves-lanes-worktrees.html @@ -179,6 +179,12 @@ .lanes { min-width: 540px; } .rules { grid-template-columns: 1fr; } } + + /* Page-specific override: this page is the tallest of the deck and + spills past one 16:9 viewport on desktop with the shared 48px body + padding-bottom. Trim it to 20px here so the whole page fits without + a vertical scrollbar at standard desktop aspect ratios. */ + body { padding-bottom: 20px; }