feat(site): the playground renders the answer - #16
Merged
Conversation
Model answers are markdown; render them. A small hand-rolled renderer (site/md.js) does headings, bold/italic, inline code, fenced code blocks, lists, links, blockquotes and tables in the codebase's vanilla, stdlib-only style - no vendored library, per DESIGN.md/TASTE.md. Model output is treated as hostile: every byte is HTML-escaped before it is emitted, and link hrefs are dropped unless they are http(s) or mailto, so a javascript: or data: URL never becomes an href. The streamed buffer is re-rendered per chunk and the renderer tolerates half-written markdown mid-stream without throwing. UX, in-contract with the terminal palette: a copy button on each answer and on every code block, a raw/rendered toggle so the exact markdown is one click away, the reasoning stream still shown dim, and the command panel kept prominent and in sync - it still shows the equivalent deepseek invocation for whatever is configured. Tests: md.test.js unit-tests the renderer including the two security cases (<script> renders inert, a javascript: link produces no javascript: href) and partial-stream inputs; playground.dom.test.js proves the page routes the answer through the renderer. make check is green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.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.
What
The playground streamed the model's answer as plain preformatted text, so any markdown it wrote arrived raw. This renders it: headings, bold/italic, inline code, fenced code blocks, lists, links, blockquotes and tables.
Before: the answer was
textContent- a wall of literal##,**, and unformatted ``` fences.After: rendered markdown inside the terminal-styled transcript, code blocks with copy buttons, a raw/rendered toggle, and a copy button on the whole answer. The command panel - the page's point - stays prominent and in sync.
Renderer: hand-rolled, not vendored
New
site/md.js, ~200 lines, same dual-export shape aspow.js. No library: DESIGN.md's pitch is no build step and TASTE.md already rejected pulling in a dependency (three.js) that would sell the reasons the site is good. A markdown lib would be the same trade for the same reason.Security (model output is hostile)
<script>alert(1)</script>renders as inert<script>....http(s)ormailto; anything with another scheme is dropped and the link renders as plain text, so[x](javascript:alert(1))produces nojavascript:href. The href value is escaped too, which neutralises entity-encoded and quote-breakout attempts.*) without throwing.Both security cases plus partial-stream inputs are unit-tested in
site/md.test.js;playground.dom.test.jsproves the page actually routes the answer through the renderer.UX (restrained, in-contract)
Copy button on the answer and on each code block; raw/rendered toggle; usage/cost line unchanged (already the CLI's stderr line); reasoning still shown dim. All styled off the
.termtokens so the transcript stays dark in both themes. No document-level horizontal scroll at any breakpoint. Web-search toggle and PoW enrol flow untouched.One narrow fix surfaced by rendering: the site dresses its own
h2/h3with a##/###prefix as a design signature - which made a rendered answer heading read as markdown that failed to render. Suppressed for.pg-bodyonly.Verification
make checkgreen. Verified in a real browser (CloakBrowser) at 1280px and 390px against the live free tier (freeseek.1lm.io, real PoW + real request; e.g.139 in / 225 out / ~\$0.000082): markdown renders, code blocks carry a working copy button, the command panel reflects the configured request, no sideways scroll at 390px.🤖 Generated with Claude Code