Skip to content

Site overhaul, Tetris tutorial chapter, and library catch-up from fixes - #57

Merged
bigmistqke merged 240 commits into
solidjs-community:nextfrom
bigmistqke:next-site
May 29, 2026
Merged

bigmistqke merged 240 commits into
solidjs-community:nextfrom
bigmistqke:next-site

Conversation

@bigmistqke

@bigmistqke bigmistqke commented May 27, 2026 •

Copy link
Copy Markdown
Contributor

What's in this PR

A new docs site for solid-three (site/, ~21k lines, 93 files) plus a small follow-up refactor of the renderer-type default. The library/test-infrastructure work that came in via the recent fixes merge — gl-prop flat refactor, browser-mode testing migration, createThree canvas swap, etc. — is not described below; it's its own concern and reviewable separately.

The docs site

Scaffolded under site/ with SolidStart and SolidBase, rendered with MDX. Every code sample is a live <Demo> — a small wrapper around @bigmistqke/repl that compiles the snippet with babel-preset-solid and runs it in an iframe; the reader can edit the source in-place. Two top-level sections:

Tutorial (nine chapters)

  1. Your first scene — Canvas, <T.Mesh>, the smart-prop pipeline.
  2. Props and children — nesting, transforms, args, reactive props.
  3. Control flow — <Show>, <For>, <Index>, <Switch>/<Match>, <Suspense>.
  4. Pointer events — click, hover, stopPropagation, onClickMissed.
  5. useFrame — signal form, imperative form, priority ordering.
  6. Loaders & Resource — useLoader, <Resource>, loader cache.
  7. Portal — escape transforms; render-to-texture.
  8. Tetris — built across three demos (render → gravity+keys → lines+score). The chapter's punchline: "game development is state management; Solid is a state manager that happens to render <T.Mesh>."
  9. A peek at WebGPU — WebGPURenderer factory, TSL basics, a TSL uniform-driven slider.

API reference

Ported and rewritten from the README into per-export pages, organised by component / hook / event / utility (16 pages). Notable rewrites:

  • Canvas — flat r3f-style gl prop documented, with an explicit note that constructor params are applied once at first construction and are never re-read (because canvas.getContext is idempotent — to swap, unmount and remount <Canvas>). Defaults table covers frameloop, gl, shadows, tone-mapping, color-space.
  • useProps — rewritten to match the actual coercion order in src/props.ts.
  • Entity / createEntity — moved off the T page where it didn't belong.
  • Events overview — consolidated event-object shape, intersection fields, smart-prop pipeline.

Home page

A 3D hero scene of SOLID THREE letters dropped with cannon-es physics, cursor repulsion, click-to-punch, camera drift, fake contact shadows, studio reflection. A toggle lazy-mounts a <Demo> editor over the scene so the home page doubles as a REPL into its own source.

<Demo> component

The piece that makes the whole site tick. Wraps @bigmistqke/repl, pre-bundles the local solid-three for the iframe, gates the editor open on click, syncs the editor theme with the site's light/dark mode, syntax-highlights via tm-textarea, surfaces compile errors without killing the iframe, and bakes color-scheme into the iframe HTML at creation so there's no white flash in dark mode.

Renderer type default (small library follow-up)

The fixes merge left ResolvedRenderer defaulting to the open Renderer union, which forced every project to declare a Register augmentation just to call WebGLRenderer-specific methods on useThree().gl. This PR flips the default:

  • ResolvedRenderer defaults to WebGLRenderer — the common case is friction-free; users on other renderers opt in via Register.
  • Register / Renderer / ResolvedRenderer re-exported at the top level so declare module "solid-three" { interface Register { ... } } works directly (previously the symbols were only accessible via the S3 namespace, so augmentation didn't merge).
  • Site widens back to the open union via a local solid-three.d.ts since the site demos both WebGL and WebGPU renderers.
  • Tests widen back in tests/setup.ts so mock RendererLike renderers in test fixtures keep type-checking.

This is the only library change in this PR; everything else under src/ was already in fixes.

Process / docs

Specs and implementation plans for the bigger pieces of work (tutorial structure, hero splash REPL, tetris chapter) live under docs/superpowers/{specs,plans}/.

Test plan

  • pnpm test — 9 files, 151 passed, 2 todo, 0 failures.
  • pnpm exec tsc --noEmit — clean apart from two pre-existing, unrelated errors (demo.tsx babel-preset, vite.config.ts extensionAlias drift).
  • pnpm build — both ESM and DTS build successfully.
  • cd site && pnpm dev — walk the tutorial chapters end to end, exercise the API reference pages, confirm the hero scene plays.

bigmistqke added 30 commits May 26, 2026 19:55
Wires @mdx-js/rollup with solid-mdx provider into the tutorial Vite config,
adds remark-frontmatter/remark-mdx-frontmatter plugins, and renders a smoke-test
chapter (00-hello.mdx) that exports a typed frontmatter object.
Replace the bespoke Vite + custom-MDX scaffolding with a SolidStart +
@kobalte/solidbase site. Salvages the @bigmistqke/repl-backed `<Demo>`
component and the local solid-three esbuild bundle plugin verbatim.

The tutorial is now its own isolated project (no longer driven by the
root vite config): tutorial/package.json with @solidjs/start v2 alpha,
@kobalte/solidbase 0.6.x, vite 8, nitro. Root `dev:tutorial` /
`build:tutorial` cd into tutorial/ and run `vite dev` / `vite build`.

Chapters are MDX files under `src/routes/`, the sidebar (Parts I-VI) is
configured in `vite.config.ts`, and Demo is exposed globally to MDX via
`src/theme/mdx-components.tsx` (SolidBase's componentsPath convention).

A small fallback plugin works around a packaging quirk in SolidBase 0.6.3
where some `.jsx` files in dist are referenced via `.js` extensions.
Demo is rendered as an empty placeholder during SSR because
@bigmistqke/repl depends on DOMParser; the client takes over on hydration.
…stqke/repl

The previous pipeline ran ts.transpile twice (preserve -> ReactJSX with
jsxImportSource: 'solid-js'), producing _jsx(...) calls that import from
solid-js/jsx-runtime. That module doesn't export 'jsx' (Solid compiles
JSX to _$template/_$insert calls, not a runtime jsx() factory), so
snippets failed at load time.

Use @bigmistqke/repl's babelTransform to load @babel/standalone +
babel-preset-solid from esm.sh at runtime, and run Solid's real JSX
transform on the snippet. TS syntax is stripped first via ts.transpile
(JsxEmit.Preserve) so Babel only handles JSX -- this also sidesteps the
@babel/preset-typescript filename requirement that babelTransform
doesn't forward.

The Babel bundle resolves asynchronously, so the Extension transform
returns an Accessor that swaps in the compiled output once the CDN
imports settle; before then it emits a placeholder default export so
the iframe loads without throwing.
…rted via ?raw)

Extracts all inline MDX template-literal snippets to tutorial/src/snippets/
and imports them via Vite's ?raw query to preserve source indentation exactly.
bigmistqke added 11 commits May 28, 2026 16:56
Tap the demo iframe's theme postMessages into a signal and rebuild the
canvas texture + background on change: dark tube / light type in dark
mode, inverted in light mode.
Revert the reference route tree and all cross-links to /api; keep /tour.
The previous approach keyed off the active link, but Kobalte unmounts a
collapsed section's content so that link isn't in the DOM until its
section is already open. Derive the section from /api/<group>/<page>
instead — the capitalized group matches the section heading — and click
its still-collapsed trigger. Also reverts the tab label to API.
Edit-mode runs the snippet in a blob: iframe whose base can't resolve
root-absolute paths, so a loader fetching "/IFKica-Regular.ttf" threw
"Failed to parse URL". Add the same <base href=origin/> the initial
bootstrap uses; module specifiers are already absolute, so only runtime
fetches are affected.
The bootstrap blob memos depended on editorTheme, so toggling the theme
regenerated the blob and reloaded the iframe — defeating the postTheme()
message that already updates color-scheme live. Read the theme untracked
when baking the HTML, and seed useSiteTheme from the real data-theme so
the initial bake is correct (no first-paint flash).
Show a hero-style progress line whenever an edit is recompiling/reloading.
Driven by a `compiling` signal set synchronously on input (outside the
startTransition that defers `hasEdited`), so it appears immediately and
covers the first-edit TS/Babel + dependency load, clearing on iframe load.
IFKica is only free for personal use; a public docs site redistributes
the font binary, which that license doesn't cover. Swap in the OFL
Zalando Sans Expanded (self-hosted .ttf, needed for letter-drop's
TTFLoader) across the @font-face, rubiks, tunnel, and letter-drop.
bigmistqke added 15 commits May 28, 2026 19:31
Replace the onMount class toggle (which walked up to the containing
<article> after first paint, causing a one-frame jump) with an
article:has(.hero) selector so the layout applies on first render.
Show the loading bar during the initial/reload load (compiling || iframeBusy)
instead of the separate pulsing circle, and remove its CSS + keyframes.
- Introduce <Entity from={Class}> as the fundamental wrapper before createT,
  and link both API references.
- Reserve callouts for genuine side-notes: createT brevity is a [!NOTE], the
  WebGPU support caveat becomes [!WARNING], and the T.Group blockquote reverts
  to inline demo narration.
- Note Entity mirrors Solid's <Dynamic> in the API reference.
- Style inline-code links with an accent border so they read as links.
…hing

Grid treadmill scroll + slow turntable orbit framing the duck; build the
extruded geometries declaratively (centered via the geometry ref); make the
eyes track the camera; smooth the teardrop body with Phong + higher
curveSegments.
Repurpose the gh-pages workflow to build and deploy the SolidStart site
(was the old demo), using the official Pages actions and triggering on
next. SolidStart v2's Vite-plugin architecture doesn't thread a deploy
base through manifest injection, SolidBase links, or the app head, so
add Vite base + nitro baseURL + Router base and a post-build pass that
prefixes root-absolute href/src in the prerendered HTML. Base lives in
one place (base.config.ts). Bump Node to 24 to run the .ts script.
typescript-eslint rejects a relative tsconfigRootDir, so every src file
failed to parse and was never linted. Point it at import.meta.dirname.
These were never enforced while the parser was misconfigured. Correct
LoaderTreeRegistry.get to return CacheNode | undefined (it always could),
which legitimises the existing not-found guards; drop redundant optional
chains on the get-or-create registry and the non-null TreeNode parent;
prefer-const and remove a no-op type assertion. Type/syntax only, no
runtime behavior change.
@bigmistqke
bigmistqke merged commit 54463cb into solidjs-community:next May 29, 2026
2 checks passed
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