@vworlds/vecs 1.0.30 → 1.0.32

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/docs/systems.md CHANGED
@@ -18,7 +18,7 @@ world
18
18
  .system("Render")
19
19
  .with(Sprite, Position)
20
20
  .enter([Sprite, Position], (e, [sprite, pos]) => sprite.show(pos))
21
- .update(Position, [Sprite], (e, pos, [sprite]) => sprite.moveTo(pos.x, pos.y))
21
+ .update({ watch: Position, inject: [Sprite] }, (e, pos, [sprite]) => sprite.moveTo(pos.x, pos.y))
22
22
  .exit([Sprite], (e, [sprite]) => sprite.hide());
23
23
  ```
24
24
 
@@ -77,16 +77,17 @@ taxonomy, ordering rules, and custom phases are covered in
77
77
  Mutation events are routed into the system's inbox as the world applies commands; the inbox is
78
78
  replayed in arrival order at the top of the system's next run, inside a deferred scope.
79
79
 
80
- ### `.enter(callback)` / `.enter(inject, callback)`
80
+ ### `.enter(callback)` / `.enter(inject, callback)` / `.enter(options, callback)`
81
81
 
82
82
  Fires once when an entity starts matching the system:
83
83
 
84
84
  ```ts
85
85
  .enter((e) => { ... })
86
86
  .enter([Position, Sprite], (e, [pos, sprite]) => sprite.setPosition(pos.x, pos.y))
87
+ .enter({ inject: [Position, Sprite] }, (e, [pos, sprite]) => sprite.setPosition(pos.x, pos.y))
87
88
  ```
88
89
 
89
- ### `.update(ComponentClass, callback)` / `.update(ComponentClass, inject, callback)`
90
+ ### `.update(ComponentClass, callback)` / `.update(options, callback)`
90
91
 
91
92
  Fires when the watched component is set or marked modified on a tracked entity — and **on entry**
92
93
  for each watched component the entity already has. `update(ComponentClass, ...)` also adds
@@ -96,7 +97,9 @@ reference:
96
97
 
97
98
  ```ts
98
99
  .update(Position, (entity, pos) => renderer.setPosition(entity.eid, pos.x, pos.y))
99
- .update(Position, [Sprite], (entity, pos, [sprite]) => sprite.setPosition(pos.x, pos.y))
100
+ .update({ watch: Position, inject: [Sprite] }, (entity, pos, [sprite]) =>
101
+ sprite.setPosition(pos.x, pos.y)
102
+ )
100
103
  ```
101
104
 
102
105
  Because `update` fires on entry, a separate `enter` that applies the same value is redundant —
@@ -108,7 +111,7 @@ Use `.update(C, ...)` by itself when `C` is the membership shape and watched val
108
111
  A query or system can register only one `update(C, ...)` callback for each component. A duplicate
109
112
  registration throws instead of replacing the existing callback.
110
113
 
111
- ### `.exit(callback)` / `.exit(inject, callback)`
114
+ ### `.exit(callback)` / `.exit(inject, callback)` / `.exit(options, callback)`
112
115
 
113
116
  Fires when an entity stops matching (component removed, or entity destroyed). Directly injected
114
117
  components are read from a **snapshot captured at exit time**, so they are still resolvable even
@@ -117,11 +120,12 @@ be `undefined`:
117
120
 
118
121
  ```ts
119
122
  .exit([Sprite], (e, [sprite]) => sprite.destroy());
123
+ .exit({ inject: [Sprite] }, (e, [sprite]) => sprite.destroy());
120
124
  ```
121
125
 
122
126
  ## Per-tick callbacks: `each` and `run`
123
127
 
124
- ### `.each(components, callback)`
128
+ ### `.each(components, callback)` / `.each(options, callback)`
125
129
 
126
130
  Fires every tick the system runs, once per tracked entity, regardless of change. Use it only for
127
131
  genuinely per-frame sweeps — when reacting to change suffices, prefer `update` (see
@@ -132,6 +136,10 @@ genuinely per-frame sweeps — when reacting to change suffices, prefer `update`
132
136
  .each([Position, Velocity], (e, [pos, vel]) => {
133
137
  pos.x += vel.vx;
134
138
  });
139
+
140
+ .each({ inject: [Position, Velocity] }, (e, [pos, vel]) => {
141
+ pos.x += vel.vx;
142
+ });
135
143
  ```
