Compare commits

...

1 Commits

Author SHA1 Message Date
Alexander Whitestone
5186ab583b feat: add the-playground codebase genome (#671)
Some checks failed
Smoke Test / smoke (pull_request) Failing after 21s
2026-04-15 00:25:18 -04:00
2 changed files with 574 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
from pathlib import Path
def _content() -> str:
return Path("the-playground-GENOME.md").read_text()
def test_the_playground_genome_exists() -> None:
assert Path("the-playground-GENOME.md").exists()
def test_the_playground_genome_has_required_sections() -> None:
content = _content()
assert "# GENOME.md — the-playground" in content
assert "## Project Overview" in content
assert "## Architecture" in content
assert "```mermaid" in content
assert "## Entry Points" in content
assert "## Data Flow" in content
assert "## Key Abstractions" in content
assert "## API Surface" in content
assert "## Test Coverage Gaps" in content
assert "## Security Considerations" in content
assert "## Dependencies" in content
assert "## Deployment" in content
assert "## Technical Debt" in content
def test_the_playground_genome_captures_repo_specific_findings() -> None:
content = _content()
assert "IndexedDB" in content
assert "AudioContext" in content
assert "smoke-test.html" in content
assert "no tests ran" in content
assert "innerHTML" in content

539
the-playground-GENOME.md Normal file
View File

@@ -0,0 +1,539 @@
# GENOME.md — the-playground
Generated: 2026-04-15 00:19:15 EDT
Repo: Timmy_Foundation/the-playground
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 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
- 1 CSS design system file
- 2 HTML entry pages (`index.html`, `smoke-test.html`)
- 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`
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`
2. browser engines (`PlaygroundAudio`, `PlaygroundVisual`, `PlaygroundGallery`)
3. thin shared globals (`PlaygroundUtils`, `PlaygroundState`, `PlaygroundEvents`, `ModeManager`)
## Architecture
```mermaid
graph TD
HTML[index.html] --> CSS[src/styles/design-system.css]
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 --> G[src/gallery/gallery.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]
P --> A
P --> V
P --> G
P --> SP
P --> GP
P --> M
P --> S
P --> E
P --> U
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
```
## 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
Script order is the runtime contract:
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`
Because everything is loaded as globals, this order matters. `src/playground.js` assumes the prior globals already exist.
### `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.
### `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
### 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
### 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
## Data Flow
### App 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
### 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.
### 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.
### 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.
### 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.
## Key Abstractions
### `PlaygroundUtils`
A tiny global helpers object.
Important methods:
- `uuid()` -> `crypto.randomUUID()`
- `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`
It behaves more like a convenience registry than a true source-of-truth store. Real durable gallery data lives in IndexedDB, not here.
### `PlaygroundEvents`
A 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
- 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)
### `PlaygroundGallery`
A thin IndexedDB repository.
Contract:
- DB name: `playground-gallery`
- store: `items`
- indexes: `type`, `collection`, `created`
- CRUD methods:
- `init()`
- `save(item)`
- `getById(id)`
- `getAll()`
- `deleteItem(id)`
### `ModeManager`
A registry + switcher for canvas modes.
It holds:
- `modes`
- `current`
- `register()`
- `switch()`
- `renderSelector()`
This is the intended extension point for future experiences.
### `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`.
## API Surface
This repo has no network API. Its API surface is an in-browser global surface.
### Browser globals exposed by load order
- `PlaygroundUtils`
- `PlaygroundState`
- `PlaygroundEvents`
- `PlaygroundAudio`
- `PlaygroundVisual`
- `PlaygroundGallery`
- `SoundPanel`
- `GalleryPanel`
- `ModeManager`
### Event bus contract
Observed event names:
- `audio:note-played`
- `audio:chord-played`
- `gallery:item-saved`
- `gallery:item-deleted`
- `canvas:mode-changed`
- `playground:ready`
### IndexedDB object contract
Saved gallery items can contain:
- `id`
- `created`
- `modified`
- `type`
- `name`
- `data`
- `mimeType`
- `thumbnail`
- `metadata`
### UI control contract
Important DOM ids and commands:
- `btn-save`
- `btn-download`
- `btn-clear`
- `btn-fullscreen`
- `mode-selector`
- `sound-content`
- `gallery-content`
- `playground-canvas`
Keyboard shortcuts implemented today:
- `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
This means the repo has a manual browser smoke harness, but no real automated CI-grade test suite.
### 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
1. `src/playground.js` orchestration
- entrance flow
- mode registration
- action bar wiring
- keyboard shortcuts
- panel toggles
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
```
## 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
### 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()`
- 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.
## Dependencies
### Browser/runtime dependencies
- Canvas 2D API
- Web Audio API / `AudioContext`
- IndexedDB
- Fullscreen API
- Blob / `toBlob`
- FileReader
- `crypto.randomUUID()`
- standard DOM APIs
### Project/tooling dependencies
- none declared
- no `package.json`
- no `requirements.txt`
- no build tooling
- no CI workflow files on `main`
### 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
## Deployment
The deployment model is intentionally trivial.
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
## 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`
### 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`
## 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.
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