Specs / Reference

Playground

Playground — Standalone Demo Webapp

Status: spec only; implementation pending. The Playground is the public-facing demo that exercises every shipped block kind, mark, agent affordance, and access-control surface in one page — modeled after playground.lexical.dev. It is separate from the docs site and shipped as its own Cloudflare Pages project.

Why a separate app

ConcernWhy not fold into the docs site
Build cadenceDocs change with PRs; the Playground changes with editor releases. Different ship cadence, different reviewers.
Bundle profileThe Playground ships the full editor (Loro WASM, wa-sqlite WASM, tree-sitter parsers, every plugin). The docs site is content-first; bundling 1+ MB of WASM into every spec page is wrong.
Routing & statePlayground state (current demo doc, selected example, debug panel toggles, agent token) is rich and ephemeral; docs pages are static.
Cost & ownershipA separate CF Pages project gives the Playground its own deploy status, its own preview URLs, its own analytics, and its own bisect history.
Demonstration”Here is weaver running as its own app on Cloudflare Pages” is part of the pitch. The Playground is itself a reference deployment shape consumers will copy.

What it shows

The Playground is the answer to “show me the editor”. It exercises the entire v1 surface:

  1. A working editor instance populated with a curated demo doc (~50 blocks, every kind, every mark, nested lists, callouts, code blocks with multiple languages, a table, images, embeds, mentions).

  2. Example switcher — empty doc, demo doc, large doc (10 k blocks for perf demos), agent-collab demo (an agent peer running scripted edits), multi-tier doc (public / internal / confidential). Note on the agent demo: the agent runtime runs in-tab and the two LoroDoc peers exchange ops in-process. This is a demo-only simplification — production agents connect over WebSocket to the Durable Object as a separate peer (see ai-agent.md §2.1). The Playground demo shows the peer model, not the production transport.

  3. Live debug overlays (toggleable, off by default):

    • Block tree — collapsible view of LoroTree structure with per-node kind, attrs, child count.
    • Op log — recent Loro ops with origin, version vector delta, container target.
    • Version vector — current per-peer state.
    • Peer panel — connected peers (humans + agents) with presence cursor positions.
    • Subdoc map — which subdoc (a separate LoroDoc per access-control.md §5) each block belongs to; color-coded by membership.
    • Serialized state — JSON snapshot + binary update bytes (hex preview).
  4. Time travel — slider that calls doc.checkout(version) and re-renders.

  5. Agent demo controls — start/stop a scripted agent peer; “ask” panel that sends a prompt to a stub agent runtime.

  6. Theme switcher — light / dark, persisted in localStorage.

  7. Permalink?example=<id>&theme=<...>&debug=<...> so a URL captures the visible state.

  8. Self-host snippet — a copy-pasteable React snippet that instantiates the same editor configuration the demo uses. The thing a visitor wants after “this is cool” is “how do I get this in my app” — the snippet is the answer.

Explicitly out of scope:

  • Saving user content. No backend persistence for visitor edits; everything is LoroDoc in memory + localStorage for the active demo’s snapshot.
  • Authentication. The agent token in the agent demo is a hard-coded scoped Biscuit baked into the build with no real privileges.
  • Sync to a real Durable Object. The Playground runs the client + the agent runtime; sync is in-process between two LoroDoc peers in the same tab.

Deployment shape

ConcernChoice
HostCloudflare Pages
Project nameweaver-playground
Default URLhttps://weaver-playground.pages.dev
Custom domainweaver-playground.openhackers.club (per the ohc/<project> convention; one-time DNS step)
Repo locationapps/playground/ (sibling of apps/docs/)
Build frameworkVite + React (not Astro) — the Playground is an SPA, not a content site. Astro’s “islands” model fights the always-on editor surface.
OutputStatic SPA (apps/playground/dist) — same pages deploy shape as docs.
CI workflow.github/workflows/deploy-playground.yml — mirrors deploy-pages.yml but with --project-name=weaver-playground.
Required CF secretsReuses the existing CLOUDFLARE_API_TOKEN + CLOUDFLARE_ACCOUNT_ID repo secrets.
Build minutes budget< 90 s per deploy. WASM artifacts are pinned and cached.

Information architecture

