diff --git a/docs/adding-algorithms.md b/docs/adding-algorithms.md deleted file mode 100644 index 5af1f46..0000000 --- a/docs/adding-algorithms.md +++ /dev/null @@ -1,22 +0,0 @@ -# Adding algorithms - -See the [sorting algorithm catalog](sorting-algorithms.md) for candidates, complexity, -stability, implementation status, and compatibility notes. - -1. Add `src/sorting/algorithms/.mjs`, following an existing algorithm's default - function and metadata properties. Use its `AS` argument to record operations - and animation frames; see the [engine API](../src/api.html). -2. Import and register the function under a stable ID in - [`algorithm-registry.mjs`](../src/sorting/algorithm-registry.mjs). -3. Add a raw-source import and matching entry in - [`algorithm-sources.mjs`](../src/sorting/algorithm-sources.mjs) for the editor. -4. Run `pnpm run check`, then `pnpm run test:browser`. See - [Development](development.md) for browser setup. - -Keep the function body self-contained: use `AS` and standard JavaScript, with -helpers declared inside the function. Imported helpers are not available when -the body is copied into the custom editor. - -Tests discover `sorting/algorithms/*.mjs` files and check registry/source coverage, sorting -results, item preservation, frame counters, and metadata. Browser tests exercise -each built-in in a worker and after saving its source through the editor. diff --git a/docs/architecture.md b/docs/architecture.md index 2470704..17f6288 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -1,128 +1,107 @@ # Architecture -Modules in `src/` use lowercase, hyphen-separated filenames. `components/ui/` contains -shadcn Base UI primitives; `components/layout/` contains the header and footer. -`components/playground/` contains the interactive screen and its controls; -`components/dialogs/` contains the algorithm editor and MIDI export dialogs. -`sorting/` contains the engine and request handling, and -`sorting/algorithms/` only algorithm implementations. Generators, -MIDI support, and visualizations each have their own directory. The worker lives in -`sorting/worker.mjs`; the Timbre adapter lives in `audio/timbre.mjs`. `@/` aliases `src/`. - -`utilities/` contains small, stateless, domain-independent helpers: `cn.ts` combines -CSS classes; `random.ts`, `shuffle.ts`, and `swap.ts` handle numbers and arrays. -There is no separate `lib/` folder or catch-all `utils.ts` file. shadcn's -`utils` alias points to `@/utilities/cn` so newly generated components use the same helper. -Domain-specific code stays with its domain rather than accumulating in `utilities/`. - -The sorting playground is the interactive data/sort screen, including its editor -and playback controls. React presentation lives under `components/`; -`controllers/` connects the sorting, audio, state, and visualization modules. Shared -settings and atoms remain in `state/`; component-local state stays in its component. A player -is one data or sort panel; the playground coordinates both. The older “workspace” -name did not describe a separate domain concept. - -TypeScript is introduced incrementally alongside `.mjs` modules. Vite handles -bundling; `pnpm run typecheck` checks `.ts` and `.tsx` application modules separately. -Built-in algorithm source and the Ace editor remain JavaScript for now. - -Generator implementations live in `generators/patterns/`. React charts live in -`components/visualizations/`; pure trajectory geometry and visualization names live -in `visualizations/`. Neither the registry nor geometry code touches the DOM. - -## UI - -TanStack Start routes in `src/routes/` contain Home, About, and API page content and use -the shared document in `src/components/layout/`. Public URLs are `/audio-sort/`, `/audio-sort/about`, and `/audio-sort/api`; -prerendering emits `index.html`, `about/index.html`, and `api/index.html`. -TanStack links provide client navigation and ordinary anchor fallbacks without -JavaScript. Audio and editor dependencies are dynamically imported by -Home's effect, never evaluated during server prerendering. About/API remain usable -without JavaScript. `src/client.tsx` hydrates the document. - -[`browser-playground.tsx`](../src/components/playground/browser-playground.tsx) owns the browser playground lifecycle with an application-scoped -vanilla Jotai store. React owns settings, tabs, transport controls, counters, -sliders, and dialogs. Shared buttons, links, and option controls use Tailwind classes. -`styles/globals.css` holds the shadcn theme and document defaults; -Chart components use Tailwind fill/stroke classes. There is no separate visualization stylesheet. -The light theme uses sky accents and neutral surfaces. Playground layout uses one -threshold (`lg`, 1024px): stacked below it, side-by-side above it. Chart heights -are fluid, bounded with `clamp()`, without height-specific media queries. - -[`create-playground.mjs`](../src/controllers/create-playground.mjs) coordinates workers, -data generation, settings subscriptions, soundfont preloading, and player lifetime. -React reads its playback snapshots through `useSyncExternalStore`. Settings and -custom algorithms are read directly from Jotai; there is no mirrored settings cache. -Audio clocks and nodes remain outside React and Jotai. - -[`create-player.mjs`](../src/controllers/create-player.mjs) publishes recorded frames, -position, and renderer selection and delegates transport and synthesis to -`audio/create-transport.ts` and `audio/create-timbre-audio.mjs`. -React subscribes to player snapshots and renders all SVG children, including markers -and the envelope diagram. Trajectory geometry is memoized by frame data; playback -only changes active colors. D3 remains for pure array, scale, color, and path helpers, -not selections or DOM mutations. -The waveform preview canvas has the same explicit imperative ownership. -Pointer capture supports dragging input values across data updates. - -Each waveform uses one shared envelope from `state/envelope.ts`. Defaults remain -attack 50 ms, decay 300 ms, sustain 50%, hold 200 ms, and release 300 ms. -Timbre's `adshr` holds at sustain level after decay; the envelope diagram uses that -ordering. The string preview is illustrative, not a sampled live waveform. - -shadcn's Base UI dialogs provide modal focus containment and Escape handling. -Closing restores focus to the trigger. Ace loads on demand from its pnpm package; -closing a dialog invalidates pending initialization and destroys the editor/session. -The editor remains JavaScript with two-space soft tabs. Invalid edits leave the -catalog unchanged and show an error. Tab panels stay mounted to preserve the -editor and waveform canvas. Sliders use center-aligned thumbs so hidden-panel -initialization does not depend on measuring thumb widths. MIDI export uses shadcn native selects, `jsmidgen`, -`file-saver`, and Blob. - -Cached-page suspension disconnects runtime effects, pauses audio, cancels workers -and pending resumes, and closes dialogs. Returning reconnects effects without -automatically playing. React continues to represent the same Jotai store. -Non-cached exits and Home effect cleanup unmount the playground, dispose owned resources, and -release chart pointer state. Fresh runtime instances can reuse the store. -The shared AudioContext stays library-owned. - -All third-party JavaScript uses package imports. `audio/timbre.mjs` only re-exports the -pinned Timbre browser entry; there are no classic script tags or `public/js` files. -D3 imports remain scoped. Sample audio is fetched and decoded by first-party -modules; see [the audio boundary](audio-dependencies.md). - -## Engine and workers - -[`create-sort-engine.ts`](../src/sorting/create-sort-engine.ts) exports `createSortEngine()`. Each default sort request -gets a fresh engine so recorded frames, counters, and custom API changes do not -leak between requests. `engine.init()` resets recording state, but does not undo -changes to engine methods when deliberately reusing an instance. - -[`sort-types.ts`](../src/sorting/sort-types.ts) defines items, frames, the -algorithm-facing API, and request/response contracts. Operations accept indices -or item references; callers remain responsible for valid indices. The recorder -preserves the legacy extra terminal frame for nonempty sorts. - -[`sort-requests.ts`](../src/sorting/sort-requests.ts) handles two message types: - -- Built-in: `{ key, type: "builtin", id, arr }` runs an imported algorithm. -- Custom: `{ key, type: "custom", source, arr }` compiles an editor body with - `Function("AS", source)`. - -Replies contain `{ key, frames }` or `{ key, error }`. Without Worker support, the -UI uses the same request handler on the main thread. Custom code is arbitrary -JavaScript, not a security sandbox. - -## Algorithms and editor source - -[`algorithm-registry.mjs`](../src/sorting/algorithm-registry.mjs) holds immutable built-in functions and -metadata. [`state/algorithm-overrides.ts`](../src/state/algorithm-overrides.ts) -stores edits and additions per application store and derives a combined catalog. -Built-in identities stay intact until overridden; invalid source is compiled -before any state update. Duplicate IDs are rejected rather than replacing an -existing entry. Function metadata and editor source format are unchanged. -[`algorithm-sources.mjs`](../src/sorting/algorithm-sources.mjs) imports raw source separately so the -editor shows readable code without including those strings in the worker bundle. -Saving an edit creates a custom override and preserves its display metadata. - -See [Adding algorithms](adding-algorithms.md) for registration and editor constraints. +See [development](development.md) for commands, publishing pages, and adding algorithms. + +## Module map + +Paths below are relative to `src/`; `@/` aliases that directory. + +| Directory | Responsibility | +| ----------------------------------------------- | ------------------------------------------------------------------------ | +| `routes/` | TanStack Start pages and the legacy `index.html` redirect | +| `components/layout/` | Shared document, header, and footer | +| `components/playground/`, `components/dialogs/` | Interactive controls, editor, and MIDI export | +| `components/ui/` | Shared shadcn Base UI primitives | +| `components/visualizations/` | React SVG charts and envelope diagram | +| `controllers/` | Playground/player coordination and settings connections | +| `state/` | Jotai settings, envelopes, playback preferences, and algorithm overrides | +| `sorting/` | Recorder, worker protocol, registries, and algorithm implementations | +| `generators/`, `midi/` | Input patterns, musical data, and MIDI encoding | +| `audio/` | Playback transport, synthesis, and sample loading | +| `visualizations/` | Pure trajectory geometry and visualization types | +| `utilities/` | Stateless helpers for arrays, randomness, and CSS classes | + +TypeScript and JavaScript coexist. Built-in algorithms and editable function bodies +remain JavaScript. Third-party JavaScript comes from package imports. + +## UI and lifecycle + +Home imports `components/playground/browser-playground.tsx` after hydration. +About/API import Markdown from `docs/` through `components/docs-page.tsx` and +remain readable without JavaScript. Browser audio and editor modules do not run +during prerendering. + +`controllers/create-playground.mjs` coordinates data generation, workers, settings +connections, sample preloading, and two players. Each player publishes frames, +position, and visualization selection. React reads runtime snapshots through +`useSyncExternalStore` and settings through the application-scoped Jotai store. +Audio clocks, nodes, and sample caches stay outside React and Jotai. + +React owns SVG children; D3 supplies array, scale, color, and path utilities. +Trajectory geometry is memoized by frame data. The waveform preview canvas is +drawn imperatively. Layout stacks below `lg` (1024px) and uses side-by-side panels +above it; chart heights use `clamp()`. + +Base UI handles dialog focus and dismissal. Ace loads on demand, with pending +initialization cancelled on close. Tab panels stay mounted for editor/canvas +lifetime. Invalid source leaves the algorithm catalog unchanged. + +Cached-page suspension disconnects effects, pauses audio, cancels workers and +pending resumes, and closes dialogs. Returning reconnects without automatically playing. +Leaving Home disposes the playground and its owned resources. The shared +AudioContext remains library-owned. + +## Sorting and editor source + +`sorting/create-sort-engine.ts` records item snapshots, markers, comparisons, and +swaps. Each default request gets a fresh engine. `init()` resets recording state, +but does not restore methods changed by custom code on a reused engine. +Operations accept indexes or item references; callers must supply valid indexes. +Nonempty recordings retain a legacy extra terminal frame. + +`sorting/sort-requests.ts` handles built-in requests by registry ID and custom +requests by compiling a function body with `Function("AS", source)`. Replies +contain `{ key, frames }` or `{ key, error }`. Without Worker support, the same +handler runs on the main thread. Custom JavaScript has no security sandbox, and the +worker does not impose an execution or frame budget. + +`sorting/algorithm-registry.mjs` holds frozen built-ins. Jotai stores custom +additions and overrides separately and derives the combined catalog. Source is +compiled before updating state; duplicate IDs are rejected. +`sorting/algorithm-sources.mjs` imports readable source separately for the editor, +so source strings are not included in the worker bundle. + +## Audio + +`audio/create-transport.ts` owns timing, position, direction, looping, and pending +resume invalidation. Its clock and effects are injected. Stop allows note tails +to finish; suspension/disposal silences owned nodes. +`audio/create-timbre-audio.mjs` connects transport events to synthesis and previews. +Waveforms share the envelope in `state/envelope.ts`; the string preview is +illustrative rather than a sampled live waveform. + +`audio/create-soundfont.ts` shares a sample cache between both players, deduplicates +requests, allows retries, and aborts fetches after ten seconds. Cache misses load +without playing a late note. `audio/create-timbre-soundfont.mjs` decodes MP3s with +the existing AudioContext and feeds buffers to Timbre. Disposal aborts requests +and ignores late results. The GeneralUser GS sample bank and instrument/note +mapping were retained during modernization. + +`audio/timbre.mjs` imports `timbre/timbre.dev.js`, not its Node entry. +`pnpm-workspace.yaml` excludes unused `speaker` and `readable-stream` dependencies; +Vite maps the bundle's CommonJS `global` to `globalThis`. Timbre publishes a global +as a side effect, but application code uses its import. `package.json` permits +compatible updates; the lockfile currently resolves Timbre to `14.11.25`. + +The migration replaced deployed Timbre `14.06.23` (whose old development file was +`13.05.03`) and removed JSONP, JavaScript MP3 decoding, and the Flash fallback. +Regression tests preserve oscillator/envelope/pluck fingerprints and exercise +sample caching and native decoding. The original audit recorded successful CORS +fetches and stereo decoding for note 60, instruments 0, 42, and 127 on 2026-09-07; +that is historical evidence, not a current availability check. + +For audio changes, audition waveform and soundfont modes, envelope edits, +instrument changes, tempo/volume, forward/reverse/loop playback, and suspension. +Automated tests do not establish audible equivalence, especially around decoder +padding. Changing the sample bank can change every instrument's sound. Remaining +listening and attribution work is tracked in [TODO](todo.md). diff --git a/docs/audio-dependencies.md b/docs/audio-dependencies.md deleted file mode 100644 index 406df80..0000000 --- a/docs/audio-dependencies.md +++ /dev/null @@ -1,90 +0,0 @@ -# Audio boundary and dependency audit - -## Current boundary - -`audio/create-transport.ts` owns position, direction, looping, clock lifetime, -and invalidation of pending audio-resume actions. Its clock and effects are -injected; it has no DOM, Jotai, or Timbre dependency. Stop allows existing note -tails to finish; suspend/dispose silence owned waveform nodes. Empty data does -not start playback. - -`audio/create-timbre-audio.mjs` adapts the existing engine: interval creation, -ADSHR and oscillator/pluck nodes, MIDI note triggers, gain, preview plotting, -and node disposal. It accepts the engine and settings getters as dependencies. -The player factory connects those modules to React controls and chart snapshots. -`audio/create-soundfont.ts` now owns a controller-scoped sample cache shared by -both players. `audio/create-timbre-soundfont.mjs` decodes fetched MP3s with the -existing AudioContext and feeds stereo buffers into the existing Timbre mixer. -No remote code is executed. Instrument selection is synchronized from settings; -audio buffers and pending requests remain outside Jotai. - -Cache misses fetch without playing late (the former `play(note, false)` behavior). -Concurrent requests are deduplicated, failed requests can retry, and fetches have -a ten-second abort timeout. Suspension pauses cached sample nodes; destruction -aborts pending requests, releases nodes, and ignores late decoder results. - -The JSONP, MP3 decoder, and soundfont vendor scripts are removed. The implementation -is first-party code, not a relocated vendor bundle. The remote GeneralUser GS bank -and numeric instrument/note mapping are unchanged. Native decoding may differ in -encoder-padding handling from the old JS decoder; listening review is still required. - -Verification includes deterministic fetch/decode/cache tests, real browser stereo -buffer playback using a generated fixture, and a manual Chrome network/decode smoke -check of notes 60 for instruments 0, 42, and 127. The real host returned HTTP 200, -allowed CORS, and all three MP3s decoded as stereo at 44100 Hz on 2026-09-07. - -## Packaged Timbre - -The app imports `timbre/timbre.dev.js` from pinned `timbre@14.11.25`, not the -package's Node entry. pnpm overrides exclude its unused `speaker` and -`readable-stream` dependencies, avoiding native Node audio installation. -Vite maps the bundle's CommonJS `global` reference to `globalThis`. The package -still publishes a legacy global as a side effect; application consumers use the -imported value rather than reading that global. - -The actual deployed minified bundle identified itself as `14.06.23`; the old -development file was `13.05.03` and was not its matching source. This migration -is therefore an explicit upgrade, not a claim of byte-for-byte equivalence. -All seven oscillator preview blocks matched the old deployed bundle. Deterministic -ADSHR and seeded pluck output matched over 700 processing blocks; regression -fingerprints preserve those checks without keeping a vendored baseline. -The published browser entry supports standard AudioContext, and production -browser tests exercise native stereo samples, playback controls, and teardown. -Listening review is still required for behavior beyond those checks. - -Third-party attribution is deferred to a separate, project-wide changeset. -Local Timbre bundles, the stale map, and the Flash fallback asset are removed. The site -requires Web Audio; Flash-only browsers are no longer supported. - -## Initial audit (2026-09-07, before the migrations) - -These historical findings motivated the native loader and package migration above. - -| Component | Evidence and compatibility concerns | Next action | -| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Timbre | The checked-in development bundle identifies itself as `13.05.03`. The npm registry reports `timbre@14.11.25`, whose main is `timbre.node.js`, with `speaker` and `readable-stream` dependencies and no browser override reported. This is not a proven drop-in import. | Inspect the published browser artifact and compare it with the deployed bundle, including local AudioContext changes, before adding a pinned dependency. Verify ADSHR, all eight generators, interval timing, and extensions. | -| Soundfont extension | The local header attributes MIT-licensed code to skratchdot. It attaches to Timbre and uses per-note JSONP URLs on `projects.skratchdot.com/free-midi`. Registry lookup for the exact name `timbre.soundfont.js` returns 404. | Prefer a focused first-party sample-loader adapter if no compatible published artifact is found; preserve instrument/note mapping and sample source first. | -| audio-jsonp | The local source registers `audio.jsonp`, installs global callbacks, injects remote scripts, and decodes base64 via Timbre internals. Exact npm name `audio-jsonp` returns 404. | Replace alongside the soundfont loader, not independently. Check CORS on actual MP3 assets before choosing fetch/decodeAudioData. | -| MP3 decoder extension | A bundled decoder extends the old engine. Exact npm name `timbre.mp3_decode` returns 404. Its transitive code/license inventory has not yet been completed. | Verify browser-native decoding and the sample-loading path before removing it. Do not copy the bundle into source and call it first-party. | -| Development bundle/map/Flash | The footer loads only `timbre.js`, but it references its source map and contains a conditional `timbre.swf` fallback. Documentation currently links the development source for envelope semantics. | Remove these only with an explicit browser-support decision and updated source references. | - -Registry checks identify specific package names, not proof that no alternative -package exists. The comparison above supersedes the initial packaging blockers. - -Primary references: - -- [Timbre package metadata](https://registry.npmjs.org/timbre/14.11.25) -- [Timbre source](https://github.com/mohayonao/timbre.js) -- [audio.jsonp documentation](https://projects.skratchdot.com/timbre.js/audiojsonp.html) -- [Soundfont extension source](https://github.com/skratchdot/timbre.soundfont.js) -- [Current sample collection](https://skratchdot.com/projects/free-midi/) - -## Listening review and future changes - -No audio-engine rewrite is required for the React migration. Native sample -loading no longer depends on the old decoder extensions, reducing coupling. -Do not change the sample bank silently: another soundfont library's defaults can -change every instrument's sound. Keep synthesis replacement separate from React. -Audition waveform and soundfont modes, envelope edits, instrument changes, -tempo/volume changes, forward/reverse/loop playback, and suspension on real audio. -Automated lifecycle tests are not a substitute for that listening review. diff --git a/docs/development.md b/docs/development.md index 4772392..1e7cad0 100644 --- a/docs/development.md +++ b/docs/development.md @@ -1,70 +1,50 @@ # Development -Use Node.js 24 or newer and the pnpm version pinned in `package.json`, installed with -your preferred version manager (such as mise) or the [pnpm installer](https://pnpm.io/installation). -Run commands from the repository root; `pnpm install --frozen-lockfile` installs the -locked dependencies. Use `pnpm add` / `pnpm add -D` for dependency changes and commit -the resulting `pnpm-lock.yaml`. Do not generate an npm lockfile. - -## Build and preview - -`pnpm dev` serves the site with live updates (`pnpm start` is an alias). -`pnpm build` creates `dist/audio-sort/`; `pnpm preview` serves that production build. -Development uses `http://localhost:5173/audio-sort/`; preview uses -`http://localhost:8080/audio-sort/` by default. - -TanStack Start prerenders the React pages and Vite bundles JavaScript and CSS. -Site files live in `src/`; tests and tool configuration stay at the root. -Only the contents of `dist/audio-sort/` are deployed. Build-time server files live in ignored `.tanstack/`; -GitHub Pages needs no Node server. - -The shared base is `/audio-sort/` in development, preview, tests, and production. -Routes are `/audio-sort/`, `/audio-sort/about`, and `/audio-sort/api`; the latter two are deployed as directory -index files. A static host may append a trailing slash on direct visits. - -Preview uses `sirv-cli` to serve `dist/` as static files only, with no server -rendering or SPA fallback. There are no deployment-specific build commands or -base-path environment variables. - -Prerendering automatically discovers static routes; new static pages need no extra -build configuration. Link crawling is disabled because Start currently duplicates -base-prefixed URLs in the Pages build. Dynamic routes would need concrete URLs -supplied explicitly. - -Static files live in root-level `public/`: images in `public/img/` and the -`.nojekyll` marker. There are no vendored JavaScript files. Files are copied unchanged -to `dist/audio-sort/` without a `public/` URL prefix. Use `/img/...` in source CSS; Vite -adjusts these URLs for the deployment path. Application modules and CSS stay in `src/`. - -CSS is bundled and minified by Vite. `src/styles/globals.css` contains Tailwind and -shadcn theme tokens; component classes own layout, controls, and SVG chart styling. -React chart components live in `src/components/visualizations/`. +Use Node.js 24+ and the pnpm version in `package.json`. -Add primitives with `pnpm dlx shadcn@latest add `. `components.json` -selects Base UI, the Nova preset, neutral base colors, and Lucide icons. Keep shared -primitives in `src/components/ui/`, screen controls in `src/components/playground/`, -and dialogs in `src/components/dialogs/`. Non-React coordination lives in `src/controllers/`. -Use `lg:` for the application's stacked/side-by-side layout; avoid adding extra width tiers. +```sh +pnpm install --frozen-lockfile +pnpm dev +``` -## Checks +Open `http://localhost:5173/audio-sort/`. Use `pnpm add` / `pnpm add -D` for +dependency changes and commit `pnpm-lock.yaml`. + +## Build and deployment -`pnpm run check` runs lint, formatting and spelling checks, TypeScript checking, unit tests, and a production build. +`pnpm build` prerenders the site into `dist/audio-sort/`. `pnpm preview` serves +`dist/` with sirv at `http://localhost:8080/audio-sort/`, without server rendering +or an SPA fallback. Build-time server files stay in ignored `.tanstack/`. -- `pnpm run lint`: check first-party JavaScript and TypeScript with Oxlint. -- `pnpm run spellcheck`: check spelling in source, docs, and configuration with CSpell. -- `pnpm run typecheck`: check TypeScript modules and React pages with strict settings; no files are emitted. -- `pnpm run format`: format with Oxfmt; `pnpm run format:check` checks without editing. -- `pnpm test`: run unit tests; `pnpm run test:watch` reruns them while editing. +Development, preview, tests, and deployment share the `/audio-sort/` base. +The public pages are Home, About, and API. About/API emit directory index files; +static hosts may append a trailing slash. The legacy `/audio-sort/index.html` +route redirects to Home in the router. -TypeScript can infer imported JavaScript modules (`allowJs`), but `checkJs` stays -off until those modules are migrated. Worker payloads are still checked at runtime. +TanStack Start discovers static routes automatically. Link crawling is disabled +because it duplicates base-prefixed URLs in this build. Dynamic routes need +explicit URLs for prerendering. Start generates `src/route-tree.gen.ts`; commit it but +do not edit it manually. + +Assets in `public/` are copied unchanged into the output, including `.nojekyll`. +For source CSS images, use `/img/...`; Vite adjusts those URLs for the site base. + +GitHub Actions runs checks and browser tests for PRs and deployment. The Pages +workflow uploads the tested `dist/audio-sort/` without rebuilding. Set the +repository's Pages source to **GitHub Actions**. No Node server is deployed. + +## Checks -Vendor and generated files are excluded from linting and formatting. Oxfmt formats -source CSS and TSX alongside JavaScript. `src/components/layout/site-document.tsx` owns the -shared document, header, and footer. Start generates `src/route-tree.gen.ts` from -`src/routes/`; commit that file but do not edit it manually. +| Command | Purpose | +| ------------------------------------------- | --------------------------------------------------------------------- | +| `pnpm run check` | Lint, formatting, spelling, types, unit tests, and production build | +| `pnpm run lint` | Oxlint checks | +| `pnpm run format` / `pnpm run format:check` | Format files / check formatting | +| `pnpm run spellcheck` | CSpell checks | +| `pnpm run typecheck` | Strict checking of application TypeScript; `.mjs` is not type-checked | +| `pnpm test` / `pnpm run test:watch` | Unit tests / watch mode | -Run browser tests against a completed production build: +Run browser tests against a completed build: ```sh pnpm exec playwright install chromium @@ -72,74 +52,58 @@ pnpm run build pnpm run test:browser ``` -Do not rebuild `dist/` while browser tests are running. To use an existing Chrome -installation, set `PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH` to its executable path. +Do not rebuild while browser tests run. To use installed Chrome, set +`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH` to its executable path. Tests cover static +URLs, navigation without JavaScript, editing, workers, playback, and UI lifecycle. +External audio services are stubbed; audible output and the real sample host need +manual checks. See [audio maintenance](architecture.md#audio) and [TODO](todo.md). -Browser tests serve the completed production build at `/audio-sort/`. -They cover page URLs, workers, editor behavior, -and UI controls. External services are stubbed; audible output and remote soundfonts -need manual testing. Known bugs are tracked in [TODO](todo.md). +CSpell configuration lives in `cspell.config.ts`. Add accepted vocabulary to +`.cspell/project.txt` or `.cspell/music.txt`, lowercase and alphabetized. Use narrow +config overrides for file-specific terms. Fix typos instead of broadly excluding +prose. The original scale catalog is excluded; its attribution stays in source. -## Spelling - -`cspell.config.ts` is the shared spelling configuration. CSpell loads TypeScript -natively with our supported Node version; no extra loader is needed. Checks use -US English, respect `.gitignore`, and exclude lock files, generated routes, and -public assets. The original scale catalogue (`src/midi/scales.ts`) is also excluded -instead of maintaining a dictionary of its names. Spelling also runs in CI through `pnpm run check`. - -Keep accepted vocabulary in version control: - -- `.cspell/project.txt`: project names, dependencies, and sorting terminology. -- `.cspell/music.txt`: instrument terminology. -- Config `overrides`: terms specific to a file or group, such as names in README references. - -Keep dictionary files lowercase and alphabetized, one word per line. Fix real typos before -adding words; do not accept an entire error report automatically. Use a narrow -`cspell:disable-next-line` directive with an explanation for non-language data -such as binary signatures, rather than disabling a whole file. Avoid broad regex -exclusions that hide prose or comments. +## Markdown site pages -The optional VS Code Code Spell Checker extension can use the same configuration -(use a current version). Add shared terms to the repository dictionaries, not a -personal editor word list, so local checks and CI agree. +Edit [about.md](about.md) and [api.md](api.md) for the public pages. +`src/components/docs-page.tsx` supports headings, lists, links, fenced code, and +GitHub-style tables. Raw HTML is not rendered. Content is prerendered and readable +without JavaScript. API-specific rendering adds marker swatches. -See CSpell's [configuration reference](https://cspell.org/docs/Configuration) and -[custom dictionary example](https://cspell.org/docs/getting-started). +To publish another document: -## Deployment +1. Add a Markdown file in `docs/` with one `#` page title. +2. Copy `src/routes/about.tsx`, change the route path and element ID, and import + the document with Vite's `?raw` suffix. Set a descriptive table label if needed. +3. Add its filename and route to `documentRoutes` in `src/components/docs-page.tsx`. +4. Add a header link if it belongs in navigation. Update the browser test's page + and navigation expectations when adding a route or link. -GitHub Actions runs checks and browser tests for PRs and before deployment. -CI uses the latest Node.js LTS release. Check/build jobs have a 10-minute timeout; -the deployment job has a 5-minute timeout. -CI builds once, tests that build, and uploads `dist/audio-sort/` without rebuilding. -The repository's Pages -publishing source must be **GitHub Actions**. +Use `/` for Home and `api.md` for another published document. Router links preserve +`/audio-sort/` and client navigation. Link unpublished development docs through +full repository URLs. Adding a file to `docs/` alone does not publish it. -## Reference +## Adding algorithms -- [Modernization plan](modernization.md) +The [sorting catalog](sorting-algorithms.md) records candidates and implementation status. -- [Architecture](architecture.md) -- [Adding algorithms](adding-algorithms.md) +1. Add `src/sorting/algorithms/.mjs` with a default function and metadata, + following an existing implementation. Use its `AS` argument; see the [API](api.md). +2. Register its stable ID in `src/sorting/algorithm-registry.mjs`. +3. Add a raw-source import and entry in `src/sorting/algorithm-sources.mjs`. +4. Update the catalog, then run `pnpm run check` and `pnpm run test:browser`. -## Markdown site pages +Keep the function body self-contained: imported helpers are unavailable when the +body is copied into the editor. Declare helpers inside the function. Choose the +exact variant before assigning complexity and stability metadata. -Edit `docs/about.md` and `docs/api.md` to update the public About and API pages. -The shared `src/components/docs-page.tsx` renderer supports Markdown headings, -lists, links, fenced code, and GitHub-style tables. Raw HTML is not rendered. -Content is included in the static HTML, so it remains readable without JavaScript. +Tests discover algorithm files and check registry/source coverage, sorting, +item preservation, counters, and metadata. Browser tests run each built-in in a +worker and after saving it through the editor. -To publish another document: +## UI components -1. Add a Markdown file in `docs/`, with a single `#` page title. -2. Copy a small route such as `src/routes/about.tsx`, change its route path, and - import your document with Vite's `?raw` suffix. Static routes are prerendered automatically. -3. Add its filename and route to `documentRoutes` in `src/components/docs-page.tsx` - so relative Markdown links such as `api.md` resolve to the published page. -4. Add a link in `src/components/layout/header.tsx` if it belongs in navigation. - -Use application paths such as `/` for Home and `api.md` for another published -Markdown document. The renderer uses router links to preserve the `/audio-sort/` -base and client navigation. Use full repository URLs for development documents -that are not published. Adding a file to `docs/` alone does not publish it. +Add primitives with `pnpm dlx shadcn@latest add `. `components.json` +selects Base UI, Nova, and Lucide. Theme defaults live in `src/styles/globals.css`; +components own their Tailwind classes. See [architecture](architecture.md) for +module ownership and the current layout. diff --git a/docs/migration-handoff.md b/docs/migration-handoff.md deleted file mode 100644 index 7c7cc38..0000000 --- a/docs/migration-handoff.md +++ /dev/null @@ -1,85 +0,0 @@ -# Migration handoff - -## Decisions - -- Framework migration first; preserve the top/data and bottom/sort design. -- Complete React/Tailwind and remove Bootstrap/jQuery together in PR #47. -- No temporary compatibility overrides or interim Bootstrap migration. -- Keep sorting algorithms, recording API, Jotai state, and audio engine intact. -- TanStack Start follows in a separate PR. Redesign and license reporting are deferred. -- `ui-design.md` and `ui-prototype.html` are exploratory reference, not implementation targets. - -## Completed UI migration - -PR #47 migrated the whole playground; PR #48 polished icons, hover states, and typography: - -- The playground uses a reusable vanilla Jotai store. -- `components/playground/sorting-playground.tsx` assembles settings, playback controls, and dialogs. -- `controllers/create-playground.mjs` owns worker/data coordination and audio subscriptions. -- `controllers/create-player.mjs` bridges transport/audio modules and publishes chart snapshots. -- React owns controls and SVG children; audio draws the waveform canvas. -- Settings/algorithm overrides stay in Jotai. Playback snapshots use `useSyncExternalStore`. -- Native ranges replace plugin sliders; native dialogs handle editing and MIDI export. -- Lazy Ace loading, invalid-source errors, focus restoration, cached-page suspension, - worker fallback, MIDI export, and teardown/remount remain covered by browser tests. -- Bootstrap, jQuery, the legacy controller/player factories, old pane/modal templates, - and `public/js` files are removed. Tailwind Preflight is enabled; no overrides remain. -- `src/css/site.css` preserves the existing visual style without copied Bootstrap CSS. -- At widths >=980px and heights >=900px, both charts gain 40px. - -All third-party JavaScript is imported from pnpm packages. Timbre remains pinned to -`14.11.25`, with Node-only dependencies excluded. Native sample loading replaces -the old JSONP/MP3 extensions. No new license-output logic is included. - -## Completed TanStack Start shell - -Eleventy and Liquid are replaced by TanStack Start file routes and React pages. -The existing playground, runtime, and visual design are retained. - -- `src/routes/` defines the three pages; Start generates `src/route-tree.gen.ts`. -- `src/components/layout/site-document.tsx` renders the shared header/footer and document. -- `src/routes/index.tsx` dynamically imports `src/components/playground/browser-playground.tsx` after hydration. - It renders the playground within Start's React root; runtime lifecycle cleanup - handles navigation away, cached pages, and remounts. Audio/editor modules never - execute during prerendering. -- Public routes are `/audio-sort/`, `/audio-sort/about`, and `/audio-sort/api`. Per the user's updated preference, - no `.html` compatibility routes or rewrites are included. Internal links use - TanStack navigation; static hosting may append a directory trailing slash. -- `vite.config.ts` emits directory index HTML and client assets to `dist/audio-sort/`, and build-time - server files to ignored `.tanstack/server/`. No server is deployed. -- Development, production, preview, and browser tests share `/audio-sort/`. - There is one build and one browser suite. Preview serves `dist/` using `sirv-cli`, - with no custom preview configuration or SPA fallback. CI uploads the tested - `dist/audio-sort/` directory without rebuilding; timeouts remain. -- Prerendering uses Start's automatic route discovery, with no manual page list or - per-page output configuration. Link crawling stays disabled because it duplicates - base-prefixed URLs in the Pages build. -- Tests cover clean URLs/reloads, client navigation, no-JavaScript content, - hydration errors, lazy-load recovery, and the existing playground regressions. -- Adding Vite's raw-import types exposed an existing `getFunctionBody` signature - mismatch; it now explicitly accepts the source strings it already handled. - -## Next - -The current `shadcn-base-ui` branch refines the UI without changing audio, state, -or sorting APIs. It uses shadcn's Base UI Nova primitives, retains Lucide and the -system font, and maps the light theme to Tailwind sky/neutral colors. - -- `src/components/ui/`: shared primitives; `components/layout/`: header/footer. -- `src/components/playground/` and `src/components/dialogs/`: controls and dialogs; `src/controllers/`: runtime coordination. -- `src/styles/globals.css`: theme/document defaults; chart styling lives in React components. -- `site.css` and the `tw:` prefix are removed. Buttons and links own their Tailwind classes. -- Two playground layouts use one 1024px threshold; chart heights are fluid. -- Tab panels stay mounted for Ace/canvas lifetime. Slider thumbs use center alignment - to avoid hidden-panel measurement. Base UI handles dialog focus and dismissal. - -Review this changeset visually and audition playback. Then continue phase 8 -(recorded writes/auxiliary buffers and Merge sort). Redesign and license reporting remain deferred. - -## Verification - -- `pnpm run format && pnpm run check` -- `PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH='/Applications/Google Chrome.app/Contents/MacOS/Google Chrome' pnpm run test:browser` -- Browser tests exercise the shared `/audio-sort/` path. Never rebuild while they run. -- Review desktop/tablet/mobile layouts and audition waveform/soundfont playback. -- See `docs/architecture.md` for ownership and lifecycle details. diff --git a/docs/modernization.md b/docs/modernization.md deleted file mode 100644 index 734b152..0000000 --- a/docs/modernization.md +++ /dev/null @@ -1,120 +0,0 @@ -# Modernization plan - -Deliver cohesive, substantial PRs in this order. Preserve sorting, playback, editable -algorithms, and static hosting throughout. Skip an interim Bootstrap 5 migration. - -**Current direction:** migrate the stack before redesigning. Preserve the current -top/data and bottom/sort layout, controls, and behavior. Use spare laptop height -for slightly taller charts; keep short-screen/mobile sizes compact. The exploratory -prototype is deferred and is not the implementation target. - -1. **TypeScript foundation.** Add strict, no-emit checking and migrate independent - data/utilities first. Keep existing JavaScript working; expand type coverage - incrementally rather than suppressing errors across the legacy controller. -2. **Finish independent TypeScript modules.** Type array utilities, generators, - and their registry while preserving runtime behavior. Keep the current - algorithm function/metadata format and JavaScript editor unchanged; a format - redesign is deferred until it simplifies code or enables useful type checking. -3. **Typed recording API.** Type items, frames, and worker messages - without changing recording semantics. Keep the factory unless a class solves - a concrete problem; algorithms depend on an interface, not its implementation. -4. **Jotai settings.** Introduce an application-scoped vanilla store behind the - current UI. Migrate settings and custom overrides to one source of truth. - Static registries stay imports; derived atoms can combine them with overrides. - Keep audio nodes, timers, workers, and editors outside the store. -5. **Playback boundary and audio dependencies.** Separate playback lifecycle and - scheduling from DOM controls. Audit Timbre, soundfont and MP3 extensions, and - audio-jsonp for package availability, local modifications, asset loading, - licenses, and browser behavior. Use pinned package imports when compatible; - otherwise plan a focused first-party replacement. Do not combine an audio - engine rewrite with a UI rewrite. Listening checks remain part of review. -6. **Complete React/Tailwind UI in one PR.** Migrate settings, transports, tabs, - counters, editor, and export dialogs without a redesign. Remove Bootstrap, - bootstrap-slider, jQuery, and all coexistence overrides in the same changeset. - Use native ranges and dialogs, Tailwind Preflight/utilities, and first-party CSS. - Keep audio scheduling outside React and give D3 sole ownership inside its SVG - container. Keep the existing responsive behavior until the technical migration works. -7. **TanStack Start shell.** Replace Eleventy/Liquid - with React routes and a static build, preserving the current page structure. - Prove static deployment early; do not wait for or bundle this with a redesign. - Use clean page URLs under the shared /audio-sort/ base, preserving worker/assets and - GitHub Pages deployment. Browser-only dependencies must not run during - prerendering. Keep existing workflow timeouts and checks. Do not combine the - static-builder replacement with the UI migration or a redesign. -8. **New recording capabilities.** Use Merge sort to design recorded writes and - auxiliary buffers, including intermediate identity semantics and counters. - Follow with counting/radix support; keep this separate from UI migrations. - -## Dependency end state - -No third-party JavaScript is served from `public/js/` or read from `globalThis`. -Dependencies come from pnpm package imports; application replacements live in -`src/`. Moving copied vendor scripts into `src/` is not a replacement. -Retain required attribution for adapted data/code. Package-managed assets such -as Ace workers may be emitted by the build; they are not manually vendored files. - -There is no remaining vendored JavaScript. React, native controls, and first-party -pointer handling replace jQuery, Bootstrap, and bootstrap-slider. -Timbre is imported from its pinned package browser entry. -JSONP and the MP3/soundfont extensions have been replaced by first-party native -sample loading. The obsolete Timbre development bundle, source map, and Flash -fallback asset have also been removed. -Check external soundfont loading separately from local script packaging. - -Completion requires no legacy script tags/vendor bridge, reproducible package -installs, and working editor, playback, MIDI export, and static-path checks. - -## Current phase - -TypeScript checks cover scales, instruments, all array utilities, generators, -the generator registry, sort recorder, and request/response handling. -Remaining `.mjs` modules and browser-entered algorithms are not type-checked yet. - -Phase 4 is complete: selected settings, waveform envelopes, custom algorithm -overrides, AutoPlay, and looping use an application-scoped Jotai store. Disposable -connections synchronize audio controls, algorithm/catalog changes, and data size. -Controllers/players now have explicit suspension and teardown for subscriptions, -workers, timers, editors, owned audio nodes, sliders, and event handlers. Cached -pages preserve data/settings; remounting does not duplicate controls or listeners. - -Phase 5 implementation is complete, pending listening review: playback position, direction, looping, scheduling, and -resume invalidation now live in a DOM-independent typed transport. A separate -audio adapter owns existing Timbre synthesis and note dispatch. The player factory -connects these to the legacy controls and visualizations. - -Soundfont samples now use runtime-owned caching, fetch, and native decoding, -while retaining the existing sample bank and Timbre mixer. The three legacy -JSONP/MP3/soundfont scripts are removed. The [audio dependency audit](audio-dependencies.md) -records sample-host verification and the Timbre package compatibility checks. -Timbre now uses the pinned `14.11.25` browser entry with its Node-only dependencies -excluded. The obsolete local bundles, map, and Flash asset are removed. -Phase 6 now replaces the complete playground in PR #47, not a sequence of islands. -React owns all controls and dialogs, uses the existing Jotai store, and subscribes -to playback snapshots from a separate runtime. D3 and audio retain their owned -SVG/canvas hosts. The legacy controller, plugin sliders, Bootstrap CSS/JavaScript, -jQuery, and temporary overrides are removed together. The existing two sections -remain, with 40px taller charts only on sufficiently tall desktop viewports. - -Phase 7 replaces Eleventy/Liquid with TanStack Start routes and React documents. -Public routes are `/audio-sort/`, `/audio-sort/about`, and `/audio-sort/api`, with no legacy `.html` aliases. -Static prerendering emits directory index files into `dist/audio-sort/`; -build-time server files remain in `.tanstack/` and are not deployed. Development, -production, preview, and browser tests share the same base and build configuration. -Home imports the existing playground after hydration; About/API need no audio or -editor runtime. Client navigation unmounts the playground when leaving Home. - -The current UI refinement adds shadcn Base UI (Nova preset) before phase 8. -Shared primitives live in `components/ui/`; playground components, dialogs, and -runtime modules live in `components/playground/`, `components/dialogs/`, and `controllers/`, respectively. Tailwind component classes replace -`site.css`, with sky/neutral theme tokens. React now renders chart SVG children -and the envelope diagram with Tailwind classes; D3 only supplies pure utilities. -The intermediate D3 stylesheet and DOM renderer implementations are removed. One `lg` -threshold separates stacked and side-by-side layouts; chart heights use `clamp()`. -Review the larger controls, dialog behavior, and laptop/mobile layouts before merging. - -After this UI review, phase 8 remains recorded writes/auxiliary buffers and Merge sort. -A larger visual redesign is still a separate decision. -See [the migration handoff](migration-handoff.md) for fresh-context continuation. -Keep transport state and shared vendor resources out of Jotai; retain listening checks. -The algorithm function/metadata format and editor remain unchanged; do not add parser/build -machinery solely to reorganize metadata. diff --git a/docs/sorting-algorithms.md b/docs/sorting-algorithms.md index 42a2016..a14d2fa 100644 --- a/docs/sorting-algorithms.md +++ b/docs/sorting-algorithms.md @@ -8,7 +8,7 @@ plus additional variants, networks, and external sorts. Each algorithm name link its Wikipedia article or the relevant parent article when it has no separate page. Implementation status checked against the [registry](../src/sorting/algorithm-registry.mjs) -on 2026-09-07. Only registered built-ins count as implemented; historical files and +on 2026-09-08. Only registered built-ins count as implemented; historical files and custom editor examples do not. ## Reading the tables @@ -184,4 +184,4 @@ general sorting implementations; the app requires an ordered permutation of the When adding an algorithm, choose its exact variant, confirm the bounds from its paper or reference implementation, test duplicate-key stability and identity preservation, -and update both this catalog and the app metadata. Follow [Adding algorithms](adding-algorithms.md). +and update both this catalog and the app metadata. Follow [Adding algorithms](development.md#adding-algorithms). diff --git a/docs/todo.md b/docs/todo.md index 7e0e3d3..4af1a96 100644 --- a/docs/todo.md +++ b/docs/todo.md @@ -1,27 +1,28 @@ -# Audio Sort +# TODO -## Todo List +Open ideas and maintenance work, not an ordered roadmap. Completed migration +history lives in Git; [About](about.md) summarizes the project story. -- Add waveform visualization in header while audio is playing +## Algorithms and recording -- Add more sorting algorithms; see the [catalog](sorting-algorithms.md). +- Add more algorithms; see the [catalog](sorting-algorithms.md). +- Design recorded writes and auxiliary buffers for Merge, Counting, and Radix, + preserving item identity and showing intermediate work. +- Review frame-recording behavior, including the extra terminal frame and how + marker calls are grouped into playback steps. -- Improve visualizations / transitions. Allow filtering of what to show / play. +## Maintenance -- Add "use defaults" button for audio controls +- Complete the audio migration listening review using the + [audio checklist](architecture.md#audio). Automated tests are not a listening review. +- Review third-party attribution across dependencies, adapted code/data, and audio assets. +- Extend TypeScript coverage to remaining JavaScript runtime modules where useful. -- Add popovers on sort selection with info about the sort's performance +## Interface ideas -- Allow defaults to be set via url parameters - -- Add "share settings" button which would populate the url based on your current settings - -- Fix the play intervalCallback() function. Shouldn't be looping so much in there. The - program was running faster before I re-factored a bunch of stuff and added this stupid loop. - -- Review engine frame-recording quirks. - -## Maintenance ideas - -See the ordered [modernization plan](modernization.md) for TypeScript, state, -UI, site-build, and remaining vendor-script migrations. +- Add a waveform visualization in the header during playback. +- Improve transitions and allow filtering which operations are shown or played. +- Add a reset-to-defaults action for audio controls. +- Make algorithm performance information easier to discover. It is already + available in the selected algorithm's Information tab; inline hints are optional. +- Support URL-based settings and a share-settings action. diff --git a/docs/ui-design.md b/docs/ui-design.md deleted file mode 100644 index f9246e4..0000000 --- a/docs/ui-design.md +++ /dev/null @@ -1,78 +0,0 @@ -# UI direction - -**Deferred:** migrate React/Tailwind/TanStack Start with the existing layout first. -This prototype is exploratory reference only; see [the current plan](modernization.md). - -Open [the interactive layout study](ui-prototype.html) directly in a browser. -It is self-contained, uses no dependencies, and is not included in the site build. -The layout switch, audio-mode selection, ranges, and disclosures work; charts are -sample data and playback, editing, and export are deliberately disconnected. - -## Two directions - -| | Two-tier workspace (recommended) | Sort-focused workspace | -| --------------- | --------------------------------------------------------------------- | ---------------------------------------------------------------- | -| Main area | Input and sorting are always visible, top and bottom. | Sorting gets the main area; input becomes a collapsible section. | -| Shared settings | One audio inspector beside both charts. | Same inspector; more room for the sorting chart. | -| Strength | Makes the relationship between input, sound, and sort easy to follow. | Better when mostly stepping through or editing algorithms. | -| Tradeoff | Less vertical room for each chart. | Comparing input with output requires opening the input section. | - -Start fresh with the presentation, not with the engine. The recommended direction -keeps the top/bottom relationship from the existing app without the narrow column -of counters or the settings panel determining both chart sizes. - -## Existing features to preserve - -- Input generators, data size, and direct dragging of input values. -- Separate input/sort transports: first/last, forward/reverse, stop, loop, scrubber. -- Algorithm selection, metadata, editable source, custom algorithms, and AutoPlay. -- Bar/flat renderers and comparison/swap/position counters. -- Shared volume, tempo, center note, scale, and waveform/soundfont selection. -- Eight waveform types with one shared envelope; native sample instruments/filter. -- MIDI export for either player, including filename, channel, and instrument. -- About/API pages, keyboard access, static hosting, and existing URL/base-path support. - -The prototype shows representative algorithms, scales, and instruments rather -than duplicating registries. It is a layout review, not a replacement application. -No new features are committed by this design step. In particular, multi-algorithm -comparison, saved presets, URL sharing, and new recording operations stay separate. - -## Interaction and responsive rules - -- Keep frequently used playback controls beside the visualization they control. -- Put counters on one horizontal strip, not between the catalog and chart. -- Use one shared audio inspector; expanding envelope settings must not push the - sorting workspace down on desktop. The inspector can scroll independently there. -- Start with one breakpoint at 900px: inspector beside charts above it, normal - document flow below it. No fixed-height clipping or nested inspector scrolling - on mobile. Mobile settings can collapse; charts remain above them. -- Use full labels, visible focus, native controls where useful, and reduced motion. -- Dialogs handle editing, metadata, and export without hiding their entry points. - -## Implementation after layout approval - -Deliver the functional workspace as one cohesive React migration: the page shell, -both charts/transports, algorithm controls, and shared audio inspector. Do not -mount React inside DOM still owned by the legacy controller. - -1. Add React/TypeScript and Tailwind; create an application hook that coordinates - the existing vanilla Jotai store, recorder/worker requests, transport, and audio. - Effects must dispose subscriptions, players, and pending work on unmount. -2. Give each D3 renderer exclusive ownership of its SVG subtree. React owns the - surrounding controls, labels, and layout, not the generated bars or markers. -3. Move edit/add and MIDI dialogs to selected accessible shadcn components; retain - lazy Ace loading and JavaScript algorithm source. Static registries remain imports. -4. Remove the legacy controller, Bootstrap/slider, and jQuery after their final - consumers migrate, including About/API shell styling. Preserve behavior rather - than compatibility shims for the old selectors. -5. Run feature-parity/browser checks at root and Pages paths, including keyboard - dialogs, dragging, native sample playback, and repeated mount/unmount. - -Keep Eleventy for this step. TanStack Start/static deployment remains phase 7; -do not combine the audio engine, UI, and site-builder migrations in one rewrite. - -## Review needed - -Choose the two-tier or sort-focused direction, identify any must-have new features, -and decide whether the audio inspector should be visible by default on mobile. -The light palette and spacing are a starting point, not a final visual identity. diff --git a/docs/ui-prototype.html b/docs/ui-prototype.html deleted file mode 100644 index 702c0d1..0000000 --- a/docs/ui-prototype.html +++ /dev/null @@ -1,598 +0,0 @@ - - - - - - Audio Sort · UI layout study - - - -
- Layout study · no audio - - - Playback, editing, and export are placeholders. -
-
-
-
-

Audio Sort

- See the pattern. Hear the process. -
- Workspace concept -
-
-
-
-
-

01Input data

-
- -
-
-
-
- Drag bars to adjust values in the finished app. -
- -
-
- -
- 1 / 24 -
- -
-
-
-
-

02Sorting

- -
-
-
- -
- -
-
- -
- -
- -
-
- Sample frame 48 / 276Comparisons 32Swaps 16Amber: comparing -
-
-
-
- Sound settings · shared -
- - - - - -
- -
- Amplitude envelope - - - -
- - - - - -
-
-
- -
-
-
-

- Design prototype only. Values are not saved; charts do not represent a running algorithm. - Compare layouts at desktop and mobile widths. -

-
- - -