136
144
 
137
145
  `each` implies `.track()`. Only one `each` per system — a second call throws. The resolved tuple
@@ -157,11 +165,12 @@ then `each`.
157
165
 
158
166
  ## Component injection
159
167
 
160
- `enter`, `exit`, `update`, `each`, `orderBy`, and `forEach` accept an injection list of component
161
- classes, resolved per entity and passed as a typed tuple:
168
+ `enter`, `exit`, `update`, `each`, `orderBy`, and `forEach` accept either a short injection list or
169
+ an options object with `inject`, resolved per entity and passed as a typed tuple:
162
170
 
163
171
  ```ts
164
172
  .each([Position, Sprite], (e, [pos, sprite]) => { ... })
173
+ .each({ inject: [Position, Sprite] }, (e, [pos, sprite]) => { ... })
165
174
  ```
166
175
 
167
176
  Nullability follows membership: components guaranteed by `with` (or `hint`) are non-nullable;
@@ -199,17 +208,20 @@ in `each` and `forEach`, at most once per tuple, and entities with zero children
199
208
 
200
209
  ### The `Iter` cursor
201
210
 
202
- Pass `Iter` (from `@vworlds/vecs`) as the first argument to `each`, `forEach`, `enter`, `exit`,
203
- `update`, or `orderBy` to receive a reusable cursor instead of the bare entity:
211
+ Pass `{ cursor: Iter, ... }` to `each`, `forEach`, `enter`, `exit`, `update`, or `orderBy` to receive
212
+ a reusable cursor instead of the bare entity:
204
213
 
205
214
  ```ts
206
215
  import { Iter } from "@vworlds/vecs";
207
216
 
208
- system.each(Iter, [Body, { target: [ChildOf, [Position]] }], (it, [body, pos]) => {
209
- it.entity; // the visited entity
210
- it.src[0]; // entity body was read from (the visited entity)
211
- it.src[1]; // entity pos was read from (the ChildOf target), or undefined
212
- });
217
+ system.each(
218
+ { cursor: Iter, inject: [Body, { target: [ChildOf, [Position]] }] },
219
+ (it, [body, pos]) => {
220
+ it.entity; // the visited entity
221
+ it.src[0]; // entity body was read from (the visited entity)
222
+ it.src[1]; // entity pos was read from (the ChildOf target), or undefined
223
+ }
224
+ );
213
225
  ```
214
226
 
215
227
  `it.src` holds the source entity per tuple slot: the visited entity for direct components, the
@@ -217,11 +229,11 @@ relationship target for `target` slots, the specific child for `down` slots. Whe
217
229
  requested, the non-cursor path runs with zero per-entity overhead — dispatch happens once at setup
218
230
  time. `each`/`forEach`/`update`/`orderBy` reuse cursor and tuple instances across the pass, so
219
231
  snapshot what you need before triggering further mutations from inside a callback. Passing
220
- `Entity` as the first argument is also accepted and means the default entity-first signature.
232
+ `{ cursor: Entity, ... }` is also accepted and means the default entity-first signature.
221
233
 
222
234
  ## Ordering and tracking
223
235
 
224
- ### `.orderBy(components, compare)`
236
+ ### `.orderBy(components, compare)` / `.orderBy(options, compare)`
225
237
 
226
238
  Keep matched entities in a custom order. Iteration, `forEach`, and `each` then walk entities in
227
239
  sorted order. Implies tracking:
@@ -232,6 +244,12 @@ world
232
244
  .with(Position, Sprite)
233
245
  .orderBy([Position], (_ea, [a], _eb, [b]) => a.y - b.y)
234
246
  .each([Position, Sprite], (e, [pos, sprite]) => sprite.draw(pos.x, pos.y));
247
+
248
+ world
249
+ .system("Render")
250
+ .with(Position, Sprite)
251
+ .orderBy({ inject: [Position] }, (_ea, [a], _eb, [b]) => a.y - b.y)
252
+ .each({ inject: [Position, Sprite] }, (e, [pos, sprite]) => sprite.draw(pos.x, pos.y));
235
253
  ```
236
254
 
237
255
  Ties break by entity id, so the order is deterministic.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vworlds/vecs",
3
- "version": "1.0.30",
3
+ "version": "1.0.32",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",