From 2347ecd20103465fcb06c24b0e81ce3d6196648f Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Wed, 13 May 2026 22:13:15 +0100 Subject: [PATCH] . --- .forgejo/workflows/deploy.yml | 20 +- .gitignore | 2 + README.md | 7 + e2e/app.spec.ts | 23 + index.html | 39 +- package-lock.json | 64 + package.json | 11 +- playwright.config.ts | 32 + public/apple-touch-icon-180x180.png | Bin 908 -> 1234 bytes public/favicon.ico | Bin 587 -> 914 bytes public/favicon.svg | 33 +- public/maskable-icon-512x512.png | Bin 2989 -> 3481 bytes public/pwa-192x192.png | Bin 1180 -> 1687 bytes public/pwa-512x512.png | Bin 3117 -> 4160 bytes public/pwa-64x64.png | Bin 488 -> 709 bytes scripts/check-unused-exports.mjs | 185 +++ src/audio/garden-audio-config.ts | 4 +- src/audio/garden-audio-energy.ts | 12 +- src/audio/garden-audio-graph.ts | 35 +- src/audio/garden-audio-input.ts | 34 +- src/audio/garden-audio-music.ts | 13 - src/audio/garden-audio-types.ts | 10 + src/audio/garden-audio.ts | 137 +- src/audio/generative-piano.test.ts | 230 +++- src/audio/generative-piano.ts | 1126 ++++++++++------- src/audio/noise-burst-player.ts | 21 +- src/audio/piano-sampler.ts | 176 ++- src/audio/piano-samples.ts | 2 +- src/config.ts | 689 +--------- src/config/color-interactions.ts | 71 ++ src/config/runtime-settings.ts | 206 +++ src/config/types.ts | 287 +++++ src/config/vibe-presets.ts | 204 +++ src/constants.ts | 1 - src/game-loop/agent-population.test.ts | 86 ++ src/game-loop/agent-population.ts | 68 +- src/game-loop/export-4k.ts | 12 +- src/game-loop/game-loop-intro.test.ts | 28 + src/game-loop/game-loop.ts | 52 +- src/game-loop/game-presentation.ts | 21 - src/game-loop/game-rules.ts | 124 -- src/game-loop/pointer-input.test.ts | 277 ++++ src/game-loop/pointer-input.ts | 174 ++- src/game-loop/simulation-frame.ts | 2 +- src/index.dom-contract.test.ts | 4 +- src/index.scss | 2 + src/index.ts | 104 +- src/page/config-pane.ts | 170 ++- src/page/full-screen-handler.ts | 13 +- src/page/menu-hider.ts | 47 +- .../agents/agent-generation/agent.ts | 11 - src/pipelines/agents/agent-pipeline.ts | 20 +- src/pipelines/agents/agent-settings.ts | 9 + src/pipelines/agents/agent.wgsl | 56 +- src/pipelines/brush/brush-settings.ts | 1 + src/pipelines/wgsl-uniform-layout.test.ts | 9 + src/settings.ts | 3 +- src/style/_app-shell.scss | 21 + src/style/_config-pane.scss | 69 + src/style/_control-dock.scss | 32 +- src/style/_loading.scss | 120 ++ src/style/_panels.scss | 36 + src/utils/browser-storage.ts | 17 + src/utils/dom.ts | 63 + src/utils/error-handler.ts | 13 +- src/utils/format-number.test.ts | 22 - src/utils/format-number.ts | 11 - src/utils/graphics/cached-buffer-write.ts | 2 +- src/vibes.test.ts | 22 + src/vibes.ts | 3 +- tsconfig.playwright.json | 7 + 71 files changed, 3799 insertions(+), 1606 deletions(-) create mode 100644 e2e/app.spec.ts create mode 100644 playwright.config.ts create mode 100644 scripts/check-unused-exports.mjs create mode 100644 src/config/color-interactions.ts create mode 100644 src/config/runtime-settings.ts create mode 100644 src/config/types.ts create mode 100644 src/config/vibe-presets.ts delete mode 100644 src/constants.ts create mode 100644 src/game-loop/agent-population.test.ts create mode 100644 src/game-loop/game-loop-intro.test.ts delete mode 100644 src/game-loop/game-presentation.ts delete mode 100644 src/game-loop/game-rules.ts create mode 100644 src/game-loop/pointer-input.test.ts create mode 100644 src/style/_config-pane.scss create mode 100644 src/style/_loading.scss create mode 100644 src/utils/browser-storage.ts create mode 100644 src/utils/dom.ts delete mode 100644 src/utils/format-number.test.ts delete mode 100644 src/utils/format-number.ts create mode 100644 tsconfig.playwright.json diff --git a/.forgejo/workflows/deploy.yml b/.forgejo/workflows/deploy.yml index b50603f..93748c6 100644 --- a/.forgejo/workflows/deploy.yml +++ b/.forgejo/workflows/deploy.yml @@ -27,17 +27,33 @@ jobs: - name: Install dependencies run: npm ci + - name: Install Playwright browsers + run: npx playwright install --with-deps chromium + - name: Lint run: npm run lint - name: Typecheck run: npm run typecheck + - name: Typecheck browser tests + run: npm run typecheck:e2e + - name: Test run: npm test - - name: Build - run: npm run build + - name: Browser tests + run: npm run test:e2e + + - name: Upload Playwright report + if: failure() + uses: actions/upload-artifact@v4 + with: + name: playwright-report + path: | + playwright-report/ + test-results/ + retention-days: 7 - name: Copy build to host pages mount if: github.event_name == 'push' && github.ref == 'refs/heads/main' diff --git a/.gitignore b/.gitignore index 14d1e17..916a63e 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,8 @@ ts-node--*/ rss.xml dist +playwright-report +test-results # Logs logs diff --git a/README.md b/README.md index 56bf279..1a7466c 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,10 @@ draw persistent coloured paths, spawn agents from those strokes, erase locally, and export the scene as a 4K wallpaper. Check out the [agent logic](./src/pipelines/agents/agent.wgsl). + +## Testing + +- `npm test` runs the Vitest unit suite. +- `npm run test:e2e` builds the production bundle and runs the Playwright Chromium + smoke test. +- `npx playwright install chromium` installs the local browser binary when needed. diff --git a/e2e/app.spec.ts b/e2e/app.spec.ts new file mode 100644 index 0000000..e42de2f --- /dev/null +++ b/e2e/app.spec.ts @@ -0,0 +1,23 @@ +import { expect, test } from '@playwright/test'; + +test('loads the app shell and WebGPU fallback in Chromium', async ({ page }) => { + await page.addInitScript(() => { + Object.defineProperty(navigator, 'gpu', { + configurable: true, + value: undefined, + }); + }); + + await page.goto('/'); + + await expect(page).toHaveTitle('Fleeting Garden'); + await expect( + page.getByRole('img', { name: 'Interactive generative garden canvas' }) + ).toBeVisible(); + await expect(page.getByRole('toolbar', { name: 'Garden toolbar' })).toBeVisible(); + await expect(page.locator('body')).not.toHaveClass(/is-loading/); + await expect(page.getByRole('alert')).toContainText('Fleeting Garden needs WebGPU'); + + await page.getByRole('button', { name: 'About' }).click(); + await expect(page.getByRole('heading', { name: 'Fleeting Garden' })).toBeVisible(); +}); diff --git a/index.html b/index.html index 8db16b3..1957196 100644 --- a/index.html +++ b/index.html @@ -6,7 +6,7 @@ name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover" /> - + Fleeting Garden - +