Fix the website issues - #1
Merged
Merged
Conversation
… in check_site
three.js r185 is not self-contained: three.module.min.js's first statement
imports ./three.core.min.js, which was never vendored. The 404 failed the
module graph before scene.js ran a line, so the page reserved a large empty
rectangle under "The stack, twelve blocks deep" and scene.js's own no-WebGL
fallback — which lives inside the module that failed to load — could never
run either.
Nothing caught it: check_site.py scanned src/href attributes, the importmap,
and import() calls in demo.js, but never followed imports *inside* a vendored
JS file. It now resolves every static and dynamic specifier in every shipped
.js against that file's own directory (bare names through the importmap), so
this class of break fails the build instead of production.
The specifier charset is deliberately narrow — minified three.js contains
English strings like "...resized from ("+w+")" that a permissive pattern
reads as imports.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: bowen <bowen.li.hurd@gmail.com>
logits_step_attn_async returns each block's post-softmax attention alongside the logits, so a caller can show what the model attended to while producing a token. ops::softmax is out-of-place, so the probe only clones Arc handles to tensors the step computes anyway — the arithmetic, and therefore the output, is unchanged. generate_async_probe threads it through the decode loop; generate_async_ctl is now a wrapper passing None and keeps its signature. Reading the n_layer+1 tensors one at a time cost a submit and a fence wait each: 111 -> 41 tok/s on an RTX A5000, 2.7x slower than the decode it was observing. WgpuContext::readback_many_async stages them into one encoder and issues every map request before awaiting any, so one poll services all of them; Tensor::to_vec_f32_batch is the facade. Same run, batched: 117 -> 120 tok/s, i.e. free. Tests cover both backends: one capture per block, rows summing to 1, no query attending forward, and — the one that matters — greedy output identical with and without the probe. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: bowen <bowen.li.hurd@gmail.com>
generate_with_attention mirrors generate but also calls on_attn(layer, n_head, weights) per block after every token, sending only the newest query row so the payload is n_head * kv_len. generate and the Stage 11 gate path (greedy_ids) are untouched and do no attention readback. n_layer/n_head/n_embd/n_ctx let the page size its architecture view from the model it is running instead of hardcoding GPT-2 124M's 12/12/768/1024. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: bowen <bowen.li.hurd@gmail.com>
scene.js becomes a createStack({canvas, label}) factory returning
{setConfig, pushAttention, reset, dispose} instead of a top-level side-effect
script. It no longer hardcodes 12/12/768/1024; demo.js feeds it the real
config from the wasm module, defaulting to the shipped char model's
6/6/384/256 until then.
While generating, each block slab carries an n_head x kv_len attention strip —
heads down, past positions across — as one DataTexture allocated at full
context width and written in place per token, with the UV repeat narrowed to
the filled part. No geometry is rebuilt per token. Per-head rows are scaled by
their own maximum before colouring, which is a display transform on real
numbers, not a substitute for them.
three.js is now imported only from scene.js, and demo.js await-imports that
module when #demo first intersects, so 751 KB is off the first-paint path
entirely. If WebGL or the import fails, the canvas card is removed rather than
left blank and the text architecture opens in its place — text generation
still runs, through the plain generate path with no probe.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: bowen <bowen.li.hurd@gmail.com>
…admap
Nine sections become five, and every one now answers what Forge is, why it
exists, or shows it working.
- #stack is absorbed into #demo ("Watch it think"): the 3D view and the demo
controls are two columns of one section, canvas first so the visual leads on
mobile. Merging them forces a correctness fix — the old section described
GPT-2 124M (12 blocks, 12 heads, n_ctx 1024) while the demo has always run
the char model's 6/6/384/256.
- The ASCII architecture <pre> becomes a semantic <ol> inside <details>. Fixed
width could not reflow, so it was the one element needing horizontal
scrolling on a phone to read a diagram whose point is a vertical flow. It
doubles as the no-WebGL fallback target.
- #verification and #roadmap are gone; one parity line survives in the hero,
and the footer already links Forge_Roadmap_V4.md. The dead
stat.dataset.sceneOk hook (no CSS rule ever matched it) went with them.
- #what and the "not a rebrand" card merge into #why: three cards for Rust,
WebGPU, and the CPU reference backend, at roughly half the words.
- The kernels lede drops "because GPT-2 inference or training needs it".
Two fixes found on the way. gen_kernels.py emitted one more </div> than its
regex consumed, so every build shipped an unbalanced tag. And #demo-charset
and #demo-progress-wrap carried Tailwind's `hidden` class while demo.js
toggled the `hidden` property — display:none from a class survives
hidden = false, so the charset warning and the 43 MB progress bar could never
appear.
plan/03-website.md is updated to match: the new section list, three.js
shipping as two files, the attention view, and the measured probe cost.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: bowen <bowen.li.hurd@gmail.com>
Signed-off-by: bowen <bowen.li.hurd@gmail.com>
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.
No description provided.