Skip to content

Fix the website issues - #1

Merged
Aisuko merged 6 commits into
mainfrom
website-v2
Jul 26, 2026
Merged

Fix the website issues#1
Aisuko merged 6 commits into
mainfrom
website-v2

Conversation

@Aisuko

@Aisuko Aisuko commented Jul 26, 2026

Copy link
Copy Markdown
Owner

No description provided.

Aisuko and others added 6 commits July 26, 2026 13:44
… 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>
@Aisuko
Aisuko merged commit c94bd51 into main Jul 26, 2026
1 check passed
@Aisuko
Aisuko deleted the website-v2 branch July 26, 2026 13:48
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