Skip to content

feat: interactive tutorial tab running flashtrace in the browser#5

Open
MentorFilou wants to merge 34 commits into
mainfrom
feat/tutorial-tab
Open

feat: interactive tutorial tab running flashtrace in the browser#5
MentorFilou wants to merge 34 commits into
mainfrom
feat/tutorial-tab

Conversation

@MentorFilou

Copy link
Copy Markdown
Member

Implements the accepted tutorial proposal (#4) as one coherent feature, per the decided single-PR delivery: a new /try/ page, reached via a compact "Try it" CTA in the top bar, where a large editable IDE mock teaches flashtrace hands-on - and its terminal executes the real, release-pinned dist/flashtrace.mjs in a module worker against the editor buffers as in-memory files.

How the runner works

  • At build time, the release bundle's five node:* import specifiers are rewritten to ~180 lines of shims (in-memory fs over a seeded Map, posix path, throwing process.exit signal, URL-pathname mapping, unreachable child_process). Every other byte ships verbatim; the build asserts the exact builtin set so upstream bundling drift fails the deploy loudly.
  • Each Run spawns a fresh module worker: seed vfs + argv, import the bundle (its own CLI-entry detection fires), capture console output and the first exit signal, and derive structured items/problems from the bundle's public exports for the chapter checks. Byte-identical reports and exit codes were verified against real CLI runs.

The tutorial

  • 11 chapters (all of the proposal's curriculum) continuing the landing page's login/auth story: foundations (item anatomy, Needs + code tags, report reading, Covers/orphans), features (revisions & wildcards, demands & deep coverage with -v, forwarding, tags & -t scoped runs where the user edits the command), extras (a five-defect capstone, keyword tables, anchored vs implicit demand tags).
  • Build-time chapter verification: every chapter's start state and each step's cumulative patched state runs through the exact rewritten bundle during pnpm build; expected defect/clean outcomes, monotonic step checks, done-conditions and exit codes are asserted - a behavioral change in a flashtrace release fails CI/deploy instead of shipping a broken lesson. The captured real reports double as the no-JS fallback (all chapters read-only, landing-example fidelity).
  • Progress (ft-tutorial-progress): write-once detailed entries - title, content-hash chapter identity rev (sha256-12 over the canonical chapter definition), lang, completedAt, and help/auto assist counters. Assisted completions get a distinct rail mark. Keyed only by stable chapter ids; corrupt/foreign data degrades to "no progress".
  • Buffers (ft-tutorial-buffers): debounced per-chapter persistence, cleared on completion; returning to in-flight work opens a resume/start-fresh dialog with an "updated since" note on rev mismatch.
  • Assists: "Help me" spotlights the current step's anchor line inside the IDE (punched-hole overlay + focused popup with explanation and docs link); "Do the next step for me" additionally typewrites the patch via setRangeText (undo intact) and runs - instant under prefers-reduced-motion. The current step is always computed as the first failing check, so type-ahead, pasted solutions and re-broken steps re-converge.
  • Polish: scroll-synced token-highlight overlay over the editors, mobile drawer rail + stacked panes, aria-live terminal and step progress, focus-managed dialogs.

Verified

  • pnpm build green (includes the ~40 real-CLI chapter verification runs).
  • Headless Chromium e2e against the dev server (local Playwright, not a committed dependency): byte-identical defective report + exit 1 → fixed → ok + exit 0; completion entries incl. assist counters; resume modal both paths; corrupt localStorage; -t auth command chapter; both assist buttons across drifted/type-ahead buffer states; reduced-motion; overlay sync; mobile drawer; no-JS fallback (11 sections, IDE hidden).
  • Workflows need no changes: CI/deploy already check out the full tool repo at the release tag, where dist/ is committed.

Also included: the dev server now serves .mjs with a JavaScript MIME type (module workers require it), and colorizeReport/highlightTokens moved into standalone modules shared between the build and the browser.

🤖 Generated with Claude Code

MentorFilou and others added 30 commits July 18, 2026 21:08
The /try/ page needs the report colorizer client-side; keep one standalone,
dependency-free module the build and the browser both import.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- shim the five node builtins the bundle imports (in-memory fs over a
  seeded Map, posix path, throwing exit signal, url pathname mapping,
  unreachable child_process) and rewrite the specifiers at build time,
  asserting the builtin set so upstream drift fails the build loudly
- module worker executes the bundle per run against the editor buffers
  and derives structured items/problems from the exported library surface
- bare /try/ page: large editable IDE mock (spec + code textareas,
  live terminal with Run and Ctrl+Enter, 5s watchdog, exit code display)
- "Try it" CTA button in the top bar, /try/ in the sitemap, .mjs MIME
  type for the dev server

Verified in Node against the landing "uncovered defect" example:
byte-identical report, exit code 1.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
esbuild keeps bare `process` references (files.mjs GIT_LOCATIONS) pointing
at the global, which Node provides but a module worker does not. Assign the
node:process shim to globalThis.process so both reference styles resolve to
the same object. Found by the headless browser check; the Node-based PoC
masked it because Node has the global.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- chapters.mjs: full v1 curriculum continuing the login/auth story
  (foundations 1-4, features 5-8, extras 9-11); language-specifics live in
  per-chapter variants (js in v1), checks/done are serializable pure
  functions over the structured run result
- chapter-utils.mjs: shared pure helpers (patch application, tags parsing,
  structured analysis via the bundle's exports) used by the browser worker
  and the build; the worker now imports them instead of inlining
- verify.mjs: every chapter's start state and each step's cumulative
  patched state runs through the rewritten release bundle at build time;
  asserts start clean/defective expectations, monotonic step checks, the
  done condition and exit 0 on the solved state - a behavioral change in a
  flashtrace release fails the deploy instead of shipping a broken lesson.
  Also computes the sha256-12 content-hash chapter identity (rev) and the
  client payload.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- chapter rail (docs sidebar pattern incl. mobile drawer) with completion
  marks - a distinct mark for assisted completions - and a reset control
- head section, IDE chrome, pane tabs and editable command-line arguments
  all switch per chapter; deep-linkable via #chapter-id
- progress map ft-tutorial-progress: write-once detailed entries (title,
  content-hash rev, lang, completedAt, assist counters), keyed only by
  stable chapter id so inserted chapters can never auto-check; corrupt or
  foreign-versioned JSON degrades to no progress
- buffers ft-tutorial-buffers: debounced per-chapter save, cleared on
  completion; returning to in-flight work opens a resume/start-fresh
  <dialog> with an updated-since note on rev mismatch
- current step = first failing check, recomputed after every run and
  (via silent background runs) after edits; completion only ever triggers
  on a real Run
- no-JS fallback: all 11 chapters render read-only with their inputs and
  the build-time captured real reports

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
init() ran before the module-level let bindings existed (temporal dead
zone) and crashed on load. Also follow hash changes to switch chapters,
so deep links work from within the page.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both operate on the current step (first failing check, so type-ahead,
pasted solutions and re-broken steps re-converge):

- Help me: spotlight overlay with a punched-out hole over the step's
  anchor line (pane tab on narrow layouts, the command input for argv
  steps), plus a focused popup inside the IDE with the step explanation
  and a docs link; dismiss via close button, Esc or backdrop click with
  focus restore
- Do the next step for me: same highlight, then typewrites the step's
  patch into the real textarea via setRangeText (undo intact) and
  triggers a run; instant apply under prefers-reduced-motion; buffers
  that drifted off the anchor get guidance instead of a broken edit
- per-chapter help/auto counters land in the progress entry; assisted
  completions render the distinct rail mark
- anchor lines are located arithmetically over the monospace editors
  (no wrapping, so no mirror element is needed)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- editors upgrade to a transparent textarea over a scroll-synced,
  highlightTokens-rendered <pre> with identical metrics; built at
  runtime, so the no-JS page keeps plain textareas. highlightTokens
  moves into its own dependency-free module (src/highlight.mjs, shipped
  to the browser; layout.mjs re-exports it for the build)
- typewriter refreshes the overlay per chunk so assisted edits stay
  visible while typing
- step progress announces politely (aria-live); the terminal already did
- compact CTA never wraps on narrow viewports

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An ungrouped 'Free editor' item (#editor) above the chapters opens a
chapter-shaped sandbox: empty spec.md and script.js, no goal, steps or
completion. Its buffers persist like a chapter's but restore silently,
and background check runs are skipped since nothing evaluates them.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The top-bar CTA now targets #editor. Landing there without a single
completed chapter opens a welcome dialog offering to start learning
from the first chapter (primary) or stay in the free editor.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The tutorial page moves to /learn/ (never shipped under /try/, so no
redirect needed) and gets a permanent spot in the top-bar nav between
Home and Docs. The 'Try it out' CTA keeps pointing at its free editor.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The free-editor mode hides #assist-bar via the hidden attribute, but
the author-level display:flex overrode the UA rule and the bar stayed
visible. Caught by the browser e2e smoke.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The base stylesheet applies `font-size: 0.9em` to every code element, so
the text in the highlight overlay rendered 10% smaller than the
transparent textarea above it. The per-character width difference summed
up along a line, drifting the caret right of the visible text. Inherit
the overlay pre's font on its inner code element instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Trackless rounded thumbs via ::-webkit-scrollbar with new
--scroll-thumb tokens per theme; the chapter/docs rails and toc get a
slimmer 8px bar. The always-dark IDE mocks override the tokens locally
so their panes keep dark thumbs in light mode. Firefox falls back to
scrollbar-color/-width behind @supports, excluded on Blink where the
standard properties would disable the pseudo-element styling.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A completed chapter now shows its solved files blurred under a check
card stating when and with how many assists it was finished, plus a
"Reset chapter" button that forgets the completion and reseeds the
start files. Completion keeps the solved buffers (instead of deleting
them) so revisits restore them silently under the overlay - the
"Work in progress" resume modal no longer appears on finished
chapters. Everything inside the IDE goes inert while the overlay is up.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every chapter step gains a short title next to its explain text, and the
steps render as an accordion between the intro and the IDE: finished
steps fold away greyed out behind a check, the current one unfolds with
its explanation, and the engine re-syncs the fold after every analysis.
The no-JS fallback lists the same titles and explanations per chapter.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Each pane gets a tab strip over its own files: click to switch, ✕ to
delete behind a confirmation dialog, + to create via a name + type
dialog. The type field autocompletes from datalists whose code list is
parsed out of docs/code-tags.md at build time; unsupported extensions
block creation and offer the tool's issue tracker, markdown is routed
to the spec pane and code the other way.

Chapters can set 'locked: true' (now on all four Foundations chapters)
to forbid file management - tabs show padlocks and a disabled +, both
with explanatory tooltips. All files of both panes feed every run, and
checks see r.spec/r.code as the pane-joined text plus the run's file
map as r.files, so steps stay satisfiable when work spans added files.
Assists patch the chapter's seeded files by name and leave user tabs
alone. Buffers persist per pane with the active tab; legacy two-string
entries still restore.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Manual clicks could leave several steps open between engine syncs. The
details elements now share name="chapter-steps", which modern browsers
fold exclusively on their own; a capture-phase toggle listener mirrors
the behavior where the attribute is unsupported. Folding the open step
to none stays allowed, and every analysis still re-syncs the fold to
the current step.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The step accordion re-folded to the current step on every run, including
the debounced silent runs fired by editor input. Clicking a different step
to explore while one of those runs was in flight snapped the fold back to
the current step - the classic "jumps back the first time, sticks the
second time" symptom.

syncStepList now only re-folds to the current step when that step index
actually changes (chapter switch, real progress) or on an explicit reset;
the progress classes still mirror every run. Background silent runs no
longer disturb a fold the user opened deliberately.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Each chapter link carries an SVG donut split into one arc per step,
clockwise from 12 o'clock; solved steps draw bold in the text color
while the rest stay thin and muted, and a completed chapter is always a
full ring next to its check. Solved-step counts persist per chapter in
ft-tutorial-steps (written after every analysis) so rings survive
reloads and chapter switches; both reset paths clear them. The rail
legend gains a JS-revealed "steps solved" demo ring.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The progress ring and completion check shared a chapter link side by
side, so a finished chapter drew both a full ring and a check. Collapse
them into a single slot: in-progress chapters show the ring, completed
ones hand the slot to the check.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Track per step whether it was cleared by the user or with an assist
("Do the next step for me" / a hint). The ring segment and the
accordion check now draw green for self-solved steps and amber for
assisted ones, so a chapter's ring shows at a glance how much help was
used, not just how far along it is.

ft-tutorial-steps entries grow from a bare solved count to
{ done, assisted }; legacy number entries migrate as all-self.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
"Help me" moves out of the assist bar into the docs row of the chapter
head (right-aligned, hidden in the free editor). The "Do the next step
for me" button is gone from the main screen; the help popup now offers
"Do this step for me" as a follow-up action instead, so auto-solving is
reached through asking for help first. The follow-up hides while a step
is being applied and on the unapplicable-step error paths.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Free editor is not a progress-tracked chapter, so its rail link no
longer reserves the ring/check gutter the chapters use. It now renders
as a bordered pill with a ‹› code glyph, setting it apart as a separate
tool pinned above the chapter groups.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Chapters teach the syntax instead of dictating one exact solution:

- Your first item: starts from an empty spec with no code pane
  (chapter noCode flag hides the right editor); any heading and any
  ID complete it
- Cover a requirement: the needed item's name is the user's choice;
  checks assert the requirement demands something and code covers it
- Read the report: new first step asks to actually run flashtrace
  and read the report before fixing
- Covers: & unwanted: rebuilt as write a Covers entry, run to see it
  come back unwanted, then close the loop with a Needs on the target
  (the revision-mismatch lesson stays in chapter 5)

New engine capabilities behind that:

- run-gated steps (step.run): only a real, user-triggered Run clears
  them - background silent runs never do; cleared state is seeded
  from the persisted step count on revisits
- adaptive auto-solve (step.solve): "Do this step for me" derives its
  snippet from the latest analysis, so it picks up IDs the user chose
  over the static example; build verification asserts solve()
  reproduces the static snippet on the static path
- applyStep takes a snippet override and appends onto empty buffers
  without the separating newline

Auto-completion keeps the current static examples as fallback.
Verified with a Playwright pass over all four chapters (custom IDs,
run gating, adaptive solve, pane hiding).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
MentorFilou and others added 4 commits July 18, 2026 23:15
Chapter 1 goes back to three steps - heading, ID line, description -
but the description stays open-ended: the check only requires the
titled item to carry a description, in the user's own words.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Split the tags-and-filtering chapter into two steps: the user now
writes the Tags: line on the auth requirement first, then scopes the
run with -t. Seeds the login requirement untagged so the added step
is a real prerequisite for the filter step.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Restructure the single-step forwarding chapter into a natural
progression that introduces the feature through its defining
property. Step 1 delegates the login requirement to the auth design
with a forwarding tag; because the design is only shallow-covered, the
requirement inherits exactly that depth. Step 2 deepens the design by
writing and tagging its demanded test, and the forwarded requirement
follows to deep-covered untouched - demonstrating that a source is
covered exactly as deeply as its target.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The /learn/ entry script had grown to ~1450 lines. Extract its engine
into sibling ./tutorial-*.mjs modules grouped by responsibility (dom,
state, store, util, highlight, files, persistence, steps, runner,
assists, chapters); tutorial.js is now a 176-line entry that wires the
IDE and bootstraps.

Shared mutable state lives in tutorial-state.mjs as live-binding exports
with small setters, so reads stay identical to the original and only
reassignment sites change - keeping the split mechanical.

build.mjs copies every tutorial-*.mjs into dist/learn/ so the browser
loads them flat next to tutorial.js.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@MentorFilou MentorFilou self-assigned this Jul 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant