Skip to content

Repository files navigation

Lab website

The static marketing, documentation, and playground frontend for the Lab programming language.

Stack

  • Vite
  • React and TypeScript
  • Tailwind CSS
  • pnpm

Development

pnpm install
pnpm dev

The production build is a static client application:

pnpm build
pnpm preview

The host must serve index.html as the fallback for client-side routes such as /docs and /playground.

Structure

  • src/pages/home-page.tsx: marketing page
  • src/pages/docs-page.tsx: documentation layout, sidebar, on-page TOC, pager
  • src/pages/playground-page.tsx: editable playground shell
  • src/components/: shared site and source-code presentation
  • src/data/examples.ts: representative Lab examples
  • src/content/docs/: documentation content, see below
  • src/lib/use-page-meta.ts: per-route title, description, canonical and card tags
  • public/brand/: brand assets, generated, see below

Brand assets

Everything under public/brand/, plus public/lab-mark.*, is generated by scripts/brand-assets.py from the geometry in that file. The output is committed, so regenerating is only needed when the mark or a wordmark changes:

python3 -m venv .venv
.venv/bin/pip install -r scripts/requirements.txt
.venv/bin/python scripts/brand-assets.py

It also needs rsvg-convert for the PNG exports (brew install librsvg) and an installed node_modules, since it reads Crimson Pro from the @fontsource-variable/crimson-pro package.

public/og/lab.png, the card a link to the site unfurls to, is generated the same way by scripts/og-images.py, which shares its typesetting with scripts/brandlib.py:

.venv/bin/python scripts/og-images.py

Do not hand-edit these files. The word in each wordmark is emitted as outlines rather than live text, so there is nothing editable in them anyway; that is deliberate, because librsvg synthesizes bold for a variable face instead of selecting its 600 instance and would otherwise set the PNG about a quarter wider than the SVG. The brand page at /brand documents what each asset is for.

Documentation content

Docs pages are .mdx files under src/content/docs/, discovered automatically: adding a file adds a page, no route or nav wiring required. Each starts with frontmatter:

---
title: The two arrows
eyebrow: Syntax
description: One-sentence dek shown under the page title.
group: Language guide
order: 50
---
  • title, eyebrow, description: rendered in the page header.
  • group: which sidebar section the page belongs to. Must match one of the names in GROUP_ORDER in src/lib/docs-content.ts; a new group needs a line added there.
  • order: sort key, both within a group and for the prev/next pager across the whole doc set. Leave gaps (10, 20, 30, …) so a page can be inserted later without renumbering its neighbors.

The page's URL is its file path relative to src/content/docs/, so guide/the-two-arrows.mdx serves at /docs/guide/the-two-arrows.

Search needs no wiring either. src/lib/remark-doc-search.ts splits each page at its headings during the MDX build and exports the plaintext as sections, which src/lib/docs-search.ts ranks; a new page is searchable as soon as it renders. Results deep-link to a heading, so anchors have to match: both the index and the rendered heading id come from slugify over the heading's full text, formatting included.

The body is ordinary Markdown: headings, lists, GFM tables, blockquotes, styled automatically to match the rest of the site by the component map in src/components/mdx-components.tsx. Two things need no special syntax:

  • A fenced code block's info string is its filename, and renders in the same bordered, dark "vessel" window used everywhere else on the site: ```lab reporter.lab. Omit it for an unlabeled window.
  • <Callout kind="note">…</Callout> reproduces the site's amber note box; kind="aside" is the neutral variant. Import it from ../../components/callout (or ../../../components/callout one level deeper); MDX files are plain modules, so this is a normal import.

Anything else bespoke a page needs can be authored as real JSX directly in the .mdx file, the same way. No content page should need dangerouslySetInnerHTML or a one-off page component; if a new visual pattern is needed on more than one page, add it to mdx-components.tsx or as a shared component instead of repeating the JSX per file.

Playground compiler integration

The playground runs the real compiler frontend in the browser. src/wasm/lab-ide-wasm/ holds a generated wasm-bindgen bundle of the lab-ide-wasm crate from the sibling Lab checkout, which wraps the same lab-ide workspace the LSP server uses. Diagnostics, document symbols, completions, hover, definition, references, rename, semantic tokens, and formatting are answered by the compiler, not by a JavaScript approximation of it.

src/lib/lab-engine/engine.ts is the only thing that touches the wasm module. LabEngine owns one LabWorkspace, keeps the last text set per path, and converts every span at the boundary: the Rust side is UTF-8 byte-offset native and CodeMirror is UTF-16 index native, so byte-offset.ts translates in both directions, including for spans returned against a file other than the active one. Every method is async even though the underlying calls are synchronous, so moving the workspace to a Web Worker stays an internal change. use-lab-engine.ts is the React binding, and src/components/playground/lab-editor.tsx is its only consumer.

The wasm bundle is committed, because there is no Rust toolchain at deploy time. Regenerate it with scripts/build-wasm.sh whenever lab-ide-wasm or its lab-ide/lab-language dependencies change, then commit the result:

LAB_REPO=/path/to/lab scripts/build-wasm.sh

The script defaults LAB_REPO to a sibling ../lab checkout, and fails with a remediation message if the wasm-bindgen CLI is missing, if its version does not match the crate version pinned in the Lab workspace's Cargo.lock, or if the wasm32-unknown-unknown target is not installed. Do not hand-edit anything under src/wasm/.

About

The website for the Lab programming language and compiler

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages