@nakednous/tree 0.0.20 → 0.0.22
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 +70 -12
- package/dist/index.js +378 -298
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -116,7 +116,7 @@ rot: { mat4Eye: mat4 } // rotation block of an eye matrix
|
|
|
116
116
|
|
|
117
117
|
### CameraTrack — lookat keyframe animation
|
|
118
118
|
|
|
119
|
-
A renderer-agnostic state machine for `{ eye, center, up, fov?, halfHeight
|
|
119
|
+
A renderer-agnostic state machine for `{ eye, center, up, fov?, halfHeight?, near, far }` lookat keyframes. Each field is independently interpolated — eye and center along their own paths, up nlerped on the unit sphere, `near` / `far` lerped linearly.
|
|
120
120
|
|
|
121
121
|
```js
|
|
122
122
|
import { CameraTrack } from '@nakednous/tree'
|
|
@@ -127,7 +127,8 @@ track.add({ eye:[300,-150,0], center:[0,0,0] })
|
|
|
127
127
|
track.play({ loop: true, duration: 90 })
|
|
128
128
|
|
|
129
129
|
// per-frame — zero allocation
|
|
130
|
-
const out = { eye:[0,0,0], center:[0,0,0], up:[0,1,0],
|
|
130
|
+
const out = { eye:[0,0,0], center:[0,0,0], up:[0,1,0],
|
|
131
|
+
fov:null, halfHeight:null, near:0.1, far:1000 }
|
|
131
132
|
track.tick()
|
|
132
133
|
track.eval(out)
|
|
133
134
|
// apply: cam.camera(out.eye[0],out.eye[1],out.eye[2],
|
|
@@ -150,11 +151,12 @@ track.centerInterp = 'step'
|
|
|
150
151
|
`add()` accepts explicit lookat specs or a bulk array:
|
|
151
152
|
|
|
152
153
|
```js
|
|
153
|
-
track.add({ eye, center?, up?, fov?, halfHeight?,
|
|
154
|
+
track.add({ eye, center?, up?, fov?, halfHeight?, near?, far?,
|
|
154
155
|
eyeTanIn?, eyeTanOut?, centerTanIn?, centerTanOut? })
|
|
155
156
|
// fov — vertical fov (radians) for perspective
|
|
156
157
|
// halfHeight — world-unit half-height for ortho
|
|
157
|
-
//
|
|
158
|
+
// fov / halfHeight are nullable — omit to leave projection unchanged
|
|
159
|
+
// near / far — clip distances; default 0.1 / 1000
|
|
158
160
|
// eyeTanIn/Out — Hermite tangents for eye path
|
|
159
161
|
// centerTanIn/Out — Hermite tangents for center path
|
|
160
162
|
track.add([ spec, spec, ... ]) // bulk
|
|
@@ -162,7 +164,9 @@ track.add([ spec, spec, ... ]) // bulk
|
|
|
162
164
|
|
|
163
165
|
For matrix-based capture use `track.add({ mat4Model: mat4Eye })` for full-fidelity TRS including roll, or `cam.capturePose()` (p5.tree bridge) for lookat-style capture.
|
|
164
166
|
|
|
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.
|
|
167
|
+
`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. They are nullable because exactly one is meaningful per keyframe (perspective xor orthographic).
|
|
168
|
+
|
|
169
|
+
`near` and `far` carry real defaults on every keyframe (`0.1` / `1000`, matching the three.js / Bevy conventions) and are therefore lerped linearly between every adjacent pair — no null-passthrough. `cam.capturePose()` extracts them from the camera's own projection matrix (not the renderer's live state), so a round-trip through `add(cam.capturePose())` is exact regardless of which camera is currently active on the renderer.
|
|
166
170
|
|
|
167
171
|
---
|
|
168
172
|
|
|
@@ -170,23 +174,77 @@ For matrix-based capture use `track.add({ mat4Model: mat4Eye })` for full-fideli
|
|
|
170
174
|
|
|
171
175
|
The interpolated path of a track can be sampled without advancing the transport cursor or firing hooks. All samplers are zero-alloc — the caller owns the output buffers — and honour the track's interpolation mode (`hermite` / `linear` / `step`) and the same stored-tangent → auto-CR fallback chain used by `eval()`.
|
|
172
176
|
|
|
177
|
+
Two shapes of method, each playing a different role:
|
|
178
|
+
|
|
179
|
+
* **Continuous samplers** — evaluate a path-evolving quantity at any point along the path. Accept either a cursor form (reads `track.seg` / `track.f`) or an explicit `(seg, t)` form, with `seg ∈ [0, segments−1]` and `t ∈ [0, 1]` local to that segment.
|
|
180
|
+
* **Keyframe-indexed queries** — give a property of a specific keyframe. Tangents at a junction, or the per-keyframe projection matrix.
|
|
181
|
+
|
|
173
182
|
**`PoseTrack`:**
|
|
174
183
|
|
|
175
184
|
```js
|
|
176
|
-
track.samplePos(out
|
|
177
|
-
track.
|
|
185
|
+
track.samplePos(out) // cursor form
|
|
186
|
+
track.samplePos(out, seg, t) // explicit
|
|
187
|
+
|
|
188
|
+
track.mat4Model(out) // cursor form — TRS as model mat4
|
|
189
|
+
track.mat4Model(out, seg, t) // explicit
|
|
190
|
+
|
|
191
|
+
track.tangents(outIn, outOut, i) // effective in/out pos-tangents at keyframe i
|
|
178
192
|
```
|
|
179
193
|
|
|
180
194
|
**`CameraTrack`:**
|
|
181
195
|
|
|
182
196
|
```js
|
|
183
|
-
track.sampleEye(out, seg, t)
|
|
184
|
-
track.sampleCenter(out, seg, t)
|
|
185
|
-
|
|
186
|
-
track.
|
|
197
|
+
track.sampleEye(out) track.sampleEye(out, seg, t)
|
|
198
|
+
track.sampleCenter(out) track.sampleCenter(out, seg, t)
|
|
199
|
+
|
|
200
|
+
track.mat4Eye(out) // cursor form — lookat eye matrix
|
|
201
|
+
track.mat4Eye(out, seg, t) // explicit
|
|
202
|
+
|
|
203
|
+
track.eyeTangents(outIn, outOut, i)
|
|
204
|
+
track.centerTangents(outIn, outOut, i)
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Tangent samplers mirror the missing side at boundary keyframes so the first and last keyframes produce visible tangent vectors.
|
|
208
|
+
|
|
209
|
+
**Projection matrices are not a track method.** Each `CameraTrack` keyframe stores `fov` (perspective) or `halfHeight` (orthographic) as a raw scalar on `track.keyframes[i]` — callers wanting a projection build one from those scalars using `mat4Persp` / `mat4Ortho` directly:
|
|
210
|
+
|
|
211
|
+
```js
|
|
212
|
+
const kf = track.keyframes[i]
|
|
213
|
+
if (kf.fov != null) {
|
|
214
|
+
const hh = near * Math.tan(kf.fov * 0.5), hw = hh * aspect
|
|
215
|
+
mat4Persp(out, -hw, hw, -hh, hh, near, far, ndcZMin)
|
|
216
|
+
} else if (kf.halfHeight != null) {
|
|
217
|
+
const hh = kf.halfHeight, hw = hh * aspect
|
|
218
|
+
mat4Ortho(out, -hw, hw, -hh, hh, near, far, ndcZMin)
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Animated `fov` or `halfHeight` in sketches flows through the bridge's camera-binding: `p5.tree` reads `eval().fov` / `eval().halfHeight` each frame and calls `cam.perspective()` / `cam.ortho()` accordingly — none of this touches matrix construction.
|
|
223
|
+
|
|
224
|
+
Callers who want an interpolated projection matrix at mid-segment `(seg, t)` lerp the raw scalars from adjacent keyframes before building:
|
|
225
|
+
|
|
226
|
+
```js
|
|
227
|
+
import { mat4Persp, mat4Ortho } from '@nakednous/tree'
|
|
228
|
+
|
|
229
|
+
function mat4ProjAt(out, track, seg, t, near, far, aspect, ndcZMin, ndcYSign = 1) {
|
|
230
|
+
const k0 = track.keyframes[seg]
|
|
231
|
+
const k1 = track.keyframes[seg + 1] ?? k0
|
|
232
|
+
|
|
233
|
+
if (k0.fov != null && k1.fov != null) {
|
|
234
|
+
const fov = k0.fov + t * (k1.fov - k0.fov)
|
|
235
|
+
const hh = near * Math.tan(fov * 0.5), hw = hh * aspect
|
|
236
|
+
return mat4Persp(out, -hw, hw, -hh, hh, near, far, ndcZMin, ndcYSign)
|
|
237
|
+
}
|
|
238
|
+
if (k0.halfHeight != null && k1.halfHeight != null) {
|
|
239
|
+
const hh = k0.halfHeight + t * (k1.halfHeight - k0.halfHeight)
|
|
240
|
+
const hw = hh * aspect
|
|
241
|
+
return mat4Ortho(out, -hw, hw, -hh, hh, near, far, ndcZMin, ndcYSign)
|
|
242
|
+
}
|
|
243
|
+
return null
|
|
244
|
+
}
|
|
187
245
|
```
|
|
188
246
|
|
|
189
|
-
|
|
247
|
+
Intended uses of the samplers: custom rendering of the path (polyline overlays, arclength-based placement), pedagogical visualisations of Hermite / Catmull-Rom, and gizmos — `p5.tree`'s `trackPath` is built on top of these.
|
|
190
248
|
|
|
191
249
|
---
|
|
192
250
|
|