@flatkit/compiler 0.35.3 → 0.36.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/flatc.mjs +8 -1
- package/dist/analysis.js +1 -1
- package/dist/{chunk-W3YUC6BC.js → chunk-43MGBTUK.js} +174 -5
- package/dist/chunk-43MGBTUK.js.map +1 -0
- package/dist/cli/flatc.js +18 -12
- package/dist/cli/flatc.js.map +1 -1
- package/dist/cli/render.js +1 -1
- package/dist/cli/render.js.map +1 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/docs/animating-symbols.md +8 -3
- package/docs/behavior-and-interactions.md +27 -2
- package/docs/dsl-gotchas.md +16 -6
- package/docs/expressions-and-stdlib.md +3 -2
- package/docs/host-integration.md +38 -1
- package/docs/scene-and-drawing.md +38 -0
- package/docs/tooling.md +5 -0
- package/package.json +4 -4
- package/prompts/flatink-core.md +3 -2
- package/prompts/flatink-lite.md +2 -1
- package/prompts/role-asset-creator.md +3 -1
- package/dist/chunk-W3YUC6BC.js.map +0 -1
|
@@ -303,18 +303,23 @@ symbol "Boat" {
|
|
|
303
303
|
```
|
|
304
304
|
|
|
305
305
|
- `params { <type> <name> = <default> [range <min> <max>] ["doc"] … }` — `<type>` is `color`, `number`,
|
|
306
|
-
or `
|
|
306
|
+
`bool` or `text`. The default, range, and doc string make the interface self-describing.
|
|
307
307
|
- **`color` params** are used as a paint — `fill hull`, `stroke hull <width>`, a **gradient stop**
|
|
308
308
|
(`0:hull@0.8`, optional `@alpha`), or a **`tint hull <amount>`** (anywhere a `#color` literal goes).
|
|
309
309
|
Resolved per instance at render; *not* available in numeric expressions.
|
|
310
|
+
- **`text` params** are what a text says — `text libelle at …` (the bare name instead of a quoted
|
|
311
|
+
string) draws the instance's value: a reusable button carries its own label. Declared with a quoted
|
|
312
|
+
default: `text libelle = "OK" "label of the button"`.
|
|
310
313
|
- **`number` / `bool` params** become **variables in the symbol's expressions** (`wave`, `flag`). `bool`
|
|
311
314
|
reads as `1`/`0`. (`flatc --check` knows them — reading a declared param in an `expr` is not an "unknown
|
|
312
315
|
variable".)
|
|
313
316
|
|
|
314
317
|
> The `timeline`, `params`, and `states` header blocks may appear in **any order** before the layers.
|
|
315
318
|
|
|
316
|
-
Set params at the instance **call-site** (literals), in `--preview`, or
|
|
317
|
-
|
|
319
|
+
Set params at the instance **call-site** (literals), in `--preview`, or at runtime (see below):
|
|
320
|
+
`Boat.wave = 1.5` for a `number`/`bool` (any expression), `Boat.hull = #33aa33` for a `color` (a color
|
|
321
|
+
literal), `Bouton.libelle = "Bravo"` for a `text` (a quoted text). `flatc --check` reports a param the
|
|
322
|
+
symbol does not declare, a value of the wrong type or out of its range, and a state that does not exist.
|
|
318
323
|
|
|
319
324
|
```
|
|
320
325
|
instance "Boat" as "Hero" at center { hull = #1a5f3a, wave = 1.5, flag = false }
|
|
@@ -154,7 +154,8 @@ object "Piece" {
|
|
|
154
154
|
target index is the exception: it resolves to `0` — "no target reached" — on a gated-off release, so it
|
|
155
155
|
can never hand you the previous gesture's answer.)
|
|
156
156
|
- **Drop zones**: by default the object's **center** is tested against the zone; `at pointer` tests the
|
|
157
|
-
pointer instead. Define an explicit rectangle with `group "Zone" … hitbox <w> <h> { … }
|
|
157
|
+
pointer instead. Define an explicit rectangle with `group "Zone" … hitbox <w> <h> { … }` — it is also
|
|
158
|
+
where the object is touched (click, press, drag, hover) when nothing drawn inside it is hit first.
|
|
158
159
|
- Several `when dropped on` per object are evaluated in declaration order (the right-zone / wrong-zones pattern).
|
|
159
160
|
- **`match` sugar** factors the whole drag+drop boilerplate — see [factoring](#reuse--factoring).
|
|
160
161
|
|
|
@@ -393,9 +394,33 @@ object "Card" {
|
|
|
393
394
|
}
|
|
394
395
|
```
|
|
395
396
|
|
|
397
|
+
## Keyboard access (`focusable`)
|
|
398
|
+
|
|
399
|
+
An object that declares `focusable` can be reached and used **without a pointer**:
|
|
400
|
+
|
|
401
|
+
```
|
|
402
|
+
object "Validate" {
|
|
403
|
+
focusable order 3 # order is optional: ranked objects first (lower first), then the others in document order
|
|
404
|
+
when clicked { check() } # Enter or Space on the focused object fires this too
|
|
405
|
+
}
|
|
406
|
+
object "Hint" {
|
|
407
|
+
focusable noring # no default ring: this object draws its own…
|
|
408
|
+
opacity = self.focused ? 1 : 0.7 # …from `self.focused` (1 while it holds the focus)
|
|
409
|
+
}
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
- **Tab / Shift+Tab** walk the focusable objects; **Enter** and **Space** click the focused one (its
|
|
413
|
+
`when clicked`). An object that is not shown (opacity 0, or absent from the picture) is skipped.
|
|
414
|
+
- The player draws a **focus ring** around the focused object — around its `hitbox` when it has one.
|
|
415
|
+
`noring` leaves the drawing to the scene.
|
|
416
|
+
- The focus is a stop, not a trap: past the last object (or before the first), Tab goes back to the page.
|
|
417
|
+
- Using the pointer drops the keyboard focus, like `:focus-visible` on a web page.
|
|
418
|
+
- Under `flatc --play`, `{ "type": "key", "name": "Tab" }` moves the focus and `"Enter"` clicks, so a
|
|
419
|
+
keyboard path is tested like any other.
|
|
420
|
+
|
|
396
421
|
## Feedback
|
|
397
422
|
|
|
398
|
-
An object can read **its own interaction state** in channel expressions: `self.hovered`, `self.grabbed`,
|
|
423
|
+
An object can read **its own interaction state** in channel expressions: `self.focused`, `self.hovered`, `self.grabbed`,
|
|
399
424
|
`self.pressed` (each `0`/`1`). So hover-lift and grab-squash are just expressions — no mirror variable,
|
|
400
425
|
no handler:
|
|
401
426
|
|
package/docs/dsl-gotchas.md
CHANGED
|
@@ -114,7 +114,9 @@
|
|
|
114
114
|
(local, on the roster item) = the center of rotation/scale; `at x,y` (on the pose) = where the local
|
|
115
115
|
origin lands. `spin cw|ccw` / `turns N` also turn around the pivot.
|
|
116
116
|
- **`expr rotation` is in RADIANS**, like `sin`/`cos`. Stay in degrees with the helpers: `rad(45)`,
|
|
117
|
-
`turns(time)` (one turn per second), `deg(r)`. e.g. `expr rotation "turns(time * 0.5)"`.
|
|
117
|
+
`turns(time)` (one turn per second), `deg(r)`. e.g. `expr rotation "turns(time * 0.5)"`. Or write
|
|
118
|
+
`expr rotationDeg "<degrees>"`, the degree twin (as in a behavior block). Any other channel name is a
|
|
119
|
+
compile error.
|
|
118
120
|
- **`time` WRAPS at `durationFrames`** (the timeline loops), so `sin(time * f)` with an arbitrary `f`
|
|
119
121
|
**jumps** every loop — and a `.flatink` with no `timeline` defaults to **60 frames (2.5 s @24fps)**, so
|
|
120
122
|
the jump is frequent. For free-running ambiance use **`clock`** (monotone, never wraps): `sin(clock * f)`.
|
|
@@ -170,8 +172,16 @@
|
|
|
170
172
|
- **Drop semantics**: by default the **object's center** (its x/y channels) is tested against
|
|
171
173
|
the zone. Two levers to match human expectations:
|
|
172
174
|
- `when dropped on Zone at pointer { … }`: tests the **POINTER position** (not the center).
|
|
173
|
-
- `group "Zone" … hitbox <W> <H> { … }`: an **explicit
|
|
174
|
-
origin, ±W/2 × ±H/2) instead of the content bbox. Replaces invisible `#ffffff01` paths.
|
|
175
|
+
- `group "Zone" … hitbox <W> <H> { … }`: an **explicit rectangle** (centered on the
|
|
176
|
+
origin, ±W/2 × ±H/2) instead of the content bbox. Replaces invisible `#ffffff01` paths. Works on an
|
|
177
|
+
`instance` too.
|
|
178
|
+
- **`hitbox` is also where the object is TOUCHED** — clicked, pressed, dragged, hovered — whenever
|
|
179
|
+
nothing drawn inside it is hit first. Use it for a stroke-only ring (only the stroke is touched
|
|
180
|
+
otherwise, not the middle), a small handle that deserves a finger-sized target, or an empty group laid
|
|
181
|
+
over a picture. The rectangle follows the object. What is drawn ABOVE it keeps the pointer.
|
|
182
|
+
- **What lets the pointer through**: `nohit`, a hidden item, and anything whose `opacity` is `0.01` or
|
|
183
|
+
less — with or without a `hitbox`. An invisible touch area is an empty group with a `hitbox`, at full
|
|
184
|
+
opacity: there is nothing to draw.
|
|
175
185
|
- **Locking a placed object**: `drag x, y { enabled <expr> }`. The drag is active only while
|
|
176
186
|
the expression is ≠ 0. No more `x = (p==1) ? Zone.x : xv` + `if p==0` guard patterns.
|
|
177
187
|
- **Event order on release**: `when released` fires **BEFORE** the drop test (useful to lower a
|
|
@@ -225,9 +235,9 @@ Inside an `object "Name" { … }`, besides `drag x, y` / `dragX` / `dragY`:
|
|
|
225
235
|
See [Behavior](behavior-and-interactions.md#seeing-where-it-was-scratched-reveal--cells).
|
|
226
236
|
- A `reveal` target is grabbable **over its whole zone**, whatever its content looks like — so a veil
|
|
227
237
|
stays scratchable where its cells have already gone to `opacity 0`. (Everywhere else, an item at
|
|
228
|
-
`opacity 0` lets the pointer through; a group whose children are ALL invisible is not hit
|
|
229
|
-
|
|
230
|
-
|
|
238
|
+
`opacity 0` lets the pointer through; a group whose children are ALL invisible is not hit unless
|
|
239
|
+
it declares a `hitbox`. Only a replayed `down/move/up` script shows this class of bug: a static
|
|
240
|
+
render looks perfect.)
|
|
231
241
|
- **`link <endX>, <endY>, <target> to <TargetsGroup> [{ enabled <expr> }]`**: pull an elastic
|
|
232
242
|
thread toward a target. During the drag, `<endX>`/`<endY>` = pointer position (DRAW the
|
|
233
243
|
thread yourself with expressions, e.g. a region connecting the object to `endX,endY`). On
|
|
@@ -50,9 +50,10 @@ per second), `deg(r)` (the inverse, for readouts). Or bind the **`rotationDeg`**
|
|
|
50
50
|
| `frame` | current frame (0-based; also wraps at `durationFrames`) |
|
|
51
51
|
| `value` | the channel's current value (in a channel binding) |
|
|
52
52
|
| `mouse.x` `mouse.y` | pointer position (scene units) |
|
|
53
|
-
| `
|
|
53
|
+
| `random()` | a number in `[0, 1[`, a new one at each call. Reproducible when the player is given a `seed` (always the case under `flatc --play`, see `--seed`) — see [host integration](host-integration.md) |
|
|
54
|
+
| `keys.<Key>` | `1` while a key is held, `0` otherwise — `<Key>` is the browser `KeyboardEvent.key` value (`keys.ArrowRight`, `keys.a`, `keys.Escape`), plus the alias `keys.Space` for the space bar, **or** the physical key, `KeyboardEvent.code` (`keys.ShiftLeft`, `keys.Digit1`, `keys.Numpad1`, `keys.KeyA`) — the way to tell the two Shift keys apart and to read the digit row. Naming a key here also makes the player **consume** it (no page scroll) — see [host integration](host-integration.md#keyboard) |
|
|
54
55
|
| `self.x` `self.y` `self.scaleX` … | the object's own current pose (in its channel bindings) |
|
|
55
|
-
| `self.hovered` `self.grabbed` `self.pressed` | the object's own interaction state (`0`/`1`) — see [feedback](behavior-and-interactions.md#feedback) |
|
|
56
|
+
| `self.hovered` `self.grabbed` `self.pressed` `self.focused` | the object's own interaction state (`0`/`1`; `focused` = it holds the keyboard focus, see `focusable`) — see [feedback](behavior-and-interactions.md#feedback) |
|
|
56
57
|
| `<Name>.x` `<Name>.y` … | a named object's live channels (e.g. `Target.x`) |
|
|
57
58
|
|
|
58
59
|
## Arrays
|
package/docs/host-integration.md
CHANGED
|
@@ -25,11 +25,26 @@ const player = new FlatPlayer(canvas, doc, {
|
|
|
25
25
|
| `autoplay` | `false` | starts the timeline on mount |
|
|
26
26
|
| `loop` | `true` | loops the timeline |
|
|
27
27
|
| `padding` | `0` | margin around the page, in CSS px |
|
|
28
|
-
| `audio` | `true` | `false` mutes `sound "…"` and audio tracks |
|
|
28
|
+
| `audio` | `true` | `false` mutes `sound "…"` and audio tracks. Sounds are decoded when the document loads, so the first one plays on time |
|
|
29
29
|
| `input` | `true` | `false` = non-interactive preview: it animates but ignores pointer **and keyboard** |
|
|
30
30
|
| `render` | `true` | `false` = headless (logic + `send`s only, no Canvas API needed) |
|
|
31
31
|
| `resolveAsset` | embedded only | maps an asset to a URL. Default: embedded `data:` URIs only — see [Security](#security) |
|
|
32
32
|
| `onEvent` | — | called on every `send` |
|
|
33
|
+
| `focusRing` | `true` | the ring drawn around the object that holds the keyboard focus (`focusable`). `false` = none, or `{ color, width }` |
|
|
34
|
+
| `seed` | none | seed of `random()`: the scene then draws the same numbers on every run. Absent, it draws from `Math.random` |
|
|
35
|
+
| `maxPixelRatio` | none | upper bound on the device pixel ratio the canvas is sized with. The backing store grows with the square of the ratio; on a 3x phone, `2` trades a little sharpness for a much cheaper frame |
|
|
36
|
+
|
|
37
|
+
### When the player paints
|
|
38
|
+
|
|
39
|
+
While it plays, the player repaints a frame **only when the picture can have changed**: a variable an
|
|
40
|
+
expression reads was written, a param or a state moved, a spring is still settling, the pointer or a key
|
|
41
|
+
changed, an image or a font finished loading. A scene at rest costs no paint at all. A scene whose
|
|
42
|
+
expressions read `time`, `clock`, `frame` or `random()`, or whose keyframes play with the playhead, is
|
|
43
|
+
repainted every frame as before.
|
|
44
|
+
|
|
45
|
+
Everything the player exposes paints on its own (`setVar`, `setKey`, `seek`, `load`…). If the host changes
|
|
46
|
+
what is drawn behind the player's back — it mutates the document it handed over, say — it calls
|
|
47
|
+
`player.render()`.
|
|
33
48
|
|
|
34
49
|
## Receiving events (`send` → `onEvent`)
|
|
35
50
|
|
|
@@ -124,6 +139,28 @@ place, and `render()` forces a repaint (useful after a late font settles).
|
|
|
124
139
|
`KeyboardEvent.key` value — `keys.ArrowRight`, `keys.a`, `keys.Escape` — plus one alias: the space bar
|
|
125
140
|
(`key === ' '`) is also exposed as **`keys.Space`**.
|
|
126
141
|
|
|
142
|
+
A physical key answers to its **`KeyboardEvent.code`** as well: `keys.ShiftLeft` and `keys.ShiftRight` are
|
|
143
|
+
two keys (both are `keys.Shift`), the digit row is `keys.Digit1`…`keys.Digit0` (its `key` is `"1"`, which
|
|
144
|
+
an expression cannot spell), the keypad `keys.Numpad1`, a letter wherever the layout puts it `keys.KeyA`.
|
|
145
|
+
|
|
146
|
+
### Keyboard focus
|
|
147
|
+
|
|
148
|
+
A scene whose objects declare `focusable` makes its canvas a **stop in the page's tab order** (the player
|
|
149
|
+
sets `tabindex="0"` on it unless you set one). Reached with Tab, the first object takes the focus (the last
|
|
150
|
+
one when the page came backwards); Tab then walks the objects, Enter and Space click the focused one, and
|
|
151
|
+
past either end the key is left to the page. The player handles Tab only while the canvas has the page's
|
|
152
|
+
focus, so it never interferes with the rest of your page.
|
|
153
|
+
|
|
154
|
+
- `focusRing` option: `false` to draw no ring (the scene uses `self.focused`), or `{ color, width }`.
|
|
155
|
+
- `player.focused` is the name of the focused object (or `null`); `player.focusNext(1 | -1)` moves the
|
|
156
|
+
focus from the host (it returns `false` when there is nothing left that way).
|
|
157
|
+
- The canvas keeps the browser's own focus outline: style it as you would any focusable element.
|
|
158
|
+
|
|
159
|
+
### Pointers
|
|
160
|
+
|
|
161
|
+
Each pointer has its own gesture: two fingers can press, hold and drag two objects at once, and lifting
|
|
162
|
+
one releases only what it was holding. `mouse.x` / `mouse.y` follow the pointer that moved last.
|
|
163
|
+
|
|
127
164
|
The listeners are attached to the **window** (a scene reacts immediately, with no click-to-focus step),
|
|
128
165
|
but the player is a good citizen about it — you should not have to do anything:
|
|
129
166
|
|
|
@@ -24,8 +24,15 @@ ellipse <cx> <cy> <rx> <ry>
|
|
|
24
24
|
rect <x> <y> <w> <h> # · <r> for uniform rounded corners · <rx> <ry> for distinct
|
|
25
25
|
path "M0 0 L10 0 L10 10 Z" # raw SVG path data
|
|
26
26
|
circle 100 100 40 as "Ring" # name a shape (right after the geometry) → addressable, e.g. text `along "Ring"`
|
|
27
|
+
path "M0 0 L8 3 L15 9 …" smooth # free-hand material: rounded wherever the outline turns gently
|
|
27
28
|
```
|
|
28
29
|
|
|
30
|
+
A `path` means what its data says: `L`, `H` and `V` are **straight lines**, next to a curve or on their own
|
|
31
|
+
— a hexagon has six flat sides. **`smooth`**, right after the path data, reads the path as **free-hand
|
|
32
|
+
material** instead: its points are joined by a curve that rounds every gentle turn (under 60°) and keeps
|
|
33
|
+
the sharp ones. It is what the editor's brush exports, and what a curve sampled as many small `L` steps
|
|
34
|
+
wants. `flatc --check` points at a long run of points with gentle turns that does not say `smooth`.
|
|
35
|
+
|
|
29
36
|
### Fill, stroke, opacity
|
|
30
37
|
|
|
31
38
|
```
|
|
@@ -35,6 +42,37 @@ path "…" nofill stroke #888 2 # outline only
|
|
|
35
42
|
rect 0 0 40 40 fill #00aaff opacity 0.5 # 0..1 (8-digit hex alpha also works)
|
|
36
43
|
```
|
|
37
44
|
|
|
45
|
+
### A shape computed while the scene runs (`polyline`)
|
|
46
|
+
|
|
47
|
+
`polyline` is a shape whose points are **two array variables**, read every frame — a trajectory, a curve as
|
|
48
|
+
it is being computed, a polygon the learner deforms:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
var tx = fill(200, 0)
|
|
52
|
+
var ty = fill(200, 0)
|
|
53
|
+
var n = 0
|
|
54
|
+
scene {
|
|
55
|
+
layer "c" {
|
|
56
|
+
polyline tx ty count "n" nofill stroke #cc3333 3 cap round # the first n points, as a line
|
|
57
|
+
polyline px py closed fill #3366cc # all the points, as a filled polygon
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
every frame {
|
|
61
|
+
if n < 200 {
|
|
62
|
+
tx[n] = 20 + n * 2
|
|
63
|
+
ty[n] = 90 - 60 * sin(n / 10)
|
|
64
|
+
n = n + 1
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
- `polyline <xs> <ys>` takes the **names** of the two arrays. `count <n>` or `count "<expr>"` keeps the
|
|
70
|
+
first points only (never past the arrays); `closed` joins the last point to the first.
|
|
71
|
+
- The segments are **straight**. Fill, stroke, `opacity`, `draw` and `nohit` are those of any shape.
|
|
72
|
+
- The arrays are the truth: write them from `every frame` or a handler, and the line follows. A scene that
|
|
73
|
+
stops writing them stops being repainted. `flatc --check` reports a name that is not a declared array.
|
|
74
|
+
- Fewer than two points draw nothing.
|
|
75
|
+
|
|
38
76
|
### Drawing a stroke progressively (`draw`)
|
|
39
77
|
|
|
40
78
|
`draw` sets **how much of an outline is stroked**, as a fraction of its **arc length** — ink that appears
|
package/docs/tooling.md
CHANGED
|
@@ -233,6 +233,11 @@ flatc <file> --play --script gestures.json [--trace]
|
|
|
233
233
|
```
|
|
234
234
|
|
|
235
235
|
- `drag` / `tap` / `scratch` (sweeps a `reveal` zone) / `connect` (pulls a `link` wire) — by name.
|
|
236
|
+
`tap` also takes a point instead of a name — `{ "type": "tap", "x": 120, "y": 80 }` — for a rail or
|
|
237
|
+
an area that has no name.
|
|
238
|
+
- Audio is off in `--play`: a `sound` action is a silent no-op, so a program is replayed as written.
|
|
239
|
+
- `random()` is seeded in `--play` (seed `1`), so a replay says the same thing twice and an `expect` can
|
|
240
|
+
assert on a draw. `--seed N` picks another one.
|
|
236
241
|
- **`turn`** rotates a `turn`/`turnDeg` target by `angle` (degrees for `turnDeg`, radians for `turn`),
|
|
237
242
|
swept in sub-steps so a multi-turn rotation lands. It presses the object where the engine finds it, i.e.
|
|
238
243
|
on **whatever is topmost there** — two clock hands overlapping at noon give the gesture to the one on
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flatkit/compiler",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.36.1",
|
|
4
4
|
"description": "The FlatInk language (parser + AST) and compiler (.flatink → .flatpack). Ships the flatc CLI.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Zwyk Studio",
|
|
@@ -57,9 +57,9 @@
|
|
|
57
57
|
"docs"
|
|
58
58
|
],
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@flatkit/engine": "0.
|
|
61
|
-
"@flatkit/player": "0.
|
|
62
|
-
"@flatkit/types": "0.
|
|
60
|
+
"@flatkit/engine": "0.36.1",
|
|
61
|
+
"@flatkit/player": "0.36.1",
|
|
62
|
+
"@flatkit/types": "0.36.1"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
65
|
"skia-canvas": "^3.0.8"
|
package/prompts/flatink-core.md
CHANGED
|
@@ -252,7 +252,8 @@ State & helpers:
|
|
|
252
252
|
var x = 0 var arr = [0,0,0] var z = fill(8, 0) // runtime state (arrays via fill)
|
|
253
253
|
fn dist(ax,ay,bx,by) = hypot(ax-bx, ay-by) // value fn
|
|
254
254
|
fn reset() { score = 0 go to frame 0 } // procedure fn
|
|
255
|
-
self.hovered self.grabbed self.pressed
|
|
255
|
+
self.hovered self.grabbed self.pressed self.focused // own interaction state (0/1)
|
|
256
|
+
focusable [order <n>] [noring] // in an object block: Tab reaches it, Enter/Space fire `when clicked`, the player rings it
|
|
256
257
|
feedback lift tilt dim shake(<expr>) // one-liner reactions (auto use "feedback")
|
|
257
258
|
```
|
|
258
259
|
|
|
@@ -323,7 +324,7 @@ ramp over `dur` s for a readable timed feedback — capture the instant with **`
|
|
|
323
324
|
13. **`$()` is for compile-time interpolation in scene coords**; runtime expressions use bare
|
|
324
325
|
identifiers and `[]` indexing. Arrays must exist before indexed write (`var hx = fill(n,0)`).
|
|
325
326
|
14. **Drop test = object center** by default; use `when dropped on Zone at pointer` for the pointer, or
|
|
326
|
-
`group "Zone" … hitbox W H { … }` for an explicit rectangle. `when released` fires BEFORE the drop test.
|
|
327
|
+
`group "Zone" … hitbox W H { … }` for an explicit rectangle (also the object's TOUCH area: a stroke-only ring is clicked in its middle only with a `hitbox`). `when released` fires BEFORE the drop test.
|
|
327
328
|
15. **`reveal`/`trace` progress is monotone** (never decreases). `link` works in WORLD coords.
|
|
328
329
|
16. **Stroke width scales with the group** (drawn in scaled space) — don't compensate by hand.
|
|
329
330
|
17. **All rotation is radians; author degrees with the `*Deg` twins.** The `rotation` channel,
|
package/prompts/flatink-lite.md
CHANGED
|
@@ -87,7 +87,8 @@ link endX,endY,target to <Group> // target = hit index 1..n (0=none), WORLD
|
|
|
87
87
|
// link draws NO thread. A bar drawn from its own origin, then:
|
|
88
88
|
// rotation = angle(srcX, srcY, endX, endY) scaleX = dist(srcX, srcY, endX, endY) / <drawn length>
|
|
89
89
|
```
|
|
90
|
-
|
|
90
|
+
Keyboard: `focusable [order n]` in an `object` block → Tab reaches it, Enter/Space fire its `when clicked`.
|
|
91
|
+
Self-state & feedback: `self.hovered self.grabbed self.pressed self.focused` (0/1) ·
|
|
91
92
|
`feedback lift tilt dim shake(<expr>)`.
|
|
92
93
|
State/funcs: `var a = 0` · `var arr = fill(8,0)` (also as an ASSIGNMENT: `arr = fill(n, 0)` blanks a grid) · `fn dist(ax,ay,bx,by) = hypot(ax-bx,ay-by)` ·
|
|
93
94
|
`fn reset() { score = 0 }`.
|
|
@@ -69,7 +69,9 @@ symbol "Boat" {
|
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
```
|
|
72
|
-
- Types: `color`, `number` (`number wave = 1 range 0 2 "…"`), `bool
|
|
72
|
+
- Types: `color`, `number` (`number wave = 1 range 0 2 "…"`), `bool`, `text` (`text label = "OK" "…"`).
|
|
73
|
+
- A `text` param is drawn with `text label at …` (the bare name instead of a quoted string): a button
|
|
74
|
+
carries its own label, set per instance with `{ label = "Play" }`.
|
|
73
75
|
- `color` params go anywhere a `#color` literal goes (`fill hull`, `stroke hull 3`).
|
|
74
76
|
- Preview a restyle: `flatc --preview Boat.flat --render --set hull=#1a5f3a -o boat.png`.
|
|
75
77
|
|