reze-engine 0.9.4 → 0.10.0

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/dist/model.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Mat4, Quat, Vec3 } from "./math";
2
2
  import { Rigidbody, Joint } from "./physics";
3
- import { AnimationState } from "./animation";
3
+ import { AnimationClip, AnimationPlayOptions, AnimationProgress } from "./animation";
4
4
  export interface Texture {
5
5
  path: string;
6
6
  name: string;
@@ -145,26 +145,23 @@ export declare class Model {
145
145
  setMorphWeight(name: string, weight: number, durationMs?: number): void;
146
146
  private applyMorphs;
147
147
  private buildClipFromVmdKeyFrames;
148
- loadAnimation(animationName: string, vmdUrl: string): Promise<void>;
148
+ loadAnimation(animationName: string, source: string): Promise<void>;
149
+ loadAnimation(animationName: string, source: AnimationClip): void;
149
150
  resetAllBones(): void;
150
151
  resetAllMorphs(): void;
151
- getAnimationState(): AnimationState;
152
+ getAnimationClip(name: string): AnimationClip | null;
152
153
  play(): void;
153
154
  play(name: string): boolean;
155
+ play(name: string, options?: AnimationPlayOptions): boolean;
154
156
  show(name: string): void;
155
157
  playAnimation(): void;
156
158
  pause(): void;
157
159
  pauseAnimation(): void;
158
160
  stop(): void;
159
161
  stopAnimation(): void;
160
- seek(time: number): void;
161
- seekAnimation(time: number): void;
162
- getAnimationProgress(): {
163
- current: number;
164
- duration: number;
165
- percentage: number;
166
- animationName: string | null;
167
- };
162
+ seek(seconds: number): void;
163
+ seekAnimation(seconds: number): void;
164
+ getAnimationProgress(): AnimationProgress;
168
165
  private static upperBound;
169
166
  private findKeyframeIndex;
170
167
  private applyPoseFromClip;
@@ -1 +1 @@
1
- {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"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"}
package/dist/model.js CHANGED
@@ -3,7 +3,6 @@ import { Engine } from "./engine";
3
3
  import { IKSolverSystem } from "./ik-solver";
4
4
  import { VMDLoader } from "./vmd-loader";
5
5
  import { AnimationState, interpolateControlPoints, rawInterpolationToBoneInterpolation, } from "./animation";
6
- const VMD_FPS = 30;
7
6
  const VERTEX_STRIDE = 8;
8
7
  export class Model {
9
8
  get name() {
@@ -255,7 +254,7 @@ export class Model {
255
254
  getMorphWeights() {
256
255
  return this.runtimeMorph.weights;
257
256
  }
258
- // ------- Bone helpers (public API) -------
257
+ // ------- Bone helpers (API) -------
259
258
  rotateBones(boneRotations, durationMs) {
260
259
  const state = this.tweenState;
261
260
  // Clone and normalize to avoid mutating input
@@ -548,7 +547,6 @@ export class Model {
548
547
  rotation: kf.rotation,
549
548
  translation: kf.translation,
550
549
  interpolation: kf.interpolation,
551
- time: kf.frame / VMD_FPS,
552
550
  })));
553
551
  }
554
552
  const morphTracksByMorph = {};
@@ -567,24 +565,28 @@ export class Model {
567
565
  morphName: name,
568
566
  frame: kf.frame,
569
567
  weight: kf.weight,
570
- time: kf.frame / VMD_FPS,
571
568
  })));
572
569
  }
573
- let maxTime = 0;
570
+ let maxFrame = 0;
574
571
  for (const frames of boneTracks.values()) {
575
572
  if (frames.length > 0)
576
- maxTime = Math.max(maxTime, frames[frames.length - 1].time);
573
+ maxFrame = Math.max(maxFrame, frames[frames.length - 1].frame);
577
574
  }
