plum
git clone https://git.pyrossh.dev/plum
A statically typed, imperative programming language inspired by rust, python
7aa0d3b
— Peter John
2026-11-03T20:34:45+05:30
docs(plans): pure scene enums: game kinds stay records in a union enum
docs/plans/2026-11-03-pure-scene-enums.review.md
CHANGED
|
@@ -17,10 +17,13 @@ This plan moves all of it to enums (user decision 2026-11-03: pure scene only; s
|
|
|
17
17
|
- `Kind[K]` is an inline-variant enum: `Group(children)`, `Sprite(texture region)`, `Label(text, size)`, `Button(text, textures, pressed, over)` and `Custom(body: K)`.
|
|
18
18
|
- `n.x` stays a plain field read, and there's no 14-field header to repeat.
|
|
19
19
|
- Narrowing back to a kind is a `match`. That fixes phase A's known gap: a trait value from the tree couldn't be narrowed back to its record.
|
|
20
|
-
- **The game brings its own kinds.**
|
|
21
|
-
- `game_pure_scene`
|
|
22
|
-
-
|
|
23
|
-
-
|
|
20
|
+
- **The game brings its own kinds, as records (user decision 2026-11-03).**
|
|
21
|
+
- `game_pure_scene` keeps `Panel`, `Ship`, `Orb`, `Mine` and `Star` as plain records. Each holds only its own fields (clock, velocity, phase, texture...) and its own `act` and `draw` methods. They no longer embed a trait or repeat the 14-field header.
|
|
22
|
+
- The records are joined by a union enum, `enum Body = Panel | Ship | Orb | Mine | Star`. A call like `b.act(node, dt)` on a `Body` dispatches to the right record with no `match` (checked by a probe).
|
|
23
|
+
- The game builds a `Node[Body]` tree.
|
|
24
|
+
- std finds the body in a `Custom(body)` node and calls two functions the game passes in, giving each the body and the node: `act(body, node, dt)` and `draw(body, node, matrix, tint)`.
|
|
25
|
+
- In the game these are one-liners: `fun actBody(b: Body, n: Node[Body], dt: Float) = b.act(n, dt)`. A body's method can move the node (`n.x = ...`) and change its own fields in place.
|
|
26
|
+
- `SceneTree.update(root, dt, actBody)` and `PureScene.drawTree(root, drawBody)` call them for `Custom` nodes. `Group`, `Sprite`, `Label` and `Button` are handled by std itself.
|
|
24
27
|
- Closure specialisation inlines the passed functions, so there's no indirect call per node.
|
|
25
28
|
- **Hit-testing and input are unchanged in behaviour.**
|
|
26
29
|
- A `Custom` node hits on its box, like today's default.
|
|
@@ -36,7 +39,7 @@ This plan moves all of it to enums (user decision 2026-11-03: pure scene only; s
|
|
|
36
39
|
## What you will get
|
|
37
40
|
- `PureScene`, `SceneTree`, `SceneInput` and `Actions` with no `trait`, no `override` and no union-of-records enums.
|
|
38
41
|
- `game_pure_scene.plum` and the `stress_pure_scene` web fixture on `Node[Body]`.
|
|
39
|
-
-
|
|
42
|
+
- Each kind is a small record with its own methods, joined by a union enum `Body`.
|
|
40
43
|
- Same rules, keys, assets, sounds and scoring.
|
|
41
44
|
- README's pure-scene section and the std doc comments updated to the new shape.
|
|
42
45
|
|
|
@@ -46,14 +49,14 @@ This plan moves all of it to enums (user decision 2026-11-03: pure scene only; s
|
|
|
46
49
|
| Actions on enums | `Action` record + `ActionKind` enum; in-place stepping kept; golden-value tests unchanged in values | M |
|
|
47
50
|
| PureScene on enums | `Node[K]`, `Kind[K]`, builders (`group`, `sprite`, `label`, `button`, `custom`), drawing, hit test, Button's pointer handling | M |
|
|
48
51
|
| SceneTree and SceneInput | update/find/hit/stage over `Node[K]` with the game's `act` (and `draw` passed through drawing) | M |
|
|
49
|
-
| Orb Run on Node[Body] | `game_pure_scene.plum`: `enum Body`, `actBody`
|
|
52
|
+
| Orb Run on Node[Body] | `game_pure_scene.plum`: kind records with `act`/`draw` methods, `enum Body = Panel \| Ship \| ...`, one-line `actBody`/`drawBody`; tests kept by name and value | M |
|
|
50
53
|
| Fixture, host checks, docs | `stress_pure_scene.plum`, host parity and draw-count tests, README | S |
|
|
51
54
|
| Benchmark | Headed Chromium run against the mutable scene, same bar as before | S |
|
|
52
55
|
|
|
53
56
|
## How it fits together
|
|
54
57
|
```mermaid
|
|
55
58
|
flowchart LR
|
|
56
|
-
G["game: enum Body, actBody, drawBody"] --> T["SceneTree.update(root, dt, actBody)"]
|
|
59
|
+
G["game: records Ship, Orb, ... + enum Body, actBody, drawBody"] --> T["SceneTree.update(root, dt, actBody)"]
|
|
57
60
|
G --> D["PureScene.drawTree(root, drawBody)"]
|
|
58
61
|
T --> N["own record Node[K] + enum Kind[K]"]
|
|
59
62
|
D --> N
|
|
@@ -84,7 +87,7 @@ flowchart LR
|
|
|
84
87
|
- The supercompiler (next plan).
|
|
85
88
|
|
|
86
89
|
## How we will know it works
|
|
87
|
-
- `grep` finds no `trait`
|
|
90
|
+
- `grep` finds no `trait` or `override` in the four std modules or `game_pure_scene.plum`, and no record-union enum in the std modules (the game's `Body` union is intended).
|
|
88
91
|
- Actions golden tests and every `game_pure_scene` test pass, with the same names and values.
|
|
89
92
|
- Host parity and draw-count tests pass: the pure scene draws the same count as the mutable scene. The `pureScene*` browser check passes.
|
|
90
93
|
- Full suites stay green: Plum std/examples (632+) and the Rust crates.
|