sx-tools: WASM kernel updates, TW/CSSX rework, content refresh, new debugging tools

Build tooling: updated OCaml bootstrapper, compile-modules, bundle.sh, sx-build-all.
WASM browser: rebuilt sx_browser.bc.js/wasm, sx-platform-2.js, .sxbc bytecode files.
CSSX/Tailwind: reworked cssx.sx templates and tw-layout, added tw-type support.
Content: refreshed essays, plans, geography, reactive islands, docs, demos, handlers.
New tools: bisect_sxbc.sh, test-spa.js, render-trace.sx, morph playwright spec.
Tests: added test-match.sx, test-examples.sx, updated test-tw.sx and web tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-02 11:31:57 +00:00
parent 9ed1100ef6
commit d40a9c6796
178 changed files with 13591 additions and 9110 deletions

View File

@@ -25,7 +25,7 @@
(defcomp ~streaming-demo/chunk (&key (stream-label :as string) (stream-color :as string) (stream-message :as string) (stream-time :as string))
(let ((colors (get stream-colors stream-color)))
(div :class (str "rounded-lg border p-5 space-y-3 " (get colors "border") " " (get colors "bg"))
(div :class "flex items-center gap-2"
(div (~tw :tokens "flex items-center gap-2")
(div :class (str "w-3 h-3 rounded-full " (get colors "dot")))
(h2 :class (str "text-lg font-semibold " (get colors "title")) stream-label))
(p :class (get colors "text") stream-message)
@@ -34,35 +34,35 @@
;; Skeleton placeholder for a stream slot
(defcomp ~streaming-demo/stream-skeleton ()
(div :class "rounded-lg border border-stone-200 bg-stone-50 p-5 space-y-3 animate-pulse"
(div :class "flex items-center gap-2"
(div :class "w-3 h-3 rounded-full bg-stone-300")
(div :class "h-6 bg-stone-200 rounded w-1/3"))
(div :class "h-4 bg-stone-200 rounded w-2/3")
(div :class "h-4 bg-stone-200 rounded w-1/2")))
(div (~tw :tokens "rounded-lg border border-stone-200 bg-stone-50 p-5 space-y-3 animate-pulse")
(div (~tw :tokens "flex items-center gap-2")
(div (~tw :tokens "w-3 h-3 rounded-full bg-stone-300"))
(div (~tw :tokens "h-6 bg-stone-200 rounded w-1/3")))
(div (~tw :tokens "h-4 bg-stone-200 rounded w-2/3"))
(div (~tw :tokens "h-4 bg-stone-200 rounded w-1/2"))))
;; Static layout — takes &rest children where the three suspense slots go.
(defcomp ~streaming-demo/layout (&rest children)
(div :class "space-y-8"
(div :class "border-b border-stone-200 pb-6"
(h1 :class "text-2xl font-bold text-stone-900" "Streaming & Suspense Demo")
(p :class "mt-2 text-stone-600"
"This page uses " (code :class "bg-stone-100 px-1 rounded text-violet-700" ":stream true")
(div (~tw :tokens "space-y-8")
(div (~tw :tokens "border-b border-stone-200 pb-6")
(h1 (~tw :tokens "text-2xl font-bold text-stone-900") "Streaming & Suspense Demo")
(p (~tw :tokens "mt-2 text-stone-600")
"This page uses " (code (~tw :tokens "bg-stone-100 px-1 rounded text-violet-700") ":stream true")
" in its defpage declaration. The browser receives the page skeleton instantly, "
"then three IO sources resolve at staggered intervals (1s, 3s, 5s)."))
;; Slot: suspense placeholders (or resolved content)
(div :class "grid gap-4" children)
(div (~tw :tokens "grid gap-4") children)
;; Flow diagram
(div :class "space-y-4"
(h2 :class "text-lg font-semibold text-stone-800" "Streaming Flow")
(div :class "grid gap-3"
(div (~tw :tokens "space-y-4")
(h2 (~tw :tokens "text-lg font-semibold text-stone-800") "Streaming Flow")
(div (~tw :tokens "grid gap-3")
(map (fn (item)
(div :class "flex items-start gap-3 rounded-lg border border-stone-200 bg-white p-4"
(div :class "flex-shrink-0 w-8 h-8 rounded-full bg-violet-100 flex items-center justify-center text-violet-700 font-bold text-sm"
(div (~tw :tokens "flex items-start gap-3 rounded-lg border border-stone-200 bg-white p-4")
(div (~tw :tokens "flex-shrink-0 w-8 h-8 rounded-full bg-violet-100 flex items-center justify-center text-violet-700 font-bold text-sm")
(get item "label"))
(p :class "text-stone-700 text-sm pt-1" (get item "detail"))))
(p (~tw :tokens "text-stone-700 text-sm pt-1") (get item "detail"))))
(list
{:label "Shell" :detail "HTML shell with three suspense placeholders sent immediately"}
{:label "Boot" :detail "sx-browser.js loads, renders fallback skeletons"}
@@ -71,9 +71,9 @@
{:label "5s" :detail "ML inference finishes — third skeleton replaced with amber box"}))))
;; How it works
(div :class "rounded-lg border border-violet-200 bg-violet-50 p-5 space-y-3"
(h2 :class "text-lg font-semibold text-violet-900" "How Multi-Stream Works")
(ol :class "list-decimal list-inside text-violet-800 space-y-2 text-sm"
(div (~tw :tokens "rounded-lg border border-violet-200 bg-violet-50 p-5 space-y-3")
(h2 (~tw :tokens "text-lg font-semibold text-violet-900") "How Multi-Stream Works")
(ol (~tw :tokens "list-decimal list-inside text-violet-800 space-y-2 text-sm")
(li "Server evaluates " (code ":data") " — gets an " (em "async generator"))
(li "HTML shell with three " (code "~shared:pages/suspense") " placeholders sent immediately")
(li "Generator yields first chunk after 1s — server sends " (code "__sxResolve(\"stream-fast\", ...)"))
@@ -82,9 +82,9 @@
(li "Each resolve replaces its skeleton independently")))
;; Technical details
(div :class "rounded-lg border border-stone-200 bg-stone-50 p-4 text-sm space-y-2"
(p :class "font-semibold text-stone-800" "Implementation details")
(ul :class "list-disc list-inside text-stone-600 space-y-1"
(div (~tw :tokens "rounded-lg border border-stone-200 bg-stone-50 p-4 text-sm space-y-2")
(p (~tw :tokens "font-semibold text-stone-800") "Implementation details")
(ul (~tw :tokens "list-disc list-inside text-stone-600 space-y-1")
(li (code "defpage :stream true") " — opts the page into chunked transfer encoding")
(li (code ":data") " helper is an async generator — each " (code "yield") " resolves a different suspense slot")
(li "Each yield includes " (code "_stream_id") " matching a " (code "~shared:pages/suspense :id") " in the shell")