578
575
  for (const frames of morphTracks.values()) {
579
576
  if (frames.length > 0)
580
- maxTime = Math.max(maxTime, frames[frames.length - 1].time);
577
+ maxFrame = Math.max(maxFrame, frames[frames.length - 1].frame);
581
578
  }
582
- return { boneTracks, morphTracks, duration: maxTime };
579
+ return { boneTracks, morphTracks, frameCount: maxFrame };
583
580
  }
584
- async loadAnimation(animationName, vmdUrl) {
585
- const vmdKeyFrames = await VMDLoader.load(vmdUrl);
586
- const clip = this.buildClipFromVmdKeyFrames(vmdKeyFrames);
587
- this.animationState.loadAnimation(animationName, clip);
581
+ loadAnimation(animationName, source) {
582
+ if (typeof source !== "string") {
583
+ this.animationState.loadAnimation(animationName, source);
584
+ return;
585
+ }
586
+ return VMDLoader.load(source).then((vmdKeyFrames) => {
587
+ const clip = this.buildClipFromVmdKeyFrames(vmdKeyFrames);
588
+ this.animationState.loadAnimation(animationName, clip);
589
+ });
588
590
  }
589
591
  resetAllBones() {
590
592
  for (let boneIdx = 0; boneIdx < this.skeleton.bones.length; boneIdx++) {
@@ -603,17 +605,21 @@ export class Model {
603
605
  this.morphsDirty = true;
604
606
  this.applyMorphs();
605
607
  }
606
- getAnimationState() {
607
- return this.animationState;
608
+ getAnimationClip(name) {
609
+ return this.animationState.getAnimationClip(name);
608
610
  }
609
- play(name) {
611
+ play(name, options) {
610
612
  if (name === undefined) {
611
613
  this.animationState.play();
612
614
  return;
613
615
  }
614
- return this.animationState.play(name);
616
+ this.resetAllBones();
617
+ this.resetAllMorphs();
618
+ return this.animationState.play(name, options);
615
619
  }
616
620
  show(name) {
621
+ this.resetAllBones();
622
+ this.resetAllMorphs();
617
623
  this.animationState.show(name);
618
624
  }
619
625
  // @deprecated Use model.play()
@@ -634,42 +640,51 @@ export class Model {
634
640
  stopAnimation() {
635
641
  this.animationState.stop();
636
642
  }
637
- seek(time) {
638
- this.animationState.seek(time);
643
+ // Seek by absolute timeline seconds, not frame index.
644
+ seek(seconds) {
645
+ this.animationState.seek(seconds);
639
646
  }
640
647
  // @deprecated Use model.seek()
641
- seekAnimation(time) {
642
- this.animationState.seek(time);
648
+ seekAnimation(seconds) {
649
+ this.animationState.seek(seconds);
643
650
  }
644
651
  getAnimationProgress() {
645
652
  const p = this.animationState.getProgress();
646
- return { current: p.current, duration: p.duration, percentage: p.percentage, animationName: p.animationName };
653
+ return {
654
+ current: p.current,
655
+ duration: p.duration,
656
+ percentage: p.percentage,
657
+ animationName: p.animationName,
658
+ looping: p.looping,
659
+ playing: p.playing,
660
+ paused: p.paused,
661
+ };
647
662
  }
648
- static upperBound(time, keyFrames, startIdx = 0) {
663
+ static upperBound(frame, keyFrames, startIdx = 0) {
649
664
  let left = startIdx, right = keyFrames.length;
650
665
  while (left < right) {
651
666
  const mid = Math.floor((left + right) / 2);
652
- if (keyFrames[mid].time <= time)
667
+ if (keyFrames[mid].frame <= frame)
653
668
  left = mid + 1;
654
669
  else
655
670
  right = mid;
656
671
  }
657
672
  return left;
658
673
  }
659
- findKeyframeIndex(time, keyFrames, cachedIdx) {
674
+ findKeyframeIndex(frame, keyFrames, cachedIdx) {
660
675
  if (keyFrames.length === 0)
661
676
  return -1;
662
677
  if (cachedIdx >= 0 && cachedIdx < keyFrames.length) {
663
- const frameTime = keyFrames[cachedIdx].time;
664
- const nextFrameTime = cachedIdx + 1 < keyFrames.length ? keyFrames[cachedIdx + 1].time : Infinity;
665
- if (time >= frameTime && time < nextFrameTime) {
678
+ const currentFrame = keyFrames[cachedIdx].frame;
679
+ const nextFrame = cachedIdx + 1 < keyFrames.length ? keyFrames[cachedIdx + 1].frame : Infinity;
680
+ if (frame >= currentFrame && frame < nextFrame) {
666
681
  return cachedIdx;
667
682
  }
668
683
  }
669
- const idx = Model.upperBound(time, keyFrames, 0) - 1;
684
+ const idx = Model.upperBound(frame, keyFrames, 0) - 1;
670
685
  return idx;
671
686
  }
672
- applyPoseFromClip(clip, time) {
687
+ applyPoseFromClip(clip, frame) {
673
688
  if (!clip)
674
689
  return;
675
690
  if (clip !== this.lastAppliedClip) {
@@ -681,8 +696,8 @@ export class Model {
681
696
  if (keyFrames.length === 0)
682
697
  continue;
683
698
  const cachedIdx = this.boneTrackIndices.get(boneName) ?? -1;
684
- const clampedTime = Math.max(keyFrames[0].time, Math.min(keyFrames[keyFrames.length - 1].time, time));
685
- const idx = this.findKeyframeIndex(clampedTime, keyFrames, cachedIdx);
699
+ const clampedFrame = Math.max(keyFrames[0].frame, Math.min(keyFrames[keyFrames.length - 1].frame, frame));
700
+ const idx = this.findKeyframeIndex(clampedFrame, keyFrames, cachedIdx);
686
701
  if (idx < 0)
687
702
  continue;
688
703
  this.boneTrackIndices.set(boneName, idx);
@@ -700,8 +715,8 @@ export class Model {
700
715
  localTrans.set(localTranslation);
701
716
  }
702
717
  else {
703
- const timeDelta = frameB.time - frameA.time;
704
- const gradient = (clampedTime - frameA.time) / timeDelta;
718
+ const frameDelta = frameB.frame - frameA.frame;
719
+ const gradient = frameDelta > 0 ? (clampedFrame - frameA.frame) / frameDelta : 0;
705
720
  const interp = frameB.interpolation;
706
721
  const rotT = interpolateControlPoints(interp.rotation, gradient);
707
722
  const rotation = Quat.slerp(frameA.rotation, frameB.rotation, rotT);
@@ -718,8 +733,8 @@ export class Model {
718
733
  if (keyFrames.length === 0)
719
734
  continue;
720
735
  const cachedIdx = this.morphTrackIndices.get(morphName) ?? -1;
721
- const clampedTime = Math.max(keyFrames[0].time, Math.min(keyFrames[keyFrames.length - 1].time, time));
722
- const idx = this.findKeyframeIndex(clampedTime, keyFrames, cachedIdx);
736
+ const clampedFrame = Math.max(keyFrames[0].frame, Math.min(keyFrames[keyFrames.length - 1].frame, frame));
737
+ const idx = this.findKeyframeIndex(clampedFrame, keyFrames, cachedIdx);
723
738
  if (idx < 0)
724
739
  continue;
725
740
  this.morphTrackIndices.set(morphName, idx);
@@ -731,7 +746,9 @@ export class Model {
731
746
  const weight = frameB
732
747
  ? frameA.weight +
733
748
  (frameB.weight - frameA.weight) *
734
- ((clampedTime - keyFrames[idx].time) / (keyFrames[idx + 1].time - keyFrames[idx].time))
749
+ (keyFrames[idx + 1].frame > keyFrames[idx].frame
750
+ ? (clampedFrame - keyFrames[idx].frame) / (keyFrames[idx + 1].frame - keyFrames[idx].frame)
751
+ : 0)
735
752
  : frameA.weight;
736
753
  this.runtimeMorph.weights[morphIdx] = weight;
737
754
  this.morphsDirty = true; // Mark as dirty when animation sets morph weights
@@ -745,9 +762,9 @@ export class Model {
745
762
  const tweensChangedMorphs = this.updateTweens();
746
763
  this.animationState.update(deltaTime);
747
764
  const clip = this.animationState.getCurrentClip();
748
- const time = this.animationState.getCurrentTime();
765
+ const frame = this.animationState.getCurrentFrame();
749
766
  if (clip !== null) {
750
- this.applyPoseFromClip(clip, time);
767
+ this.applyPoseFromClip(clip, frame);
751
768
  }
752
769
  // Apply morphs if tweens changed morphs or animation changed morphs
753
770
  const verticesChanged = this.morphsDirty || tweensChangedMorphs;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reze-engine",
3
- "version": "0.9.4",
3
+ "version": "0.10.0",
4
4
  "description": "A lightweight WebGPU engine for real-time 3D MMD/PMX model rendering",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
package/src/animation.ts CHANGED
@@ -18,52 +18,82 @@ export interface BoneKeyframe {
18
18
  rotation: Quat
19
19
  translation: Vec3
20
20
  interpolation: BoneInterpolation
21
- time: number
22
21
  }
23
22
 
24
23
  export interface MorphKeyframe {
25
24
  morphName: string
26
25
  frame: number
27
26
  weight: number
28
- time: number
29
27
  }
30
28
 
31
29
  export interface AnimationClip {
32
30
  boneTracks: Map<string, BoneKeyframe[]>
33
31
  morphTracks: Map<string, MorphKeyframe[]>
32
+ frameCount: number // last keyframe frame index
33
+ }
34
+
35
+ export interface AnimationPlayOptions {
36
+ priority?: number // Higher number = higher priority. Default: 0.
37
+ loop?: boolean // When true, timeline wraps at end. Default: false.
38
+ }
39
+
40
+ /** Wall-clock playback progress; `current`/`duration` are seconds (clip span uses `AnimationClip.frameCount`, not `duration`). */
41
+ export interface AnimationProgress {
42
+ animationName: string | null
43
+ current: number
34
44
  duration: number
35
- loop?: boolean
45
+ percentage: number
46
+ looping: boolean
47
+ /** True while the timeline is advancing (not idle at end, not paused). */
48
+ playing: boolean
49
+ paused: boolean
50
+ }
51
+
52
+ export const FPS = 30
53
+
54
+ interface QueuedAnimationRequest {
55
+ name: string
56
+ priority: number
57
+ loop: boolean
36
58
  }
37
59
 
38
- // Non-interruptible playback; play(name) while playing queues one next.
60
+ // Priority-aware playback: higher priority preempts, otherwise latest request is queued.
39
61
  export class AnimationState {
40
62
  private animations = new Map<string, AnimationClip>()
41
63
  private currentAnimationName: string | null = null
42
- private currentTime = 0
64
+ private currentFrame = 0
65
+ private currentPriority = 0
66
+ private currentLoop = false
43
67
  private isPlaying = false
44
68
  private isPaused = false
45
- private nextAnimationName: string | null = null
69
+ private nextAnimation: QueuedAnimationRequest | null = null
46
70
  private onEnd: ((animationName: string) => void) | null = null
47
71
 
48
72
  loadAnimation(name: string, clip: AnimationClip): void {
49
- this.animations.set(name, clip)
73
+ this.animations.set(name, {
74
+ boneTracks: clip.boneTracks,
75
+ morphTracks: clip.morphTracks,
76
+ frameCount: clip.frameCount,
77
+ })
50
78
  }
51
79
 
52
80
  removeAnimation(name: string): void {
53
81
  this.animations.delete(name)
54
82
  if (this.currentAnimationName === name) {
55
83
  this.currentAnimationName = null
56
- this.currentTime = 0
84
+ this.currentFrame = 0
85
+ this.currentPriority = 0
86
+ this.currentLoop = false
57
87
  this.isPlaying = false
58
- this.nextAnimationName = this.nextAnimationName === name ? null : this.nextAnimationName
59
- } else if (this.nextAnimationName === name) {
60
- this.nextAnimationName = null
88
+ this.nextAnimation = this.nextAnimation?.name === name ? null : this.nextAnimation
89
+ } else if (this.nextAnimation?.name === name) {
90
+ this.nextAnimation = null
61
91
  }
62
92
  }
63
93
 
64
- play(name: string): boolean
94
+ play(name: string, options?: AnimationPlayOptions): boolean
65
95
  play(): void
66
- play(name?: string): boolean | void {
96
+ play(name?: string, options?: AnimationPlayOptions): boolean | void {
67
97
  if (name === undefined) {
68
98
  if (this.currentAnimationName && this.animations.has(this.currentAnimationName)) {
69
99
  this.isPaused = false
@@ -72,15 +102,39 @@ export class AnimationState {
72
102
  return
73
103
  }
74
104
  if (!this.animations.has(name)) return false
105
+ const priority = options?.priority ?? 0
106
+ const loop = options?.loop ?? false
107
+
108
+ if (this.currentAnimationName === name) {
109
+ this.currentFrame = 0
110
+ this.currentPriority = priority
111
+ this.currentLoop = loop
112
+ this.isPlaying = true
113
+ this.isPaused = false
114
+ return true
115
+ }
116
+
75
117
  if (this.isPlaying && !this.isPaused) {
76
- this.nextAnimationName = name
118
+ if (priority > this.currentPriority) {
119
+ this.currentAnimationName = name
120
+ this.currentFrame = 0
121
+ this.currentPriority = priority
122
+ this.currentLoop = loop
123
+ this.isPlaying = true
124
+ this.isPaused = false
125
+ this.nextAnimation = null
126
+ return true
127
+ }
128
+ this.nextAnimation = { name, priority, loop }
77
129
  return true
78
130
  }
79
131
  this.currentAnimationName = name
80
- this.currentTime = 0
132
+ this.currentFrame = 0
133
+ this.currentPriority = priority
134
+ this.currentLoop = loop
81
135
  this.isPlaying = true
82
136
  this.isPaused = false
83
- this.nextAnimationName = null
137
+ this.nextAnimation = null
84
138
  return true
85
139
  }
86
140
 
@@ -91,22 +145,30 @@ export class AnimationState {
91
145
  const clip = this.animations.get(this.currentAnimationName)
92
146
  if (!clip) return { ended: false, animationName: this.currentAnimationName }
93
147
 
94
- this.currentTime += deltaTime
95
- const duration = clip.duration
148
+ const frameCount = clip.frameCount
149
+ if (frameCount <= 0 || !Number.isFinite(frameCount)) {
150
+ return { ended: false, animationName: this.currentAnimationName }
151
+ }
152
+
153
+ this.currentFrame += deltaTime * FPS
96
154
 
97
- if (this.currentTime >= duration) {
98
- this.currentTime = duration
99
- if (clip.loop) {
100
- this.currentTime = 0
155
+ if (this.currentFrame >= frameCount) {
156
+ if (this.currentLoop) {
157
+ while (this.currentFrame >= frameCount) {
158
+ this.currentFrame -= frameCount
159
+ }
101
160
  return { ended: false, animationName: this.currentAnimationName }
102
161
  }
162
+ this.currentFrame = frameCount
103
163
  const finishedName = this.currentAnimationName
104
164
  this.onEnd?.(finishedName)
105
- if (this.nextAnimationName !== null) {
106
- const next = this.nextAnimationName
107
- this.nextAnimationName = null
108
- this.currentAnimationName = next
109
- this.currentTime = 0
165
+ if (this.nextAnimation !== null) {
166
+ const next = this.nextAnimation
167
+ this.nextAnimation = null
168
+ this.currentAnimationName = next.name
169
+ this.currentFrame = 0
170
+ this.currentPriority = next.priority
171
+ this.currentLoop = next.loop
110
172
  this.isPlaying = true
111
173
  this.isPaused = false
112
174
  return { ended: true, animationName: finishedName }
@@ -124,42 +186,62 @@ export class AnimationState {
124
186
  stop(): void {
125
187
  this.isPlaying = false
126
188
  this.isPaused = false
127
- this.currentTime = 0
128
- this.nextAnimationName = null
189
+ this.currentFrame = 0
190
+ this.currentPriority = 0
191
+ this.currentLoop = false
192
+ this.nextAnimation = null
129
193
  }
130
194
 
131
- seek(time: number): void {
195
+ // Seek by absolute timeline seconds, not frame index.
196
+ seek(seconds: number): void {
132
197
  const clip = this.getCurrentClip()
133
- if (!clip) return
134
- this.currentTime = Math.max(0, Math.min(time, clip.duration))
198
+ if (!clip || clip.frameCount <= 0 || !Number.isFinite(clip.frameCount)) return
199
+ const targetFrame = seconds * FPS
200
+ this.currentFrame = Math.max(0, Math.min(targetFrame, clip.frameCount))
135
201
  }
136
202
 
137
203
  getCurrentClip(): AnimationClip | null {
138
204
  return this.currentAnimationName !== null ? this.animations.get(this.currentAnimationName) ?? null : null
139
205
  }
140
206
 
207
+ getAnimationClip(name: string): AnimationClip | null {
208
+ return this.animations.get(name) ?? null
209
+ }
210
+
141
211
  getCurrentAnimation(): string | null {
142
212
  return this.currentAnimationName
143
213
  }
144
214
 
145
215
  getCurrentTime(): number {
146
- return this.currentTime
216
+ const clip = this.getCurrentClip()
217
+ if (!clip) return 0
218
+ return this.currentFrame / FPS
219
+ }
220
+
221
+ getCurrentFrame(): number {
222
+ return this.currentFrame
147
223
  }
148
224
 
225
+ /** Clip length in seconds (`frameCount / FPS`). */
149
226
  getDuration(): number {
150
227
  const clip = this.getCurrentClip()
151
- return clip ? clip.duration : 0
228
+ if (!clip || clip.frameCount <= 0 || !Number.isFinite(clip.frameCount)) return 0
229
+ return clip.frameCount / FPS
152
230
  }
153
231
 
154
- getProgress(): { animationName: string | null; current: number; duration: number; percentage: number } {
232
+ getProgress(): AnimationProgress {
155
233
  const clip = this.getCurrentClip()
156
- const duration = clip ? clip.duration : 0
157
- const percentage = duration > 0 ? (this.currentTime / duration) * 100 : 0
234
+ const duration = clip && clip.frameCount > 0 ? clip.frameCount / FPS : 0
235
+ const current = clip ? this.currentFrame / FPS : 0
236
+ const percentage = duration > 0 ? (current / duration) * 100 : 0
158
237
  return {
159
238
  animationName: this.currentAnimationName,
160
- current: this.currentTime,
239
+ current,
161
240
  duration,
162
241
  percentage,
242
+ looping: this.currentLoop,
243
+ playing: this.isPlaying && !this.isPaused,
244
+ paused: this.isPaused,
163
245
  }
164
246
  }
165
247
 
@@ -174,10 +256,12 @@ export class AnimationState {
174
256
  show(name: string): void {
175
257
  if (!this.animations.has(name)) return
176
258
  this.currentAnimationName = name
177
- this.currentTime = 0
259
+ this.currentFrame = 0
260
+ this.currentPriority = 0
261
+ this.currentLoop = false
178
262
  this.isPlaying = false
179
263
  this.isPaused = false
180
- this.nextAnimationName = null
264
+ this.nextAnimation = null
181
265
  }
182
266
 
183
267
  setOnEnd(callback: ((animationName: string) => void) | null): void {