feat(pages): language guide with run-in-place examples + REPL deep links - #3
Merged
Conversation
… DEMO.md Companion page to the engineering tour, same design system. Tutorial is the spine; DEMO.md's stream/cursor material becomes its own section. Sketches and network-only examples are labeled; the sources of truth remain TUTORIAL.md / DEMO.md, which CI executes on every push. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 96e6711)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 722e255)
…uide
repl.html gains a hash runner: #code=<URI-encoded source> is fed through
the normal submit path after wasm init (echoed like typed input, history
populated). Two REPL line-at-a-time gotchas are smoothed at intake:
multi-line @{...} match blocks join to the documented single-line idiom,
and multi-line if/then/else chains join so the else doesn't dangle.
The guide marks browser-safe blocks with pre.run; a small script builds
each link from the block's own text (annotation-only lines dropped), so
no snippet is hand-copied. Network examples, sketches, and the comment
demo are unmarked. Verified: all 29 links execute error-free in the wasm
VM via Playwright, with value assertions on 11.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 75eb405)
[profile.wasm-release]: opt-level=z, fat LTO, 1 CGU, panic=abort, strip. panic=abort is safe here: VM errors are Results by design (no catch_unwind in-tree; overflow probed in-browser — clean error, no trap). wasm-opt -Oz needs --enable-bulk-memory since Rust emits bulk-memory ops by default. 2.1MB/580KB-gzip -> 1.13MB/373KB-gzip, verified against the pinned wasm-bindgen 0.2.114 locally. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit a637c37)
The globals expose one persistent session VM; the language guide's run-in-place blocks need a fresh VM per run (the doctest harness's semantics) without nuking the session. Exports a constructor plus eval/is_complete with the same output contract as the globals. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 2415a61)
…-browser
Every runnable block gets ▸ run / edit / reset controls. Run executes
the block in a fresh ReplVm (CI doctest semantics); live results replace
the documented '-- Returns:' lines with ✓/✗ verdicts, and a masthead
'run all blocks' re-verifies the whole page client-side (29/29 locally).
edit swaps the block for a textarea; deep links remain for sharing.
The REPL line-handling logic (multi-line @{} and if/else joining) moves
to a shared docs/fmpl-live.js module used by both repl.html and the
guide, along with the annotation-checking block runner (same conventions
as fmpl-core/tests/doc_examples.rs, including order-insensitive top-level
map compare). wasm loads lazily on first run; prefetch warms the cache.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 19b7ea7)
… ops First CI run of the shrink step failed validation on i32.extend8_s: ubuntu's packaged binaryen predates default sign-ext support. Pin the release that matches the locally verified build. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit e8d2dbd)
…quiet exits Assessment findings from a first-visitor walkthrough, addressed: - The hero looked like a REPL but was frozen — now it IS one: ▸ run steps through the demo session statement by statement, and the prompt is a real input (same session VM; reset restarts). The affordance no longer lies. - 'run all blocks' was a verification feature posing as the page's first CTA, and it spent the one-by-one experience. Split: per-block ▸ run now STEPS one statement at a time (≫ finish drains the rest), while §13 gains '✓ verify this page' — non-destructive, fresh VM per block, per-block verdict chips + badge, no text rewritten. reset-all included. - Exit-sign demotion: the caption's 'run in your browser' link is gone (the page runs in the browser); per-block REPL links shrink to a quiet ↗ glyph for sharing. - Caption diet; 'edit' appears only after a block has been run. fmpl-live.js: runBlock refactored into createRunner (statement stepper); runBlock drains it, so verify and stepping share one implementation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit c70c10d)
Clearing the hint on boot made the first ▸ run visually jarring: the instruction vanished and the transcript shifted up. The hint is already written as an FMPL comment, so it simply stays in the scrollback and the session grows beneath it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 7a4ec17)
…the page The provenance caption moves above the hero — it sets up the terminal rather than captioning it after the fact. §1's opening no longer sends readers to the standalone REPL: the fastest path is this page; the toolchain block covers local installs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit ba17a49)
…tabs The full browser REPL gets one subtle mention in §1 (blank-slate scratch sessions) with a recommendation to keep learning in place. It and the per-block ↗ links now open in a new tab so the guide is never navigated away from. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 37f9673)
'…or type FMPL here' kept reappearing after every submitted line. Once the session is going — stepped or typed — an empty prompt is just an empty prompt; reset restores the invitation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit fd6c4b4)
…one interaction The hero terminal and the run-in-place doc blocks were two separate interaction concepts. Collapse them into one: an amber ▸ in a left gutter marks the next statement everywhere. The hero is "terminal material" (stepped lines promote into a growing transcript, cursor becomes the live prompt); doc blocks are "document material" (running fills the reserved `-- Returns:` slots in place, line count never changes). - Fixed control bars (▸ next / » run to end / ↺ reset); buttons disable rather than hide so nothing shifts under the pointer between clicks. - Empty-enter drives the hero script forward — the prompt is the cursor. - Runner fixes: hasOpenBlockComment() keeps /* */ from splitting across statements; isCommentOnly() advances the cursor silently instead of hitting the VM (a lone -- is an eval error); findNextStatement() and trailingAnnotationSplit() place the cursor and transform annotations without the VM. startIdx now threaded through the runner. - Remove the inline block editor — blocks are read-and-step only. - Mobile: 16px input row under 40rem stops iOS tap-zoom; auto-focus gated behind (pointer: fine) so » run to end doesn't pop the keyboard on touch. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> (cherry picked from commit bf3c4e5)
The masthead opened with a possessive attribution — phrasing written when these pages lived on a fork and had to distinguish whose work was whose. On the canonical repo that reads as a byline the author didn't ask for. The dek now describes the tutorial; attribution moves to the meta strip as a quiet trailing item, and the footer stops repeating it.
The landing page and the tour opened with the same sentence word-for-word, both leading with a possessive byline, and the guide card repeated it a third time — a pattern from the fork, where whose-work-was-whose needed restating everywhere. It reads as branding on the author's own site. Each dek now leads with the subject and they no longer duplicate. The guide credits its author in the meta strip; the tour keeps its mentions in the lineage prose, where they carry information.
'Written by' pushed the strip to two rows, which put the byline alone on its own line — more prominent than the inline trailing item it replaced. The CI-verified value loses a redundant verb to make room; the caption directly below already says CI executes the snippets.
The guide claimed 'CI-verified: every snippet' in four places. CI runs the blocks in TUTORIAL.md, DEMO.md and README.md — doc_examples.rs never reads fmpl-guide.html. The page is a hand transcription, so a slip in the HTML would go uncaught and the page can drift from its sources silently. What is true: the sources are CI-executed, and this page runs its own blocks live in the browser against the real VM. The copy now says that instead. Wiring the guide into doc_examples.rs would make the stronger claim honest and is worth doing separately. Also corrects the wasm-release comment: there is a catch_unwind in the tree, in a test, which never builds under that profile.
The comment carried an estimate (~2.1MB -> ~1.1MB) that had never been measured against the build CI actually produces. Measuring without running the bootstrap first compounds it: that links the Rust fallback parser instead of the FMPL-generated one and understates the artifact by ~30%. Bootstrapped, matching pages.yml: 2.30MB -> 1.19MB raw, 553KB -> 374KB gzipped. The result lands within 460 bytes of the deployed artifact, which the workflow's own 'ls -l' line makes checkable.
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.
Adds a web rendering of
TUTORIAL.md+DEMO.mdasdocs/fmpl-guide.html, where every code block runs in the browser against the real VM, and wires the browser REPL up to take deep links so any snippet can open in a full session.The site had "what it is" (the tour) and "try it" (the REPL) but no "learn it" surface. This is that.
What's here
docs/fmpl-guide.html— the guide. Each block has▸ next/» run to end/↺ reset; blocks carrying-- =>or-- Returns:comments assert against them and show a verdict (✓ 3/3 verified). A live terminal in the masthead runs a short scripted session, then hands you the prompt.docs/fmpl-live.js— the run-in-place engine: line normalization for multi-line@{...}andif/else, per-block VM instances, verdicts.fmpl-wasm/src/lib.rs— aReplVmclass alongside the existing global functions. Purely additive; nothing existing changed. Each guide block gets a fresh VM (matching the doctest harness's semantics) whilerepl.htmlkeeps its long-lived session.docs/repl.html—#code=<encoded>prefill, fed through the normal submit path. Safe to auto-run: the wasm build has no network or file builtins..github/workflows/pages.yml+Cargo.toml— a size-tunedwasm-releaseprofile and awasm-optpass. 2.30MB → 1.19MB raw, 553KB → 374KB gzipped.Two build details worth a look
panic = "abort"in the new profile. VM errors areResults by design, and the onecatch_unwindin the tree is in a test, which never builds under this profile, so unwinding machinery is pure weight in the browser. Flagging it because it's the one change here with runtime semantics.binaryen is pinned to 129. apt's
wasm-optis too old to accept the sign-extension ops rustc emits by default, and Rust also emits bulk-memory ops thatwasm-opthas to be told about explicitly. The pin is what I measured against. A floating version will break the deploy the moment the runner image shifts.Important note
The guide is a hand transcription of
TUTORIAL.md/DEMO.md.doc_examples.rsexecutes the blocks in those files, but nothing readsfmpl-guide.html. A transcription slip wouldn't be caught, and the page can drift from its sources the next time you edit them.The copy on the page says only what's true: the sources are CI-executed, and the page runs its own blocks live in the browser. It does not claim to be CI-verified itself.
Closing that properly means teaching
check_doc_fileto pull<pre><code>blocks out of the guide and run them too; the machinery's already there. I left it out to keep this PR to one idea, but I'm happy to do it here or as a follow-up, whichever you prefer.Notes
docs/repl/stays gitignored; the wasm is built from source on every deploy, never committed.joinMatchBlocksinfmpl-live.jsis long (209 lines). It's a line-joining state machine and I think splitting it would hurt more than help, but say the word if you'd rather it were broken up.cargo check -p fmpl-wasm --target wasm32-unknown-unknown --profile wasm-releasepasses on this branch.Companion to #2, which repoints the stale fork URLs on the existing pages.
Background if useful: see mparrett#8 for how this page came together (intended advisory only).
Rendered preview: https://mparrett.github.io/fmpl/fmpl-guide.html. My fork, serving this branch's copy of the page so it can be read rendered rather than as a 1,500-line diff. The live blocks work there. It's a temporary mirror; the fork is coming down once this is settled.