Files
feuerwerk/README.md
T
rootandClaude Fable 5.1 aaa8154adf Camera view frame, viewport clipping, overlay layer for editor symbols
- Camera assets get width/height properties; play mode renders only the
  camera frame (letterboxed, masked, culled) and nothing without a camera
- Remove demo arrow-key/camera-follow systems from play mode
- Clip world and gizmos to the viewport (selection frame no longer leaks
  over the left panel)
- Blur focused widget on pointerdown outside it so inspector edits commit
  before selection changes
- Separate objects/overlay layers so camera symbols always render on top
- Add tools/seed-demo.mjs for reproducible E2E runs

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 11:13:08 +02:00

99 lines
5.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Game Maker
A browser-based tool "one step before a game engine": create **assets** (scenes, cameras,
sprites), place them into scenes, tweak their properties in an inspector and press **Play** –
all in one program, all drawn inside a single WebGL canvas.
Live: <https://nockal.com/game-maker/> · Widget playground: <https://nockal.com/game-maker/?playground>
## Concepts
| Term | Meaning |
|---|---|
| **Asset** | Named thing with a type (`scene`, `camera`, `sprite`) and typed properties. Assets have **no position**. |
| **Scene object** | An asset placed into a scene: a link to the asset + a **position** + sparse **overrides** of the asset's properties. Scenes cannot be placed. |
| **Override** | A per-object value that replaces the asset's value for one property. Only changed keys are stored; the inspector marks them bold and offers a reset (↺). |
| **Edit mode** | The viewport draws the project model; panels, grid, gizmos and drag-to-move are active. |
| **Play mode** | A `World` is instantiated from the active scene (one entity per scene object, resolved properties as mutable state). Systems tick it; nothing writes back. **Stop discards the world.** |
**The camera defines what is rendered.** A camera asset has a view size (`width` × `height`,
default 640×360) and a `zoom`; the frame it covers in world units is `size / zoom`. In edit
mode that frame is drawn as an outline. In play mode only that frame is rendered – fitted into
the viewport with black letterboxing – and objects outside it are culled. A scene without a
camera renders nothing in play mode. Play has no built-in behaviour (no input, no movement):
behaviour will come with scripting in a later phase.
**Editor symbols are always on top.** The viewport draws scene content (sprites) in an
`objects` layer and editor symbols (camera icon, labels) in an `overlay` layer above it, so a
sprite can never hide a symbol regardless of hierarchy order. Z-order between sprites is not
configurable yet.
## Stack
- **PixiJS v8** – rendering and pointer events. No game engine; runtime systems live in `src/runtime/`.
- **Own canvas widget toolkit** (`src/ui/`) – panels, buttons, lists, text/number/color fields,
popups. The only DOM element is a hidden `<input>` used as a keyboard bridge (IME, mobile
keyboard, clipboard) while a canvas text field is focused.
- **Vite + TypeScript**, **Vitest** for the pure core.
- **PHP 8** JSON API (`api/`) storing one JSON file per project in `data/projects/`, with
atomic writes and an integer revision that rejects stale saves (HTTP 409).
## Layout
```
web/index.html Vite source page (dev) index.html built page (generated, served)
src/core/ model, property schema, resolve, commands, store – no Pixi imports
src/runtime/ World, Entity, System interface, Input tracker (no systems yet)
src/ui/ widget toolkit (generic, knows nothing about assets)
src/viewport/ scene renderer: model in edit mode, world in play mode
src/editor/ App composition, state, panels, inspector field factory
api/ PHP backend data/projects/ persisted projects
tests/ Vitest unit tests tools/ e2e.mjs (CDP smoke test), seed-demo.mjs
```
Rules that keep it organised: `core/` imports nothing from other layers; `ui/` never sees
assets; position exists only on scene objects; overrides are merged in exactly one place
(`core/properties/resolve.ts`); the inspector is generated from `PropertySchema` – a new
property is one schema line.
## Development
Node 22 is required (on this machine: `PATH=/opt/node22/bin:$PATH`).
```bash
npm install
npm run dev # http://localhost:5175/game-maker/dist/ – API calls are proxied to production
npm test # unit tests (core)
npm run typecheck
npm run build # writes dist/ and regenerates index.html
node tools/seed-demo.mjs <projectId> # reset the demo project to the state the e2e run expects
node tools/e2e.mjs <projectId> # headless end-to-end run with screenshots in /tmp/gm-e2e-*.png
```
The workspace folder itself is what nginx serves, so `npm run build` is the deployment.
## API
All routes go through `api/index.php?r=…` (the site's nginx does not pass `PATH_INFO`).
| Method | Route | Body → Result |
|---|---|---|
| GET | `projects` | `[{id,name,revision,updatedAt}]` |
| POST | `projects` | `{name}` → project document (201) |
| GET | `projects/{id}` | `{id,name,revision,updatedAt,project}` |
| PUT | `projects/{id}` | `{revision, project}` → `{revision,updatedAt}` or **409** `{revision}` when stale |
| DELETE | `projects/{id}` | 204 |
There is no authentication yet; `data/` is world-readable. Both are phase-2 topics.
## Keyboard
`Ctrl+Z` / `Ctrl+Shift+Z` / `Ctrl+Y` undo/redo · `Delete` remove selection · `Ctrl+Enter` play ·
`Esc` stop · `Tab` cycles fields · number fields: drag to scrub (`Shift` ×10, `Alt` ×0.1),
`↑`/`↓` step · viewport: wheel zooms, middle-drag or `Shift`+drag pans.
## Out of scope for phase 1
Textures on sprites, physics, scripting, multi-select, z-order UI, auth, editing while playing,
touch-optimised layout.