|
|
|
|
@@ -1,34 +1,42 @@
|
|
|
|
|
# GENOME.md — the-playground
|
|
|
|
|
|
|
|
|
|
Generated: 2026-04-15 00:19:15 EDT
|
|
|
|
|
Generated: 2026-04-17 10:00 UTC
|
|
|
|
|
Repo: Timmy_Foundation/the-playground
|
|
|
|
|
Issue: timmy-home #671
|
|
|
|
|
Analyzed commit: `142d77736de3b303ea5320dbd5dcfda99e59f325`
|
|
|
|
|
Host issue: timmy-home #671
|
|
|
|
|
|
|
|
|
|
## Project Overview
|
|
|
|
|
|
|
|
|
|
The Sovereign Playground is a browser-only creative sandbox: a dark, local-first art toy with an entrance ritual, a canvas in the center, a sound panel on the left, a gallery on the right, and a footer action bar for save/download/clear/fullscreen.
|
|
|
|
|
`the-playground` is a browser-first creative sandbox with a strong visual identity and a deliberately simple deployment model: open `index.html` or serve static files. It is not yet the full platform promised by the README. The current repo is a compact prototype shell with real interaction loops for sound, drawing, constellation play, gallery persistence, and export.
|
|
|
|
|
|
|
|
|
|
The current codebase is much smaller than the README vision. The README describes a platform with Sound Studio, Visual Forge, Gallery, Games Floor, Video Forge, and a long roadmap of immersive experiences. The code on `main` today implements a solid prototype shell with:
|
|
|
|
|
- a cinematic entrance screen
|
|
|
|
|
- two actual canvas modes: `free-draw` and `ambient`
|
|
|
|
|
- a basic Web Audio engine for notes/chords/scales
|
|
|
|
|
- a basic Canvas 2D visual engine
|
|
|
|
|
- an IndexedDB-backed gallery
|
|
|
|
|
- a manual browser smoke harness
|
|
|
|
|
|
|
|
|
|
Quick measured facts from the fresh main clone I analyzed:
|
|
|
|
|
- 10 JavaScript source files
|
|
|
|
|
Current measured facts from the fresh `main` archive I analyzed:
|
|
|
|
|
- 14 JavaScript source files
|
|
|
|
|
- 1 CSS design system file
|
|
|
|
|
- 2 HTML entry pages (`index.html`, `smoke-test.html`)
|
|
|
|
|
- 1 Python test module in the target repo (`tests/test_perf_budgets.py`)
|
|
|
|
|
- 0 package manifests
|
|
|
|
|
- 0 build steps
|
|
|
|
|
- `python3 -m pytest -q` -> `no tests ran in 0.02s`
|
|
|
|
|
- browser smoke harness shows 18 passing checks, but the summary is broken and still says `0 passed, 0 failed`
|
|
|
|
|
- `pytest -q` → `7 passed in 0.03s`
|
|
|
|
|
- no backend or network API in the shipped app shell
|
|
|
|
|
|
|
|
|
|
This repo is best understood as a browser-native prototype platform shell with one strong design language and three real cores:
|
|
|
|
|
1. orchestration in `src/playground.js`
|
|
|
|
|
What exists on `main` today:
|
|
|
|
|
- cinematic entrance screen
|
|
|
|
|
- three actual canvas/runtime modes:
|
|
|
|
|
- `free-draw`
|
|
|
|
|
- `ambient`
|
|
|
|
|
- `constellation`
|
|
|
|
|
- a Web Audio engine for notes/chords/scales
|
|
|
|
|
- a Canvas 2D visual engine
|
|
|
|
|
- an IndexedDB-backed gallery
|
|
|
|
|
- export helpers for WAV, single-item download, ZIP packaging, and standalone HTML export
|
|
|
|
|
- perf budget artifacts and a dormant runtime performance monitor
|
|
|
|
|
- a browser smoke harness plus one pytest module for perf budget/pipeline presence
|
|
|
|
|
|
|
|
|
|
This repo is best understood as four layers:
|
|
|
|
|
1. page shell + script-order runtime contract
|
|
|
|
|
2. browser engines (`PlaygroundAudio`, `PlaygroundVisual`, `PlaygroundGallery`)
|
|
|
|
|
3. thin shared globals (`PlaygroundUtils`, `PlaygroundState`, `PlaygroundEvents`, `ModeManager`)
|
|
|
|
|
3. experience/orchestration (`src/playground.js`, `ModeManager`, `constellation`)
|
|
|
|
|
4. export/perf sidecars that are only partially integrated into the live app
|
|
|
|
|
|
|
|
|
|
## Architecture
|
|
|
|
|
|
|
|
|
|
@@ -38,258 +46,237 @@ graph TD
|
|
|
|
|
HTML --> U[src/utils/utils.js]
|
|
|
|
|
HTML --> S[src/utils/state.js]
|
|
|
|
|
HTML --> E[src/utils/events.js]
|
|
|
|
|
HTML --> A[src/engine/audio-engine.js]
|
|
|
|
|
HTML --> V[src/engine/visual-engine.js]
|
|
|
|
|
HTML --> AE[src/engine/audio-engine.js]
|
|
|
|
|
HTML --> VE[src/engine/visual-engine.js]
|
|
|
|
|
HTML --> G[src/gallery/gallery.js]
|
|
|
|
|
HTML --> WAV[src/export/wav-encoder.js]
|
|
|
|
|
HTML --> EXP[src/export/download.js]
|
|
|
|
|
HTML --> SP[src/panels/sound/sound-panel.js]
|
|
|
|
|
HTML --> GP[src/panels/gallery/gallery-panel.js]
|
|
|
|
|
HTML --> M[src/modes/mode-manager.js]
|
|
|
|
|
HTML --> P[src/playground.js]
|
|
|
|
|
HTML --> MM[src/modes/mode-manager.js]
|
|
|
|
|
HTML --> CONST[src/modes/constellation.js]
|
|
|
|
|
HTML --> APP[src/playground.js]
|
|
|
|
|
|
|
|
|
|
P --> A
|
|
|
|
|
P --> V
|
|
|
|
|
P --> G
|
|
|
|
|
P --> SP
|
|
|
|
|
P --> GP
|
|
|
|
|
P --> M
|
|
|
|
|
P --> S
|
|
|
|
|
P --> E
|
|
|
|
|
P --> U
|
|
|
|
|
APP --> AE
|
|
|
|
|
APP --> VE
|
|
|
|
|
APP --> G
|
|
|
|
|
APP --> SP
|
|
|
|
|
APP --> GP
|
|
|
|
|
APP --> MM
|
|
|
|
|
APP --> U
|
|
|
|
|
APP --> S
|
|
|
|
|
APP --> E
|
|
|
|
|
GP --> EXP
|
|
|
|
|
EXP --> WAV
|
|
|
|
|
G --> IDB[(IndexedDB playground-gallery)]
|
|
|
|
|
AE --> AC[AudioContext]
|
|
|
|
|
VE --> CANVAS[Canvas 2D]
|
|
|
|
|
|
|
|
|
|
User[User interactions] --> P
|
|
|
|
|
P --> Canvas[Canvas 2D]
|
|
|
|
|
P --> Audio[AudioContext]
|
|
|
|
|
P --> DB[IndexedDB playground-gallery]
|
|
|
|
|
DB --> GP
|
|
|
|
|
SP --> A
|
|
|
|
|
M --> Canvas
|
|
|
|
|
Smoke[smoke-test.html] --> U
|
|
|
|
|
Smoke --> S
|
|
|
|
|
Smoke --> E
|
|
|
|
|
Smoke --> A
|
|
|
|
|
Smoke --> V
|
|
|
|
|
Smoke --> G
|
|
|
|
|
SMOKE[smoke-test.html] --> U
|
|
|
|
|
SMOKE --> S
|
|
|
|
|
SMOKE --> E
|
|
|
|
|
SMOKE --> AE
|
|
|
|
|
SMOKE --> VE
|
|
|
|
|
SMOKE --> G
|
|
|
|
|
|
|
|
|
|
PERF[src/utils/perf-monitor.js]
|
|
|
|
|
PERFTEST[tests/test_perf_budgets.py] --> PERF
|
|
|
|
|
PERFTEST --> PERFCFG[lighthouse-budget.json + .lighthouserc.json + .gitea/workflows/perf-check.yml]
|
|
|
|
|
HTML -. not loaded on main .-> PERF
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Entry Points
|
|
|
|
|
|
|
|
|
|
### `index.html`
|
|
|
|
|
The real application shell.
|
|
|
|
|
- loads `src/styles/design-system.css`
|
|
|
|
|
- renders the entrance curtain, header, panels, canvas, action bar, and toast container
|
|
|
|
|
- loads 10 classic `<script>` files in a strict dependency order
|
|
|
|
|
- has no framework, bundler, or module loader
|
|
|
|
|
The real product entry point.
|
|
|
|
|
|
|
|
|
|
Script order is the runtime contract:
|
|
|
|
|
Responsibilities:
|
|
|
|
|
- defines the entrance curtain
|
|
|
|
|
- defines header, left sound panel, center canvas, right gallery panel, and footer action bar
|
|
|
|
|
- loads global scripts in strict dependency order
|
|
|
|
|
- exposes no module loader or bundler boundary
|
|
|
|
|
|
|
|
|
|
Current runtime script order:
|
|
|
|
|
1. `src/utils/utils.js`
|
|
|
|
|
2. `src/utils/state.js`
|
|
|
|
|
3. `src/utils/events.js`
|
|
|
|
|
4. `src/engine/audio-engine.js`
|
|
|
|
|
5. `src/engine/visual-engine.js`
|
|
|
|
|
6. `src/gallery/gallery.js`
|
|
|
|
|
7. `src/panels/sound/sound-panel.js`
|
|
|
|
|
8. `src/panels/gallery/gallery-panel.js`
|
|
|
|
|
9. `src/modes/mode-manager.js`
|
|
|
|
|
10. `src/playground.js`
|
|
|
|
|
7. `src/export/wav-encoder.js`
|
|
|
|
|
8. `src/export/download.js`
|
|
|
|
|
9. `src/panels/sound/sound-panel.js`
|
|
|
|
|
10. `src/panels/gallery/gallery-panel.js`
|
|
|
|
|
11. `src/modes/mode-manager.js`
|
|
|
|
|
12. `src/modes/constellation.js`
|
|
|
|
|
13. `src/playground.js`
|
|
|
|
|
|
|
|
|
|
Because everything is loaded as globals, this order matters. `src/playground.js` assumes the prior globals already exist.
|
|
|
|
|
Important truth: `src/utils/perf-monitor.js` exists in the repo but is not loaded by `index.html` on current `main`.
|
|
|
|
|
|
|
|
|
|
### `src/playground.js`
|
|
|
|
|
The orchestration nucleus.
|
|
|
|
|
Responsibilities:
|
|
|
|
|
- entrance particle animation
|
|
|
|
|
- enter transition
|
|
|
|
|
- engine construction and initialization
|
|
|
|
|
- canvas sizing
|
|
|
|
|
- gallery boot
|
|
|
|
|
- sound panel boot
|
|
|
|
|
- ambient particle loop
|
|
|
|
|
- mode registration
|
|
|
|
|
- save/download/clear/fullscreen button wiring
|
|
|
|
|
- panel toggle wiring
|
|
|
|
|
- keyboard shortcut wiring
|
|
|
|
|
|
|
|
|
|
If you want to know what the product actually does today, this is the file.
|
|
|
|
|
What it does today:
|
|
|
|
|
- entrance particle system and enter transition
|
|
|
|
|
- engine construction and initialization
|
|
|
|
|
- default ambient animation loop
|
|
|
|
|
- mode registration and selector rendering
|
|
|
|
|
- canvas resizing
|
|
|
|
|
- gallery initialization and rerender after saves
|
|
|
|
|
- save/download/clear/fullscreen button wiring
|
|
|
|
|
- footer prompt handling and keyboard shortcuts
|
|
|
|
|
|
|
|
|
|
This file is the clearest statement of what the app actually is right now.
|
|
|
|
|
|
|
|
|
|
### `smoke-test.html`
|
|
|
|
|
The only real automated harness shipped in the target repo.
|
|
|
|
|
- dynamically loads a subset of source files
|
|
|
|
|
- performs 18 browser assertions around utils/state/events/audio/visual/gallery
|
|
|
|
|
- writes green/red lines into the DOM
|
|
|
|
|
- currently has a broken summary counter
|
|
|
|
|
Browser smoke harness.
|
|
|
|
|
- loads a subset of runtime files directly
|
|
|
|
|
- runs assertions in the browser DOM
|
|
|
|
|
- provides manual high-signal sanity checks around utils/state/events/audio/visual/gallery
|
|
|
|
|
|
|
|
|
|
### Engine modules
|
|
|
|
|
- `src/engine/audio-engine.js`
|
|
|
|
|
- Web Audio wrapper for notes, chords, scales, note playback, and chord playback
|
|
|
|
|
- `src/engine/visual-engine.js`
|
|
|
|
|
- Canvas wrapper for resize, clear, line/circle drawing, seeded palette generation, and placeholder noise
|
|
|
|
|
- `src/gallery/gallery.js`
|
|
|
|
|
- IndexedDB persistence layer
|
|
|
|
|
### `tests/test_perf_budgets.py`
|
|
|
|
|
The only pytest module in the target repo.
|
|
|
|
|
|
|
|
|
|
### Panel / mode modules
|
|
|
|
|
- `src/panels/sound/sound-panel.js`
|
|
|
|
|
- renders sound controls and quick-play chord UI
|
|
|
|
|
- `src/panels/gallery/gallery-panel.js`
|
|
|
|
|
- renders gallery thumbnails and empty state
|
|
|
|
|
- `src/modes/mode-manager.js`
|
|
|
|
|
- registry/switcher for canvas modes
|
|
|
|
|
What it verifies:
|
|
|
|
|
- existence of `src/utils/perf-monitor.js`
|
|
|
|
|
- existence of `lighthouse-budget.json`
|
|
|
|
|
- existence of `.lighthouserc.json`
|
|
|
|
|
- existence of `.gitea/workflows/perf-check.yml`
|
|
|
|
|
- very shallow content checks for the perf monitor and perf workflow artifacts
|
|
|
|
|
|
|
|
|
|
## Data Flow
|
|
|
|
|
|
|
|
|
|
### App boot flow
|
|
|
|
|
### Boot flow
|
|
|
|
|
1. Browser opens `index.html`.
|
|
|
|
|
2. CSS design system establishes the entire visual identity.
|
|
|
|
|
3. Utility/state/event globals load.
|
|
|
|
|
4. Audio, visual, gallery, panel, and mode globals load.
|
|
|
|
|
5. `src/playground.js` runs immediately in an IIFE.
|
|
|
|
|
6. The entrance screen appears with animated gold particles.
|
|
|
|
|
7. User clicks `Enter` or presses any key.
|
|
|
|
|
8. `enterPlayground()`:
|
|
|
|
|
- fades the entrance out
|
|
|
|
|
- creates and initializes `PlaygroundAudio`
|
|
|
|
|
- reveals the playground
|
|
|
|
|
- calls `initPlayground()`
|
|
|
|
|
- plays a welcome chord
|
|
|
|
|
2. CSS establishes the gold-on-dark design system.
|
|
|
|
|
3. utility/state/events globals load.
|
|
|
|
|
4. engine/gallery/export/panel/mode globals load.
|
|
|
|
|
5. `src/playground.js` runs in an IIFE.
|
|
|
|
|
6. entrance screen shows animated particles.
|
|
|
|
|
7. user clicks `Enter` or presses a key.
|
|
|
|
|
8. `enterPlayground()` fades out entrance, initializes audio, reveals the app shell, and starts the playground.
|
|
|
|
|
|
|
|
|
|
### Main interaction flow
|
|
|
|
|
1. `initPlayground()` creates `PlaygroundVisual(canvas)`.
|
|
|
|
|
2. Canvas is resized to the container.
|
|
|
|
|
3. `PlaygroundGallery` opens IndexedDB and initializes the gallery panel.
|
|
|
|
|
4. `SoundPanel.init(audioEngine)` renders the left control surface.
|
|
|
|
|
5. `ModeManager.register()` adds two modes:
|
|
|
|
|
- `free-draw`
|
|
|
|
|
- `ambient`
|
|
|
|
|
6. `ModeManager.renderSelector()` creates mode buttons.
|
|
|
|
|
7. `ModeManager.switch('ambient')` makes the experience feel alive on load.
|
|
|
|
|
### Core interaction flow
|
|
|
|
|
1. `PlaygroundVisual` binds the canvas.
|
|
|
|
|
2. `PlaygroundGallery` opens IndexedDB.
|
|
|
|
|
3. `SoundPanel.init(audioEngine)` renders the left-side sound UI.
|
|
|
|
|
4. `GalleryPanel.init(galleryEngine)` renders the right-side gallery UI.
|
|
|
|
|
5. `ModeManager` registers available modes and renders selector buttons.
|
|
|
|
|
6. ambient mode starts by default; draw and constellation can be selected.
|
|
|
|
|
|
|
|
|
|
### Draw mode flow
|
|
|
|
|
1. User switches to `Draw`.
|
|
|
|
|
2. `free-draw.init()` binds mouse and touch listeners.
|
|
|
|
|
3. Pointer movement draws lines on the canvas via `visualEngine.drawLine()`.
|
|
|
|
|
4. X-position is mapped to frequency with `PlaygroundUtils.map()`.
|
|
|
|
|
5. `audioEngine.play()` emits short sine notes while drawing.
|
|
|
|
|
6. The first interaction hides the “Click anywhere to begin” prompt.
|
|
|
|
|
### Draw/save/export flow
|
|
|
|
|
1. user draws or interacts in a mode.
|
|
|
|
|
2. save path converts canvas to a blob/data URL.
|
|
|
|
|
3. `PlaygroundGallery.save()` writes a gallery item into IndexedDB.
|
|
|
|
|
4. `gallery:item-saved` fires on the event bus.
|
|
|
|
|
5. `GalleryPanel` rerenders.
|
|
|
|
|
6. download path exports the canvas PNG and a JSON metadata sidecar.
|
|
|
|
|
7. gallery panel can also invoke `PlaygroundExport.downloadItem()` for persisted items.
|
|
|
|
|
|
|
|
|
|
### Save/export flow
|
|
|
|
|
1. User clicks `Save`.
|
|
|
|
|
2. Canvas is converted to PNG via `canvas.toBlob()`.
|
|
|
|
|
3. `FileReader` converts the blob to a data URL.
|
|
|
|
|
4. `galleryEngine.save()` writes an object into IndexedDB with:
|
|
|
|
|
- `id`
|
|
|
|
|
- `created`
|
|
|
|
|
- `modified`
|
|
|
|
|
- `type`
|
|
|
|
|
- `name`
|
|
|
|
|
- `data`
|
|
|
|
|
- `mimeType`
|
|
|
|
|
- `thumbnail`
|
|
|
|
|
- `metadata.mode`
|
|
|
|
|
5. `gallery:item-saved` fires on the event bus.
|
|
|
|
|
6. `GalleryPanel` rerenders.
|
|
|
|
|
### Constellation mode flow
|
|
|
|
|
1. `ModeManager.switch('constellation')` activates `src/modes/constellation.js`.
|
|
|
|
|
2. stars are created and drawn on the canvas.
|
|
|
|
|
3. drag events move stars.
|
|
|
|
|
4. close-distance interactions trigger pentatonic notes and an ambient drone.
|
|
|
|
|
5. teardown removes listeners and fades out drone oscillators.
|
|
|
|
|
|
|
|
|
|
### Gallery render flow
|
|
|
|
|
1. `GalleryPanel.render()` calls `gallery.getAll()`.
|
|
|
|
|
2. Results are sorted newest-first by ISO timestamp.
|
|
|
|
|
3. Gallery HTML is rebuilt via `innerHTML`.
|
|
|
|
|
4. Clicking a thumb currently only shows a toast with the item id prefix.
|
|
|
|
|
- there is no real open/view/edit flow yet
|
|
|
|
|
|
|
|
|
|
### Download flow
|
|
|
|
|
1. User clicks `Download`.
|
|
|
|
|
2. Canvas blob is created.
|
|
|
|
|
3. `PlaygroundUtils.downloadBlob()` synthesizes an `<a download>` link.
|
|
|
|
|
4. Browser downloads a PNG snapshot.
|
|
|
|
|
### Metrics synthesis flow (current state)
|
|
|
|
|
1. perf budget artifacts exist in the repo.
|
|
|
|
|
2. `tests/test_perf_budgets.py` proves those files exist.
|
|
|
|
|
3. `PerfMonitor` can emit paint/layout/long-task/memory signals.
|
|
|
|
|
4. but the live app never loads or starts it, so there is no real runtime metric emission on `main`.
|
|
|
|
|
|
|
|
|
|
## Key Abstractions
|
|
|
|
|
|
|
|
|
|
### `PlaygroundUtils`
|
|
|
|
|
A tiny global helpers object.
|
|
|
|
|
Important methods:
|
|
|
|
|
- `uuid()` -> `crypto.randomUUID()`
|
|
|
|
|
Small browser helper surface:
|
|
|
|
|
- `uuid()`
|
|
|
|
|
- `clamp()`
|
|
|
|
|
- `lerp()`
|
|
|
|
|
- `map()`
|
|
|
|
|
- `toast()`
|
|
|
|
|
- `downloadBlob()`
|
|
|
|
|
|
|
|
|
|
It is intentionally small, but it is depended on by multiple subsystems.
|
|
|
|
|
|
|
|
|
|
### `PlaygroundState`
|
|
|
|
|
A global mutable state container with sections for:
|
|
|
|
|
- `canvas`
|
|
|
|
|
- `audio`
|
|
|
|
|
- `gallery`
|
|
|
|
|
- `ui`
|
|
|
|
|
- `recording`
|
|
|
|
|
Global mutable state bucket for:
|
|
|
|
|
- canvas
|
|
|
|
|
- audio
|
|
|
|
|
- gallery
|
|
|
|
|
- UI
|
|
|
|
|
- recording
|
|
|
|
|
|
|
|
|
|
It behaves more like a convenience registry than a true source-of-truth store. Real durable gallery data lives in IndexedDB, not here.
|
|
|
|
|
It is a convenience registry, not a durable data store.
|
|
|
|
|
|
|
|
|
|
### `PlaygroundEvents`
|
|
|
|
|
A minimal event bus:
|
|
|
|
|
Minimal event bus:
|
|
|
|
|
- `on(event, fn)`
|
|
|
|
|
- `emit(event, data)`
|
|
|
|
|
- `off(event, fn)`
|
|
|
|
|
|
|
|
|
|
This is the main loose-coupling seam across modules.
|
|
|
|
|
|
|
|
|
|
### `PlaygroundAudio`
|
|
|
|
|
A lightweight music engine over `AudioContext`.
|
|
|
|
|
Capabilities:
|
|
|
|
|
- note-name to frequency conversion
|
|
|
|
|
- chord construction
|
|
|
|
|
- scale construction
|
|
|
|
|
- one-shot oscillator playback
|
|
|
|
|
Web Audio wrapper for:
|
|
|
|
|
- note → frequency mapping
|
|
|
|
|
- chord generation
|
|
|
|
|
- scale generation
|
|
|
|
|
- oscillator playback
|
|
|
|
|
- chord playback
|
|
|
|
|
- analyser wiring for future visualization/reactivity
|
|
|
|
|
|
|
|
|
|
### `PlaygroundVisual`
|
|
|
|
|
A minimal canvas wrapper.
|
|
|
|
|
Capabilities:
|
|
|
|
|
- resize canvas and bind context into `PlaygroundState`
|
|
|
|
|
- clear canvas
|
|
|
|
|
- draw lines and circles
|
|
|
|
|
- deterministic palette generation from a seed
|
|
|
|
|
- placeholder pseudo-noise function (`perlin2d`, not real Perlin)
|
|
|
|
|
Canvas wrapper for:
|
|
|
|
|
- resize
|
|
|
|
|
- clear
|
|
|
|
|
- drawLine
|
|
|
|
|
- drawCircle
|
|
|
|
|
- seeded palette generation
|
|
|
|
|
- placeholder pseudo-noise helper
|
|
|
|
|
|
|
|
|
|
### `PlaygroundGallery`
|
|
|
|
|
A thin IndexedDB repository.
|
|
|
|
|
Contract:
|
|
|
|
|
IndexedDB repository:
|
|
|
|
|
- DB name: `playground-gallery`
|
|
|
|
|
- store: `items`
|
|
|
|
|
- object store: `items`
|
|
|
|
|
- indexes: `type`, `collection`, `created`
|
|
|
|
|
- CRUD methods:
|
|
|
|
|
- `init()`
|
|
|
|
|
- `save(item)`
|
|
|
|
|
- `getById(id)`
|
|
|
|
|
- `getAll()`
|
|
|
|
|
- `deleteItem(id)`
|
|
|
|
|
- methods: `init`, `save`, `getById`, `getAll`, `deleteItem`
|
|
|
|
|
|
|
|
|
|
### `ModeManager`
|
|
|
|
|
A registry + switcher for canvas modes.
|
|
|
|
|
It holds:
|
|
|
|
|
- `modes`
|
|
|
|
|
- `current`
|
|
|
|
|
Registry/switcher for canvas experiences:
|
|
|
|
|
- `register()`
|
|
|
|
|
- `switch()`
|
|
|
|
|
- `renderSelector()`
|
|
|
|
|
- `current`
|
|
|
|
|
- `modes`
|
|
|
|
|
|
|
|
|
|
This is the intended extension point for future experiences.
|
|
|
|
|
### `PlaygroundExport`
|
|
|
|
|
Download/export sidecar for:
|
|
|
|
|
- single item download
|
|
|
|
|
- metadata sidecars
|
|
|
|
|
- batch ZIP export
|
|
|
|
|
- standalone HTML gallery export
|
|
|
|
|
|
|
|
|
|
### `SoundPanel` and `GalleryPanel`
|
|
|
|
|
These are rendering adapters that convert state/engine methods into DOM UI.
|
|
|
|
|
They keep the app readable by not putting every DOM template inside `src/playground.js`.
|
|
|
|
|
### `PlaygroundWavEncoder`
|
|
|
|
|
AudioBuffer → WAV blob encoder used by export paths.
|
|
|
|
|
|
|
|
|
|
### `PerfMonitor`
|
|
|
|
|
Dormant runtime performance monitor for:
|
|
|
|
|
- FCP/LCP
|
|
|
|
|
- CLS
|
|
|
|
|
- long tasks
|
|
|
|
|
- memory polling
|
|
|
|
|
|
|
|
|
|
Useful code, but currently disconnected from the product entrypoint.
|
|
|
|
|
|
|
|
|
|
## API Surface
|
|
|
|
|
|
|
|
|
|
This repo has no network API. Its API surface is an in-browser global surface.
|
|
|
|
|
This repo has no network API. The public surface is browser globals plus IndexedDB object contracts.
|
|
|
|
|
|
|
|
|
|
### Browser globals exposed by load order
|
|
|
|
|
### Browser globals exposed on `main`
|
|
|
|
|
- `PlaygroundUtils`
|
|
|
|
|
- `PlaygroundState`
|
|
|
|
|
- `PlaygroundEvents`
|
|
|
|
|
- `PlaygroundAudio`
|
|
|
|
|
- `PlaygroundVisual`
|
|
|
|
|
- `PlaygroundGallery`
|
|
|
|
|
- `PlaygroundWavEncoder`
|
|
|
|
|
- `PlaygroundExport`
|
|
|
|
|
- `SoundPanel`
|
|
|
|
|
- `GalleryPanel`
|
|
|
|
|
- `ModeManager`
|
|
|
|
|
@@ -303,8 +290,8 @@ Observed event names:
|
|
|
|
|
- `canvas:mode-changed`
|
|
|
|
|
- `playground:ready`
|
|
|
|
|
|
|
|
|
|
### IndexedDB object contract
|
|
|
|
|
Saved gallery items can contain:
|
|
|
|
|
### Gallery item contract
|
|
|
|
|
Persisted items can include:
|
|
|
|
|
- `id`
|
|
|
|
|
- `created`
|
|
|
|
|
- `modified`
|
|
|
|
|
@@ -314,9 +301,10 @@ Saved gallery items can contain:
|
|
|
|
|
- `mimeType`
|
|
|
|
|
- `thumbnail`
|
|
|
|
|
- `metadata`
|
|
|
|
|
- sometimes audio/video-specific fields consumed by export helpers
|
|
|
|
|
|
|
|
|
|
### UI control contract
|
|
|
|
|
Important DOM ids and commands:
|
|
|
|
|
### UI command surface
|
|
|
|
|
Important DOM ids:
|
|
|
|
|
- `btn-save`
|
|
|
|
|
- `btn-download`
|
|
|
|
|
- `btn-clear`
|
|
|
|
|
@@ -326,127 +314,78 @@ Important DOM ids and commands:
|
|
|
|
|
- `gallery-content`
|
|
|
|
|
- `playground-canvas`
|
|
|
|
|
|
|
|
|
|
Keyboard shortcuts implemented today:
|
|
|
|
|
- `Ctrl+S` -> Save
|
|
|
|
|
- `Ctrl+D` -> Download
|
|
|
|
|
- `F11` -> Fullscreen
|
|
|
|
|
- `Escape` -> exit fullscreen
|
|
|
|
|
Keyboard shortcuts implemented on `main`:
|
|
|
|
|
- `Ctrl+S` → Save
|
|
|
|
|
- `Ctrl+D` → Download
|
|
|
|
|
- `F11` → Fullscreen
|
|
|
|
|
- `Escape` → exit fullscreen
|
|
|
|
|
|
|
|
|
|
## Test Coverage Gaps
|
|
|
|
|
|
|
|
|
|
### Current state
|
|
|
|
|
What I verified on a fresh clone of `main`:
|
|
|
|
|
- `find src -name '*.js' -print0 | xargs -0 -n1 node --check` -> passes
|
|
|
|
|
- `python3 -m pytest -q` -> `no tests ran in 0.02s`
|
|
|
|
|
- `smoke-test.html` runs 18 browser assertions successfully
|
|
|
|
|
- but `smoke-test.html` reports `0 passed, 0 failed` in the summary even while showing 18 green checks
|
|
|
|
|
What I verified on a fresh `main` archive:
|
|
|
|
|
- `pytest -q` → `7 passed in 0.03s`
|
|
|
|
|
- there is exactly one pytest module: `tests/test_perf_budgets.py`
|
|
|
|
|
- no JS unit-test harness
|
|
|
|
|
- no package manifest
|
|
|
|
|
- browser smoke harness still exists, but it is not the same thing as CI-grade coverage
|
|
|
|
|
|
|
|
|
|
This means the repo has a manual browser smoke harness, but no real automated CI-grade test suite.
|
|
|
|
|
### What is covered today
|
|
|
|
|
- presence/shape of perf budget artifacts
|
|
|
|
|
- presence of the perf monitor file
|
|
|
|
|
- presence of the perf check workflow
|
|
|
|
|
- smoke-test manual coverage around utils/state/events/audio/visual/gallery (browser harness, not pytest)
|
|
|
|
|
|
|
|
|
|
### What is covered by `smoke-test.html`
|
|
|
|
|
- UUID/clamp/lerp helpers
|
|
|
|
|
- default state and snapshot
|
|
|
|
|
- event bus firing
|
|
|
|
|
- AudioContext construction and music theory helpers
|
|
|
|
|
- canvas visual primitives and deterministic palette generation
|
|
|
|
|
- IndexedDB save/getAll/getById/delete flow
|
|
|
|
|
|
|
|
|
|
### What is not covered and should be
|
|
|
|
|
### Critical uncovered paths
|
|
|
|
|
1. `src/playground.js` orchestration
|
|
|
|
|
- entrance flow
|
|
|
|
|
- mode registration
|
|
|
|
|
- action bar wiring
|
|
|
|
|
- initialization sequence
|
|
|
|
|
- action-bar wiring
|
|
|
|
|
- keyboard shortcuts
|
|
|
|
|
- panel toggles
|
|
|
|
|
2. `src/export/download.js`
|
|
|
|
|
- single-item export
|
|
|
|
|
- ZIP export
|
|
|
|
|
- standalone HTML export
|
|
|
|
|
3. `src/export/wav-encoder.js`
|
|
|
|
|
- WAV blob correctness
|
|
|
|
|
4. `src/modes/constellation.js`
|
|
|
|
|
- drag lifecycle
|
|
|
|
|
- teardown correctness
|
|
|
|
|
- audio interaction contract
|
|
|
|
|
5. gallery interaction behavior
|
|
|
|
|
- open/view flow
|
|
|
|
|
- item count updates
|
|
|
|
|
- HTML escaping and render safety
|
|
|
|
|
|
|
|
|
|
2. `ModeManager`
|
|
|
|
|
- teardown/init switching order
|
|
|
|
|
- active button state
|
|
|
|
|
- event emission correctness
|
|
|
|
|
|
|
|
|
|
3. `SoundPanel`
|
|
|
|
|
- BPM slider updates state
|
|
|
|
|
- quality button activation
|
|
|
|
|
- chord button actually invokes audio engine
|
|
|
|
|
- volume slider is rendered but currently unwired
|
|
|
|
|
|
|
|
|
|
4. `GalleryPanel`
|
|
|
|
|
- empty/non-empty rendering
|
|
|
|
|
- item-count text updates
|
|
|
|
|
- click behavior
|
|
|
|
|
- escaping/sanitization of item fields before `innerHTML`
|
|
|
|
|
|
|
|
|
|
5. cross-module browser integration
|
|
|
|
|
- draw mode pointer lifecycle
|
|
|
|
|
- touch behavior
|
|
|
|
|
- fullscreen and download wiring
|
|
|
|
|
- prompt fade-out on first interaction
|
|
|
|
|
|
|
|
|
|
### Generated missing tests for critical paths
|
|
|
|
|
|
|
|
|
|
#### A. Mode switching contract test
|
|
|
|
|
A Node+VM or browser test should verify teardown/init ordering and active button state.
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
# pseudo-test idea
|
|
|
|
|
# load utils/state/events/mode-manager
|
|
|
|
|
# register two fake modes with counters
|
|
|
|
|
# switch twice
|
|
|
|
|
# assert first teardown ran before second init
|
|
|
|
|
# assert PlaygroundState.canvas.mode updated
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### B. Smoke summary correctness test
|
|
|
|
|
The current smoke harness is lying about pass/fail totals.
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
# browser-level assertion
|
|
|
|
|
# after smoke-test.html finishes,
|
|
|
|
|
# count the green result rows and compare them to the h2 summary
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### C. GalleryPanel XSS regression test
|
|
|
|
|
`GalleryPanel.render()` builds markup with `innerHTML` from gallery item data.
|
|
|
|
|
That should be locked down with a test before the panel grows more capable.
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
# save item with name containing HTML-like content
|
|
|
|
|
# render gallery
|
|
|
|
|
# assert rendered text is escaped / inert
|
|
|
|
|
# assert no unexpected nodes/scripts are created
|
|
|
|
|
```
|
|
|
|
|
### Filed from this analysis
|
|
|
|
|
- the-playground #247 — PerfMonitor ships but is never loaded or started on `main`
|
|
|
|
|
- the-playground #248 — batch export loads JSZip from CDN, violating zero-dependency/local-first posture
|
|
|
|
|
|
|
|
|
|
## Security Considerations
|
|
|
|
|
|
|
|
|
|
### Strengths
|
|
|
|
|
- zero network/API attack surface in the app itself
|
|
|
|
|
- no dependency tree or third-party script loaders
|
|
|
|
|
- local-first persistence using IndexedDB instead of remote storage
|
|
|
|
|
- deterministic, transparent runtime based on classic script tags
|
|
|
|
|
- reduced-motion CSS support already present
|
|
|
|
|
### Strong points
|
|
|
|
|
- no backend/API attack surface in the shipped app
|
|
|
|
|
- local-first IndexedDB persistence
|
|
|
|
|
- static hosting posture is simple and inspectable
|
|
|
|
|
- no npm dependency tree on current `main`
|
|
|
|
|
|
|
|
|
|
### Risks and caveats
|
|
|
|
|
1. `innerHTML` is used in multiple modules.
|
|
|
|
|
- `ModeManager.renderSelector()` builds buttons with `innerHTML`
|
|
|
|
|
- `SoundPanel.render()` builds control markup with `innerHTML`
|
|
|
|
|
- `GalleryPanel.render()` builds gallery thumbnails with `innerHTML`
|
|
|
|
|
- The first two are fed by trusted in-repo data.
|
|
|
|
|
- `GalleryPanel.render()` is the risky one because it interpolates gallery item data (`item.name`, `item.thumbnail`) coming back from IndexedDB.
|
|
|
|
|
|
|
|
|
|
2. Browser capability assumptions are strong.
|
|
|
|
|
- `crypto.randomUUID()`
|
|
|
|
|
- `AudioContext`
|
|
|
|
|
- `indexedDB`
|
|
|
|
|
- `canvas.toBlob()`
|
|
|
|
|
### Risks
|
|
|
|
|
1. `innerHTML` remains a major sink surface
|
|
|
|
|
- gallery rendering is the riskiest because it interpolates persisted item data
|
|
|
|
|
- related issues already exist in the target repo
|
|
|
|
|
2. dynamic third-party script load in export path
|
|
|
|
|
- `PlaygroundExport._loadJSZip()` injects a CDN script tag for JSZip
|
|
|
|
|
- this breaks the repo's own zero-dependency/local-first claim
|
|
|
|
|
3. dormant perf monitoring path
|
|
|
|
|
- monitoring code exists but is not in the runtime path
|
|
|
|
|
- repo can give a false sense of observability
|
|
|
|
|
4. browser capability assumptions remain strong
|
|
|
|
|
- IndexedDB
|
|
|
|
|
- AudioContext
|
|
|
|
|
- Fullscreen API
|
|
|
|
|
- FileReader
|
|
|
|
|
- all are required for the best path
|
|
|
|
|
|
|
|
|
|
3. No storage limits or cleanup policy.
|
|
|
|
|
- IndexedDB can grow without quotas or cleanup UX inside the app
|
|
|
|
|
- saved images are stored as data URLs, which can become heavy over time
|
|
|
|
|
|
|
|
|
|
4. No CSP/integrity story because the repo assumes direct static hosting or file-open execution.
|
|
|
|
|
- Blob/FileReader
|
|
|
|
|
- `crypto.randomUUID()`
|
|
|
|
|
|
|
|
|
|
## Dependencies
|
|
|
|
|
|
|
|
|
|
@@ -461,79 +400,51 @@ That should be locked down with a test before the panel grows more capable.
|
|
|
|
|
- standard DOM APIs
|
|
|
|
|
|
|
|
|
|
### Project/tooling dependencies
|
|
|
|
|
- none declared
|
|
|
|
|
- no `package.json`
|
|
|
|
|
- no `requirements.txt`
|
|
|
|
|
- no build tooling
|
|
|
|
|
- no CI workflow files on `main`
|
|
|
|
|
- no bundler
|
|
|
|
|
- no build step
|
|
|
|
|
- one pytest-based perf artifact check
|
|
|
|
|
- one browser smoke harness
|
|
|
|
|
|
|
|
|
|
### Verification tools used during analysis
|
|
|
|
|
- `node --check` for JS syntax verification
|
|
|
|
|
- browser execution of `smoke-test.html`
|
|
|
|
|
- `pytest` baseline probe, which confirmed there is no Python test suite in this target repo
|
|
|
|
|
### External runtime dependency discovered
|
|
|
|
|
- JSZip from CDN in `src/export/download.js` for batch ZIP export
|
|
|
|
|
|
|
|
|
|
## Deployment
|
|
|
|
|
|
|
|
|
|
The deployment model is intentionally trivial.
|
|
|
|
|
Current deployment model is still very simple:
|
|
|
|
|
- open `index.html` directly in a browser
|
|
|
|
|
- or serve the repo as static files from any web server
|
|
|
|
|
|
|
|
|
|
How to run it today:
|
|
|
|
|
- open `index.html` in a browser
|
|
|
|
|
- or serve the repo as static files from any plain web server
|
|
|
|
|
|
|
|
|
|
There is no backend, no API contract, no environment variables, and no deployment automation in the target repo.
|
|
|
|
|
|
|
|
|
|
Practical verification flow:
|
|
|
|
|
1. `find src -name '*.js' -print0 | xargs -0 -n1 node --check`
|
|
|
|
|
2. open `smoke-test.html`
|
|
|
|
|
3. open `index.html`
|
|
|
|
|
4. click `Enter`
|
|
|
|
|
5. verify:
|
|
|
|
|
- entrance transition
|
|
|
|
|
- ambient mode active by default
|
|
|
|
|
- sound panel playable
|
|
|
|
|
- save creates a gallery item in IndexedDB
|
|
|
|
|
- download exports a PNG
|
|
|
|
|
Verification flow I used:
|
|
|
|
|
1. inspect `index.html` script contract
|
|
|
|
|
2. run `pytest -q` in the target repo
|
|
|
|
|
3. inspect critical mode/export/perf files directly
|
|
|
|
|
4. compare live repo state to the existing genome artifact
|
|
|
|
|
|
|
|
|
|
## Technical Debt
|
|
|
|
|
|
|
|
|
|
### Highest-priority debt
|
|
|
|
|
1. README vision vs code reality gap
|
|
|
|
|
- the README describes a much larger platform than the current implementation
|
|
|
|
|
- mainline code today is a polished shell plus two real modes
|
|
|
|
|
|
|
|
|
|
2. No real automated test suite
|
|
|
|
|
- `python3 -m pytest -q` returns `no tests ran`
|
|
|
|
|
- the only harness is `smoke-test.html`
|
|
|
|
|
- the smoke harness summary is already broken
|
|
|
|
|
|
|
|
|
|
3. `GalleryPanel.render()` trusts item data too much
|
|
|
|
|
- direct `innerHTML` interpolation of stored item fields is a future XSS footgun
|
|
|
|
|
|
|
|
|
|
4. Global load-order coupling
|
|
|
|
|
- every major module assumes previous globals are already loaded
|
|
|
|
|
- there is no module isolation or dependency enforcement beyond script order
|
|
|
|
|
|
|
|
|
|
5. Volume slider is fake right now
|
|
|
|
|
- `vol-slider` exists in `SoundPanel.render()`
|
|
|
|
|
- there is no listener wiring it to `audioEngine.masterGain`
|
|
|
|
|
1. README vision still exceeds code reality
|
|
|
|
|
2. orchestration/export/mode behavior lacks serious automated coverage
|
|
|
|
|
3. `PerfMonitor` exists but is not wired into runtime (`#247`)
|
|
|
|
|
4. ZIP export relies on CDN-loaded JSZip (`#248`)
|
|
|
|
|
5. gallery/open interaction depth is still shallow compared to the product promise
|
|
|
|
|
|
|
|
|
|
### Meaningful product debt
|
|
|
|
|
- gallery items do not really open; click only toasts an id prefix
|
|
|
|
|
- no import/restore/export package flows
|
|
|
|
|
- no video forge
|
|
|
|
|
- no games floor
|
|
|
|
|
- no persistence integration between `PlaygroundState.gallery` and IndexedDB
|
|
|
|
|
- `mode-label` in the footer exists but is never updated
|
|
|
|
|
- `canvas-overlay` exists but is unused
|
|
|
|
|
- `perlin2d()` is explicitly a placeholder, not real Perlin noise
|
|
|
|
|
- skip-link CSS exists, but no skip link appears in `index.html`
|
|
|
|
|
- no real frontend app/test packaging discipline
|
|
|
|
|
- no integrated runtime metrics surface despite perf budget artifacts
|
|
|
|
|
- export system is richer than the rest of the UI exposes
|
|
|
|
|
- batch export and standalone gallery export exist in code but are not a clearly surfaced first-class workflow in the main shell
|
|
|
|
|
- the prototype is still held together by global load order rather than explicit module boundaries
|
|
|
|
|
|
|
|
|
|
## Bottom Line
|
|
|
|
|
|
|
|
|
|
The Playground is a clean sovereign-web prototype: one HTML shell, one design system, a handful of browser engines, and a strong aesthetic identity. It already proves the interaction model.
|
|
|
|
|
`the-playground` is no longer just a two-mode shell. Current `main` has grown into a more substantial browser prototype with export infrastructure, a third experience mode, a perf-budget lane, and one real pytest module.
|
|
|
|
|
|
|
|
|
|
What it does not yet have is the verification, hardening, and feature depth implied by its own vision. The core challenge now is not invention. It is contraction into truth:
|
|
|
|
|
- make the shipped surface match the promise
|
|
|
|
|
- turn `smoke-test.html` into real automated coverage
|
|
|
|
|
- harden `innerHTML` paths
|
|
|
|
|
- finish the panel/mode/gallery interactions that are still only half-born
|
|
|
|
|
But the repo still has a truth gap between what exists in source and what is actually exercised end-to-end:
|
|
|
|
|
- export is richer than the visible UI story
|
|
|
|
|
- performance monitoring exists but is not running
|
|
|
|
|
- dependency posture says local-first while ZIP export reaches for a CDN
|
|
|
|
|
- automated coverage is still far thinner than the surface area of the product
|
|
|
|
|
|
|
|
|
|
That is the real architectural story now: the codebase is starting to branch into platform-level capabilities, but verification and integration are lagging behind the feature shards already present in source.
|
|
|
|
|
|