@nakednous/tree 0.0.10 → 0.0.11

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/README.md CHANGED
@@ -33,6 +33,15 @@ import * as tree from '@nakednous/tree'
33
33
 
34
34
  The dependency direction is strict: `@nakednous/tree` never imports from the bridge or the DOM layer. This is what lets the same `PoseTrack` that drives a camera path also animate any object — headless, server-side, or in a future renderer.
35
35
 
36
+ Source is organised into four focused modules:
37
+
38
+ ```
39
+ form.js — you have specs, you want a matrix
40
+ query.js — you have a matrix, you want information
41
+ quat.js — quaternion algebra and mat4/mat3 conversions
42
+ track.js — spline math and keyframe animation state machines
43
+ ```
44
+
36
45
  ---
37
46
 
38
47
  ## What it does
@@ -68,7 +77,7 @@ track.rotInterp = 'nlerp' // normalised lerp; cheaper, slightly non-constant
68
77
  track.rotInterp = 'step' // snap to k0 quaternion
69
78
  ```
70
79
 
71
- Playback features: signed `rate` (negative reverses), `loop`, `pingPong`, `seek(t)` scrubbing, and lifecycle hooks (`onPlay`, `onEnd`, `onStop`). `_onActivate` / `_onDeactivate` are lib-space hooks for the host layer's draw-loop registry — not for user code.
80
+ Playback features: signed `rate` (negative reverses), `loop`, `bounce`, `seek(t)` scrubbing, and lifecycle hooks (`onPlay`, `onEnd`, `onStop`). `_onActivate` / `_onDeactivate` are lib-space hooks for the host layer's draw-loop registry — not for user code.
72
81
 
73
82
  `add()` accepts flexible specs. Top-level forms:
74
83
 
@@ -79,7 +88,7 @@ track.add({ mMatrix: mat4 }) // decompose a column-major m
79
88
  track.add([ spec, spec, ... ]) // bulk
80
89
  ```
81
90
 
82
- `tanIn` is the incoming position tangent at this keyframe; `tanOut` is the outgoing tangent. When only one is given, the other mirrors it. When neither is given, centripetal Catmull-Rom tangents are auto-computed from neighboring keyframes — identical to prior default behavior.
91
+ `tanIn` is the incoming position tangent at this keyframe; `tanOut` is the outgoing tangent. When only one is given, the other mirrors it. When neither is given, centripetal Catmull-Rom tangents are auto-computed from neighboring keyframes.
83
92
 
84
93
  ```js
85
94
  track.add({ pos:[0,0,0] }) // auto tangents
@@ -138,7 +147,7 @@ track.centerInterp = 'hermite' // smoother when center is also moving freely
138
147
  track.centerInterp = 'step'
139
148
  ```
140
149
 
141
- `add()` accepts:
150
+ `add()` accepts explicit lookat specs or a bulk array:
142
151
 
143
152
  ```js
144
153
  track.add({ eye, center?, up?, fov?, halfHeight?,
@@ -148,12 +157,10 @@ track.add({ eye, center?, up?, fov?, halfHeight?,
148
157
  // both nullable; omit to leave projection unchanged
149
158
  // eyeTanIn/Out — Hermite tangents for eye path
150
159
  // centerTanIn/Out — Hermite tangents for center path
151
- track.add({ vMatrix: mat4 }) // view matrix (world→eye); eye reconstructed
152
- track.add({ eMatrix: mat4 }) // eye matrix (eye→world); eye read from col3
153
160
  track.add([ spec, spec, ... ]) // bulk
154
161
  ```
155
162
 
156
- Note: both matrix forms default `up` to `[0,1,0]`. The matrix col1 (up_ortho) is intentionally not used — it differs from the hint for upright cameras and would shift orbitControl's orbit reference. Use `capturePose()` (p5.tree bridge) when the real up hint is needed.
163
+ For matrix-based capture use `PoseTrack.add({ mMatrix: eMatrix })` for full-fidelity TRS including roll, or `cam.capturePose()` (p5.tree bridge) for lookat-style capture.
157
164
 
158
165
  `fov` and `halfHeight` are lerped between keyframes only when both adjacent keyframes carry a non-null value for that field. Mixed or null entries pass `null` through — the bridge leaves the projection unchanged.
159
166
 
@@ -164,7 +171,7 @@ Note: both matrix forms default `up` to `[0,1,0]`. The matrix col1 (up_ortho) is
164
171
  Both `PoseTrack` and `CameraTrack` extend `Track`, which holds all transport machinery:
165
172
 
