Initial commit: Game Maker phase 1
Canvas-only 2D game editor/runtime built on PixiJS v8 + Vite + TypeScript. - core: asset model (Scene/Camera/Sprite), scene objects with sparse overrides, property schema + resolve, command stack (undo/redo), serialization and project store interface (16 unit tests) - ui: custom in-canvas widget toolkit (panels, fields, color picker, list/scroll, popup) with a hidden <input> keyboard bridge - editor: asset/hierarchy panels, schema-driven inspector, toolbar - viewport: box rendering, camera frame, selection gizmo, drag/zoom/pan - runtime: world/entity instantiation for play mode, input, camera follow - api: PHP JSON project store with revision counter (409 on conflict) - tools: CDP-based e2e smoke test Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
commit
5a46124454
65 files changed
+7193
No files matched your search
@@ -0,0 +1,88 @@
|
||||
# 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.** |
|
||||
|
||||
Phase-1 demo behaviour in Play: the arrow keys move the sprite that was selected when Play was
|
||||
pressed (or the first sprite); the first camera in the scene follows it.
|
||||
|
||||
## 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, systems (Input, PlayerControl, CameraFollow)
|
||||
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 headless CDP smoke test
|
||||
```
|
||||
|
||||
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/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.
|
||||
Reference in new issue
Block a user