/                       # main editor page; left = examples + debug controls, center = editor, right = side panels
/?example=<id>          # deep-link to an example
/?debug=tree,ops,vv     # comma-separated debug panel ids to enable
/embed/<example>        # bare editor for iframe embedding from third-party sites (no chrome)
/perf                   # perf microsite — runs the benchmark suite in-browser; results table
/about                  # one-page "what this is, link to docs, link to repo"

/perf is the bridge to benchmarks.md: the same suite the offline harness runs, but in the visitor’s browser, against a fixed set of reference docs.

What is needed before implementation starts

DependencyStatus todayBlocking?
@weaver/core shipping a usable editor buildPre-implementationYes
@weaver/react chrome (toolbar, slash menu, drag handle)Pre-implementationYes
At least one agent peer runtime that can be sandboxed in-tabPre-implementationYes — for the agent demo only
@weaver/wasm Loro + wa-sqlite bundlePre-implementationYes
Demo content seed corpusTBDYes; can be authored alongside the Playground
CF Pages project weaver-playground createdNot yetOne-line wrangler call when ready
DNS CNAME weaver-playground.openhackers.clubweaver-playground.pages.devNot yetWhen the custom domain is wanted

Outcome rubric

The Playground is shipped when the following criteria are independently gradeable as true by a reviewer who only sees the deployed https://weaver-playground.pages.dev:

Coverage

  • Every block kind listed in block-model.md §3 “Block kinds shipped in v1” is present at least once in the default demo doc.
  • Every mark listed in block-model.md §3 “Marks shipped in v1” is present at least once in the default demo doc.
  • The “large doc” example contains ≥ 10 000 blocks and reaches first paint within ≤ 1500 ms on the canonical machine defined in benchmarks.md §4.5.
  • The “agent-collab” example shows a visible second peer cursor with origin: agent-N on at least one streaming insertion.
  • The “multi-tier” example renders blocks that belong to at least three distinct subdocs (separate LoroDocs per access-control.md §5). Each subdoc’s blocks render with a distinct CSS border color visible in the DOM; a screenshot shows three distinct colors.

Debug overlays

  • Each of the six debug panels (block tree, op log, version vector, peer panel, subdoc map, serialized state) is independently toggleable via URL param and via UI.
  • The op log shows origin on every entry.
  • The version-vector panel’s displayed timestamp changes after a single keystroke within 200 ms (measured: subscribe to its text-content mutation; record the delta from the keydown event).
  • The time-travel slider, when scrubbed, re-renders the editor to the document state at that version with no console errors.

Self-host snippet

  • The “self-host” panel shows a React snippet that imports from @weaver/react and @weaver/core only — no Playground-internal modules.
  • The snippet is copyable with one button click.
  • Pasting the snippet into a fresh Vite + React app yields a working editor with the same default plugins as the Playground’s default-example configuration. (Reviewer test: run the snippet locally; verify the editor renders.)

Deployment

  • GET / returns 200 and the TLS cert presented for weaver-playground.pages.dev has notAfter ≥ 30 days from the day of the grader’s check.
  • The build size is ≤ 1.5 MB gzipped including WASM (docs site baseline is < 200 KB; the Playground is allowed more because of WASM).
  • The deploy workflow runs in ≤ 90 s wall-clock per push and is wired to the main branch.
  • A push that breaks the build leaves the previously-deployed version in place (Pages atomic deploy; no half-state).

Output quality

  • GET /, GET /perf, GET /about, GET /embed/<any-example-id>, and GET /?example=<each-example-id> all return 200.
  • Loading / and /perf in a clean Chromium produces zero console errors and zero uncaught promise rejections (verified via Page.on('pageerror') and Page.on('console') filtering error / warning).
  • The site is usable in a 1024-wide viewport without horizontal scroll.
  • An axe-core accessibility scan of / reports zero serious or critical violations.
  • The HTTP response for / carries Content-Security-Policy, Strict-Transport-Security, X-Content-Type-Options: nosniff, and Referrer-Policy headers (verified by curl -I).

Reproducibility

  • Anyone with the repo and the two CF secrets can pnpm install && pnpm --filter @weaver/playground build && wrangler pages deploy apps/playground/dist --project-name=weaver-playground and produce a deploy where (a) the set of emitted route paths is identical to CI’s artifact and (b) the SHA-256 of index.html equals CI’s artifact’s SHA-256.

See also