From 9bafb0f07393ac90ce87a46ba0731962c3a4888b Mon Sep 17 00:00:00 2001 From: Ronald Tse Date: Mon, 7 Sep 2026 15:18:30 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20/playground=20=E2=80=94=20the=20two-lay?= =?UTF-8?q?er=20stack,=20directly=20usable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Any of the 289 authority systems through the site worker, optional Arabic vocalization through the neural layer (lite int4 or 2.1 int8, download-once), shareable URL state, and a copyable TS snippet that mirrors the exact configuration using the published npm API. --- e2e/playground.spec.ts | 28 +++++ src/layouts/Base.astro | 1 + src/pages/playground.astro | 231 +++++++++++++++++++++++++++++++++++++ 3 files changed, 260 insertions(+) create mode 100644 e2e/playground.spec.ts create mode 100644 src/pages/playground.astro diff --git a/e2e/playground.spec.ts b/e2e/playground.spec.ts new file mode 100644 index 00000000..31ccd04b --- /dev/null +++ b/e2e/playground.spec.ts @@ -0,0 +1,28 @@ +// Playground — the two-layer stack client-side: golden path runs a real +// authority system through the worker (no model download in CI). +import { expect, test } from "@playwright/test" + +test("playground runs a deterministic system end-to-end", async ({ page }) => { + await page.goto("/playground") + await expect(page.getByRole("heading", { name: "Playground" })).toBeVisible() + await page.fill("#input", "Антон Павлович Чехов") + await page.fill("#filter", "bgnpcgn-rus") + await page.selectOption("#system", { index: 0 }) + await page.click("#run") + const out = page.locator("#output") + await expect(out).not.toBeEmpty({ timeout: 30_000 }) + await expect(out).toContainText("Anton") + // shareable URL carries the state + await expect(page).toHaveURL(/sys=bgnpcgn-rus/) + // the snippet mirrors the selected system + await expect(page.locator("#snippet")).toContainText("transliterateAsync") +}) + +test("filter narrows the system list", async ({ page }) => { + await page.goto("/playground") + await page.fill("#filter", "Thai") + const first = await page.locator("#system option").first().textContent() + expect(first).toBeTruthy() + const count = await page.locator("#system option").count() + expect(count).toBeLessThan(50) +}) diff --git a/src/layouts/Base.astro b/src/layouts/Base.astro index 8d6c6967..b88bb877 100644 --- a/src/layouts/Base.astro +++ b/src/layouts/Base.astro @@ -274,6 +274,7 @@ const slug = (label: string) => label.toLowerCase().replace(/\s+/g, "-")
  • Live transliteration
  • Map catalogue
  • Model catalogue
  • +
  • Playground
  • Neural demo
  • Authorities
  • Documentation
  • diff --git a/src/pages/playground.astro b/src/pages/playground.astro new file mode 100644 index 00000000..0323a1bd --- /dev/null +++ b/src/pages/playground.astro @@ -0,0 +1,231 @@ +--- +// Playground: the full two-layer stack in the browser — pick any of the +// 289 authority systems, optionally vocalize Arabic through the neural +// layer first, transliterate off-main-thread, share the state by URL, +// and copy the exact TS that does the same thing. +import Base from "../layouts/Base.astro" +import catalogue from "../data/maps-catalogue.json" + +const systems = Object.entries(catalogue as Record) + .map(([code, m]) => ({ code, name: m.data.name, lang: m.data.language })) + .sort((a, b) => a.name.localeCompare(b.name)) +--- + + +
    +

    Playground

    +

    + The whole stack runs in your browser: 289 authority systems, plus the + neural layer for the conversions no committee ever published. Nothing + leaves the page. +

    + +
    +
    + + + + + + + + + + + + +
    + +
    + + + + + + + +
    + +
    +
    +
    + + + + +