Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions projects/lumen-atelier-8f3c/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
41 changes: 41 additions & 0 deletions projects/lumen-atelier-8f3c/JOURNAL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Lumen: The Lost Gardens — journal

An atmospheric puzzle game about restoring floating gardens with light. The campaign introduces six optical mechanisms over 48 puzzles; daily and seeded workshop gardens keep the game open-ended.

## Design

- Palette: parchment mist `#f0f3ed`, limestone `#d5dfca`, deep lagoon `#133d3c`, forest ink `#243e36`, sunlight `#e8bd70`, faded lilac `#ada6c0`.
- Typography: Cormorant Garamond for literary titles, DM Sans for clear interface text. All fonts bundled locally.
- Layout: calm botanical field guide surrounding a large, luminous isometric stone garden. The playable garden is the hero.
- Signature: light traces engraved paths across floating stone slabs and wakes faceted seed crystals.
- Aesthetic review: avoided a generic space dashboard; the botanical field-guide frame and tactile light-bearing ruins ground the interface in the game's subject.

## Ideas / backlog

- [x] 48 verified campaign puzzles across six chapters
- [x] Isometric interactive garden with keyboard and touch support
- [x] Daily puzzle and shareable seeded workshop gardens
- [x] Undo, restart, two-stage hints, chapter selection, and completion awards
- [x] Local progress, backup/import, settings, and optional synthesized audio
- [x] Field guide, narrative memories, and achievements
- [x] Responsive design and reduced motion support
- [x] Custom static catalog thumbnail
- [x] Engine and browser interaction verification
- [x] Run exact repository gate and publish a PR
- [ ] Future: a freeform tile editor and community puzzle exchange

## Session log

- 2026-09-24 (codex, gpt-6): Started from the required template; established visual direction and parallelized puzzle engine, garden renderer, and persistence/audio work.

- 2026-09-24 (codex, gpt-6): Shipped the full campaign, atlas, daily/workshop, eight achievements, journal ending, responsive isometric renderer, synthesized audio, local sessions, safe progress backups, and accessibility settings. Verified all 48 solutions and 600 generated boards with 11 engine tests; browser tests cover real pointer solves, gates/bridges/portals, hints/undo, backups, mobile, and the ending. Fixed deep-link resume, storage failure reporting, and saved ambience without autoplay. Exact repository conformance/lint/build/output gate passed.

## Follow-up notes

- The canonical guide turn count is a known valid solution budget; it is not an optimality proof.
- The workshop generates reproducible boards from seeds. A freeform tile editor remains a separate future feature.
- Save data is device-local. Export transfers completed gardens; only the active arrangement is saved locally and undo history resets on reload.
- Font subsets are bundled locally; game, art, and audio need no external services.
- See README.md for development and verification commands.

- 2026-09-24 (codex, gpt-6): Final release verified with 11 engine tests, 13 browser scenarios, and the exact repository gate. Publishing the isolated project branch through the mandatory auto-merge PR workflow.
60 changes: 60 additions & 0 deletions projects/lumen-atelier-8f3c/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Lumen: The Lost Gardens

An unhurried light-routing puzzle game. Rotate carved stone channels on a floating garden to connect a sun well to every sleeping crystal.

## Play

- **48 campaign gardens** across six chapters, with an ending and six recoverable journal memories.
- **Six evolving rules:** turning channels, branches, rooted stones, directional gates, isolated bridges, and paired portals.
- **A daily garden** shared by UTC date, with date links that remain replayable.
- **Seeded workshop gardens:** choose a chapter's rules and any 32-bit seed; share the resulting URL.
- **Three-bloom awards**, eight achievements, unlimited undo/restart, and optional two-step hints.
- **Local saves and portable backups**, keyboard support, reduced motion, contrast settings, and optional synthesized sound and ambience.
- Every chapter is open from the beginning. There are no timers, accounts, ads, or network game services.

## Controls

| Action | Mouse / touch | Keyboard |
| --- | --- | --- |
| Turn a stone clockwise | Click / tap | Tab to stone, then Enter or Space |
| Turn counterclockwise | Shift + click | Shift + Enter / Space |
| Move focus across stones | — | Arrow keys |
| Undo | Undo | Z or U |
| Restart | Restart | R |
| Hint | A gentle nudge | H |
| Field guide | Help / Field guide | ? |
| Close dialog / leave focus mode | Close | Escape |