166
173
  ```js
167
- track.play({ duration, loop, pingPong, rate, onPlay, onEnd, onStop })
174
+ track.play({ duration, loop, bounce, rate, onPlay, onEnd, onStop })
168
175
  track.stop([rewind]) // rewind=true seeks to origin on stop
169
176
  track.reset() // clear all keyframes and stop
170
177
  track.seek(t) // normalised position [0, 1]
@@ -177,12 +184,23 @@ track.remove(i) // remove keyframe at index
177
184
 
178
185
  track.playing // boolean
179
186
  track.loop // boolean
180
- track.pingPong // boolean
187
+ track.bounce // boolean
181
188
  track.rate // get/set — never starts/stops playback
182
189
  track.duration // frames per segment
183
190
  track.keyframes // raw array
184
191
  ```
185
192
 
193
+ **Loop modes** — `loop` and `bounce` are fully independent flags:
194
+
195
+ | `loop` | `bounce` | behaviour |
196
+ |--------|----------|-----------|
197
+ | false | false | play once — stop at end (fires `onEnd`) |
198
+ | true | false | repeat — wrap back to start |
199
+ | true | true | bounce forever — reverse direction at each boundary |
200
+ | false | true | bounce once — flip at far boundary, stop at origin |
201
+
202
+ The internal `_dir` field (±1) tracks bounce travel direction — `rate` is never mutated at boundaries.
203
+
186
204
  Hook firing order:
187
205
  ```
188
206
  play() → onPlay → _onActivate
@@ -248,7 +266,7 @@ Three-state result: `VISIBLE` (fully inside), `SEMIVISIBLE` (intersecting), `INV
248
266
 
249
267
  Exported individually for use in hot paths.
250
268
 
251
- **Quaternions** — `[x,y,z,w]` w-last:
269
+ **Quaternions** — `[x,y,z,w]` w-last (`quat.js`):
252
270
 
253
271
  ```
254
272
  qSet qCopy qDot qNormalize qNegate qMul
@@ -259,15 +277,34 @@ quatToAxisAngle
259
277
 
260
278
  **Spline / vector:** `hermiteVec3`, `lerpVec3`
261
279
 
262
- **Mat4:**
280
+ **Mat4 arithmetic** (`query.js`):
263
281
  ```
264
- mat4Mul mat4Invert mat4Transpose mat4MulPoint
282
+ mat4Mul mat4Invert mat4Transpose mat4MulPoint mat4MulDir
265
283
  mat3NormalFromMat4 mat4Location mat3Direction
284
+ mat4PV mat4MV
266
285
  ```
267
286
 
268
- **TRS ↔ mat4:** `transformToMat4`, `mat4ToTransform`
287
+ **TRS ↔ mat4 (track.js):** `transformToMat4`, `mat4ToTransform`
288
+
289
+ **Matrix construction from specs** (`form.js`):
290
+ ```
291
+ mat4FromBasis — rigid frame from orthonormal basis + translation
292
+ mat4LookAt — view matrix (world→eye) from lookat params
293
+ mat4EyeMatrix — eye matrix (eye→world) from lookat params
294
+ mat4FromTRS — column-major mat4 from flat TRS scalars
295
+ mat4FromTranslation — translation-only mat4
296
+ mat4FromScale — scale-only mat4
297
+ mat4Perspective — perspective projection
298
+ mat4Ortho — orthographic projection
299
+ mat4Frustum — off-centre perspective projection
300
+ mat4Bias — NDC→texture/UV remap [0,1] for shadow mapping
301
+ mat4Reflect — reflection across a plane
302
+ mat4ToTranslation — extract translation (col 3)
303
+ mat4ToScale — extract scale (column lengths)
304
+ mat4ToRotation — extract rotation as unit quaternion
305
+ ```
269
306
 
270
- **Projection queries** (read from a projection mat4 — no renderer needed):
307
+ **Projection queries** read scalars from an existing projection mat4 (`query.js`):
271
308
  ```
272
309
  projIsOrtho projNear projFar projFov projHfov
273
310
  projLeft projRight projTop projBottom
@@ -275,7 +312,7 @@ projLeft projRight projTop projBottom
275
312
 
276
313
  **Pixel ratio:** `pixelRatio(proj, vpH, eyeZ, ndcZMin)` — world-units-per-pixel at a given depth, handles both perspective and orthographic.
277
314
 
278
- **Pick matrix:** `applyPickMatrix(proj, px, py, W, H)` — mutates a projection mat4 in-place so that pixel `(px, py)` maps to the full NDC square. Used by the p5.tree GPU color-ID picking implementation. Convention-independent (perspective and orthographic).
315
+ **Pick matrix:** `mat4Pick(proj, px, py, W, H)` — mutates a projection mat4 in-place so that pixel `(px, py)` maps to the full NDC square. Used by the p5.tree GPU color-ID picking implementation. Convention-independent (perspective and orthographic).
279
316
 
280
317
  ---
281
318