A hint first identifies a useful stone. Request it again to rotate that stone to the guide solution. Hints reduce the current attempt's award to one bloom. Three blooms require a solution within the displayed turn guide without hints; any other unassisted solution earns two. The guide is a known-solution budget, not a claim of a mathematically shortest solution. Undo preserves the hint count; restarting begins a new attempt. Best awards remain saved when replaying.

Progress and the current garden's arrangement are saved locally. Export/import in Settings transfers completed gardens; it does not transfer an unfinished arrangement or undo history. Importing preserves existing best scores. If storage is unavailable, playing still works and the footer advises creating a backup. Saved ambience begins after the next player interaction; audio never starts on page load.

## Development

```sh
pnpm install
pnpm dev
pnpm lint
pnpm build
node --test tests/game.test.mjs
pnpm exec playwright install chromium
pnpm exec playwright test
```

Use Node 24 for the engine tests (native TypeScript stripping). Browser tests accept `PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH` when Chromium is already installed elsewhere. Playwright starts a local Vite server and keeps screenshots/traces under ignored `node_modules/.cache/`.

Run the repository's exact release gate from the repository root:

```sh
node scripts/verify-project.mjs lumen-atelier-8f3c
```

## Implementation

- `src/game.ts`: deterministic generation, solutions, light propagation, and hints. Sources and receivers are fixed; light requires reciprocal ports. A bridge keeps its two channels isolated, gates accept only the correct incoming direction, and matched portals connect distant components. Visited entry states prevent infinite cycles.
- `src/Board.tsx`: responsive interactive SVG with procedural stone, crystal, plant, and light artwork; no image downloads.
- `src/App.tsx`: campaign, atlas, workshop, journal, settings, awards, hash routing, and current-session state.
- `src/progress.ts`: validated persistent records and portable, mergeable backups.
- `src/audio.ts`: small Web Audio instrument with lazy creation and explicit cleanup.

All imagery, typography, and code are served from the app's relative Vite base. The only runtime persistence is browser local storage. No tracking or third-party requests.
22 changes: 22 additions & 0 deletions projects/lumen-atelier-8f3c/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'
import { defineConfig, globalIgnores } from 'eslint/config'

export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
js.configs.recommended,
tseslint.configs.recommended,
reactHooks.configs.flat.recommended,
reactRefresh.configs.vite,
],
languageOptions: {
globals: globals.browser,
},
},
])
15 changes: 15 additions & 0 deletions projects/lumen-atelier-8f3c/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="./favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#f0f3ed" />
<meta name="description" content="A quiet adventure in light. Restore 48 floating gardens, discover six puzzle mechanics, and return for a new garden every day." />
<title>Lumen — The Lost Gardens</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
36 changes: 36 additions & 0 deletions projects/lumen-atelier-8f3c/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "lumen-lost-gardens",
"private": true,
"version": "1.0.0",
"type": "module",
"packageManager": "pnpm@11.5.2",
"scripts": {
"preinstall": "npx only-allow pnpm",
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"@fontsource/cormorant-garamond": "^5.3.0",
"@fontsource/dm-sans": "^5.3.0",
"lucide-react": "^1.47.0",
"react": "^19.2.6",
"react-dom": "^19.2.6"
},
"devDependencies": {
"@eslint/js": "^10.0.1",
"@playwright/test": "^1.63.0",
"@types/node": "^24.12.3",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^6.0.1",
"eslint": "^10.3.0",
"eslint-plugin-react-hooks": "^7.1.1",
"eslint-plugin-react-refresh": "^0.5.2",
"globals": "^17.6.0",
"typescript": "~6.0.2",
"typescript-eslint": "^8.59.2",
"vite": "^8.0.12"
}
}
25 changes: 25 additions & 0 deletions projects/lumen-atelier-8f3c/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { defineConfig } from '@playwright/test'

export default defineConfig({
testDir: './tests',
testMatch: '**/*.spec.ts',
timeout: 60000,
expect: { timeout: 8000 },
fullyParallel: true,
workers: 3,
reporter: 'list',
outputDir: 'node_modules/.cache/playwright-results',
use: {
baseURL: 'http://127.0.0.1:5174',
viewport: { width: 1440, height: 1000 },
reducedMotion: 'reduce',
trace: 'retain-on-failure',
screenshot: 'only-on-failure',
launchOptions: { executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH },
},
webServer: {
command: 'pnpm dev --host 127.0.0.1 --port 5174 --strictPort',
url: 'http://127.0.0.1:5174',
reuseExistingServer: !process.env.CI,
},
})
Loading
Loading