distark-render 1.0.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/README.md +75 -0
- package/dist/modules/eyeSystem.d.ts +104 -0
- package/dist/modules/eyeSystem.d.ts.map +1 -0
- package/dist/modules/eyeSystem.js +326 -0
- package/dist/modules/eyeSystem.js.map +1 -0
- package/dist/modules/imageLoad.d.ts +86 -0
- package/dist/modules/imageLoad.d.ts.map +1 -0
- package/dist/modules/imageLoad.js +259 -0
- package/dist/modules/imageLoad.js.map +1 -0
- package/dist/modules/mouthSystem.d.ts +147 -0
- package/dist/modules/mouthSystem.d.ts.map +1 -0
- package/dist/modules/mouthSystem.js +277 -0
- package/dist/modules/mouthSystem.js.map +1 -0
- package/dist/modules/renderRig.d.ts +53 -0
- package/dist/modules/renderRig.d.ts.map +1 -0
- package/dist/modules/renderRig.js +1248 -0
- package/dist/modules/renderRig.js.map +1 -0
- package/dist/test-skia.d.ts +15 -0
- package/dist/test-skia.d.ts.map +1 -0
- package/dist/test-skia.js +179 -0
- package/dist/test-skia.js.map +1 -0
- package/dist/types.d.ts +204 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +61 -0
package/README.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Distark Render
|
|
2
|
+
|
|
3
|
+
Rendering-agnostic character rig system with TypeScript. Render 2D character rigs to HTML Canvas with automatic image loading and caching.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install distark-render
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### Browser (ES Modules)
|
|
14
|
+
|
|
15
|
+
```html
|
|
16
|
+
<canvas id="canvas" width="800" height="800"></canvas>
|
|
17
|
+
|
|
18
|
+
<script type="module">
|
|
19
|
+
import { ImageLoader, CharacterRigRenderer } from 'https://unpkg.com/distark-render';
|
|
20
|
+
|
|
21
|
+
const imageLoader = new ImageLoader();
|
|
22
|
+
const renderer = new CharacterRigRenderer(imageLoader);
|
|
23
|
+
const canvas = document.getElementById('canvas');
|
|
24
|
+
|
|
25
|
+
// Load character data
|
|
26
|
+
const characterData = await fetch('character.json').then(r => r.json());
|
|
27
|
+
|
|
28
|
+
// Render to canvas
|
|
29
|
+
await renderer.render(canvas, characterData);
|
|
30
|
+
</script>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Node.js
|
|
34
|
+
|
|
35
|
+
```javascript
|
|
36
|
+
import { ImageLoader, CharacterRigRenderer } from 'distark-render';
|
|
37
|
+
|
|
38
|
+
const imageLoader = new ImageLoader();
|
|
39
|
+
const renderer = new CharacterRigRenderer(imageLoader);
|
|
40
|
+
const canvas = document.getElementById('canvas');
|
|
41
|
+
const characterData = await fetch('character.json').then(r => r.json());
|
|
42
|
+
await renderer.render(canvas, characterData);
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Features
|
|
46
|
+
|
|
47
|
+
- 🎨 Rendering-agnostic architecture
|
|
48
|
+
- 🖼️ Automatic image loading and caching
|
|
49
|
+
- 🔄 Support for MD5 hashes and direct URLs
|
|
50
|
+
- 👁️ Eye and mouth animation systems
|
|
51
|
+
- ⚡ TypeScript support with full type definitions
|
|
52
|
+
- 🌐 Works in browser and Node.js
|
|
53
|
+
|
|
54
|
+
## API
|
|
55
|
+
|
|
56
|
+
### ImageLoader
|
|
57
|
+
|
|
58
|
+
Handles loading images from URLs or MD5 hashes with automatic caching.
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
const imageLoader = new ImageLoader(baseHost?: string);
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### CharacterRigRenderer
|
|
65
|
+
|
|
66
|
+
Renders character rigs to canvas.
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
const renderer = new CharacterRigRenderer(imageLoader?: ImageLoader);
|
|
70
|
+
await renderer.render(canvas, rigData, loadedImages?, cameraOffset?, showPivotPoints?);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## License
|
|
74
|
+
|
|
75
|
+
MIT
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Eye System Module
|
|
3
|
+
* Handles eye blinking, gaze direction, and eye movement for character rigs
|
|
4
|
+
*/
|
|
5
|
+
import type { EyeData, EyeDirection, EyelidState, EyeMovementConfig, EyeState, Position } from '../types.js';
|
|
6
|
+
/**
|
|
7
|
+
* EyeSystem class - Manages eye animation, blinking, and gaze for characters
|
|
8
|
+
*/
|
|
9
|
+
export declare class EyeSystem {
|
|
10
|
+
private state;
|
|
11
|
+
private eyeData;
|
|
12
|
+
private characterId;
|
|
13
|
+
/**
|
|
14
|
+
* Default eye movement ranges for different directions
|
|
15
|
+
*/
|
|
16
|
+
private static readonly EYE_MOVEMENT_RANGES;
|
|
17
|
+
/**
|
|
18
|
+
* Creates a new EyeSystem instance
|
|
19
|
+
* @param characterId - Unique identifier for the character
|
|
20
|
+
* @param eyeData - Eye configuration data from rig
|
|
21
|
+
*/
|
|
22
|
+
constructor(characterId: string, eyeData: EyeData);
|
|
23
|
+
/**
|
|
24
|
+
* Get current eye state
|
|
25
|
+
*/
|
|
26
|
+
getState(): EyeState;
|
|
27
|
+
/**
|
|
28
|
+
* Reset timing (call when timeline resets or on first frame)
|
|
29
|
+
*/
|
|
30
|
+
resetTiming(currentTime: number): void;
|
|
31
|
+
/**
|
|
32
|
+
* Detect if timeline has reset (time went backwards)
|
|
33
|
+
*/
|
|
34
|
+
private detectReset;
|
|
35
|
+
/**
|
|
36
|
+
* Update blinking animation
|
|
37
|
+
* @param currentTime - Current time in seconds
|
|
38
|
+
*/
|
|
39
|
+
updateBlinking(currentTime: number): void;
|
|
40
|
+
/**
|
|
41
|
+
* Update eye gaze direction
|
|
42
|
+
* @param currentTime - Current time in seconds
|
|
43
|
+
* @param config - Movement configuration (direction or target position)
|
|
44
|
+
*/
|
|
45
|
+
updateGazeDirection(currentTime: number, config: EyeMovementConfig): void;
|
|
46
|
+
/**
|
|
47
|
+
* Set eye direction using predefined movement ranges
|
|
48
|
+
*/
|
|
49
|
+
setEyeDirection(direction: EyeDirection): void;
|
|
50
|
+
/**
|
|
51
|
+
* Calculate eye direction to look at a target position
|
|
52
|
+
* @param targetPos - Target position in world space
|
|
53
|
+
* @param characterPos - Character position (optional, defaults to {x: 0, y: 0})
|
|
54
|
+
*/
|
|
55
|
+
calculateDirectionToPosition(targetPos: Position, characterPos?: Position): EyeDirection;
|
|
56
|
+
/**
|
|
57
|
+
* Random eye movement (simulates natural eye wandering)
|
|
58
|
+
*/
|
|
59
|
+
randomEyeMovement(): void;
|
|
60
|
+
/**
|
|
61
|
+
* Update eye system (handles both blinking and movement timing)
|
|
62
|
+
* @param currentTime - Current time in seconds
|
|
63
|
+
* @param isPlaying - Whether animation is playing (controls automatic movements)
|
|
64
|
+
* @param speakingCharacterPos - Position of speaking character (if any)
|
|
65
|
+
* @param characterPos - This character's position
|
|
66
|
+
*/
|
|
67
|
+
update(currentTime: number, isPlaying?: boolean, speakingCharacterPos?: Position, characterPos?: Position): void;
|
|
68
|
+
/**
|
|
69
|
+
* Get current eyelid image key based on state
|
|
70
|
+
*/
|
|
71
|
+
getEyelidImageKey(side: 'left' | 'right'): string;
|
|
72
|
+
/**
|
|
73
|
+
* Get current iris positions
|
|
74
|
+
*/
|
|
75
|
+
getIrisPositions(): {
|
|
76
|
+
left: Position;
|
|
77
|
+
right: Position;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Get current eyelid state
|
|
81
|
+
*/
|
|
82
|
+
getEyelidState(): EyelidState;
|
|
83
|
+
/**
|
|
84
|
+
* Set eye update interval (time between automatic eye movements)
|
|
85
|
+
*/
|
|
86
|
+
setEyeUpdateInterval(interval: number): void;
|
|
87
|
+
/**
|
|
88
|
+
* Set blink interval (time between blinks)
|
|
89
|
+
*/
|
|
90
|
+
setBlinkInterval(interval: number): void;
|
|
91
|
+
/**
|
|
92
|
+
* Force immediate blink
|
|
93
|
+
*/
|
|
94
|
+
forceBlink(): void;
|
|
95
|
+
/**
|
|
96
|
+
* Get debug info
|
|
97
|
+
*/
|
|
98
|
+
getDebugInfo(): string;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Factory function to create eye system from rig data
|
|
102
|
+
*/
|
|
103
|
+
export declare function createEyeSystem(characterId: string, eyeData: EyeData): EyeSystem;
|
|
104
|
+
//# sourceMappingURL=eyeSystem.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eyeSystem.d.ts","sourceRoot":"","sources":["../../modules/eyeSystem.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACR,OAAO,EACP,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,QAAQ,EACR,QAAQ,EACX,MAAM,aAAa,CAAC;AAErB;;GAEG;AACH,qBAAa,SAAS;IAClB,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,WAAW,CAAS;IAE5B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAWzC;IAEF;;;;OAIG;gBACS,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAwBjD;;OAEG;IACH,QAAQ,IAAI,QAAQ;IAIpB;;OAEG;IACH,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAQtC;;OAEG;IACH,OAAO,CAAC,WAAW;IAKnB;;;OAGG;IACH,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAgDzC;;;;OAIG;IACH,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,GAAG,IAAI;IAsCzE;;OAEG;IACH,eAAe,CAAC,SAAS,EAAE,YAAY,GAAG,IAAI;IAiB9C;;;;OAIG;IACH,4BAA4B,CAAC,SAAS,EAAE,QAAQ,EAAE,YAAY,GAAE,QAAyB,GAAG,YAAY;IAoBxG;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAMzB;;;;;;OAMG;IACH,MAAM,CACF,WAAW,EAAE,MAAM,EACnB,SAAS,GAAE,OAAe,EAC1B,oBAAoB,CAAC,EAAE,QAAQ,EAC/B,YAAY,GAAE,QAAyB,GACxC,IAAI;IA8CP;;OAEG;IACH,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM;IAejD;;OAEG;IACH,gBAAgB,IAAI;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,QAAQ,CAAA;KAAE;IAOvD;;OAEG;IACH,cAAc,IAAI,WAAW;IAI7B;;OAEG;IACH,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAI5C;;OAEG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAIxC;;OAEG;IACH,UAAU,IAAI,IAAI;IAMlB;;OAEG;IACH,YAAY,IAAI,MAAM;CAQzB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,SAAS,CAEhF"}
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Eye System Module
|
|
3
|
+
* Handles eye blinking, gaze direction, and eye movement for character rigs
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* EyeSystem class - Manages eye animation, blinking, and gaze for characters
|
|
7
|
+
*/
|
|
8
|
+
export class EyeSystem {
|
|
9
|
+
/**
|
|
10
|
+
* Creates a new EyeSystem instance
|
|
11
|
+
* @param characterId - Unique identifier for the character
|
|
12
|
+
* @param eyeData - Eye configuration data from rig
|
|
13
|
+
*/
|
|
14
|
+
constructor(characterId, eyeData) {
|
|
15
|
+
this.characterId = characterId;
|
|
16
|
+
this.eyeData = eyeData;
|
|
17
|
+
// Initialize state
|
|
18
|
+
this.state = {
|
|
19
|
+
eyeLastUpdatedTime: -1,
|
|
20
|
+
eyeUpdateInterval: 0.75,
|
|
21
|
+
currentDirection: 'center',
|
|
22
|
+
eyeLidLastUpdatedTime: null,
|
|
23
|
+
eyeLidUpdateInterval: 3.0 + Math.random() * 2.0, // 3-5 seconds between blinks
|
|
24
|
+
currentEyeLidCount: 0,
|
|
25
|
+
currentEyeLidState: 'open',
|
|
26
|
+
blinkDuration: 0.15,
|
|
27
|
+
nextBlinkOffset: Math.random() * 0.5, // Random offset for natural timing
|
|
28
|
+
leftIrisX: eyeData.leftIrisXCoor ?? 0,
|
|
29
|
+
leftIrisY: eyeData.leftIrisYCoor ?? 0,
|
|
30
|
+
rightIrisX: eyeData.rightIrisXCoor ?? 0,
|
|
31
|
+
rightIrisY: eyeData.rightIrisYCoor ?? 0
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Get current eye state
|
|
36
|
+
*/
|
|
37
|
+
getState() {
|
|
38
|
+
return { ...this.state };
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Reset timing (call when timeline resets or on first frame)
|
|
42
|
+
*/
|
|
43
|
+
resetTiming(currentTime) {
|
|
44
|
+
this.state.eyeLastUpdatedTime = currentTime - this.state.eyeUpdateInterval;
|
|
45
|
+
this.state.eyeLidLastUpdatedTime = null;
|
|
46
|
+
this.state.currentEyeLidCount = 0;
|
|
47
|
+
this.state.currentEyeLidState = 'open';
|
|
48
|
+
this.state.nextBlinkOffset = Math.random() * 0.5;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Detect if timeline has reset (time went backwards)
|
|
52
|
+
*/
|
|
53
|
+
detectReset(currentTime) {
|
|
54
|
+
const prevTime = this.state.eyeLastUpdatedTime;
|
|
55
|
+
return Number.isFinite(prevTime) && prevTime > 0 && (currentTime + 0.001 < prevTime);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Update blinking animation
|
|
59
|
+
* @param currentTime - Current time in seconds
|
|
60
|
+
*/
|
|
61
|
+
updateBlinking(currentTime) {
|
|
62
|
+
// Initialize blink timing if needed
|
|
63
|
+
if (this.state.eyeLidLastUpdatedTime === null) {
|
|
64
|
+
this.state.eyeLidLastUpdatedTime = currentTime - this.state.eyeLidUpdateInterval + this.state.nextBlinkOffset;
|
|
65
|
+
console.log(`🔧 [${this.characterId}] Blink timing initialized - eyeLidLastUpdatedTime: ${this.state.eyeLidLastUpdatedTime.toFixed(2)}s, interval: ${this.state.eyeLidUpdateInterval.toFixed(2)}s`);
|
|
66
|
+
}
|
|
67
|
+
const timeSinceBlink = currentTime - this.state.eyeLidLastUpdatedTime;
|
|
68
|
+
const oldState = this.state.currentEyeLidState;
|
|
69
|
+
console.log(`⏱️ [${this.characterId}] updateBlinking - currentTime: ${currentTime.toFixed(2)}s, timeSinceBlink: ${timeSinceBlink.toFixed(2)}s, interval: ${this.state.eyeLidUpdateInterval.toFixed(2)}s, currentState: ${this.state.currentEyeLidState}`);
|
|
70
|
+
// Check if it's time to start a new blink
|
|
71
|
+
if (timeSinceBlink >= this.state.eyeLidUpdateInterval) {
|
|
72
|
+
this.state.currentEyeLidCount = 1; // Start blinking
|
|
73
|
+
this.state.eyeLidLastUpdatedTime = currentTime;
|
|
74
|
+
this.state.currentEyeLidState = 'half-closed';
|
|
75
|
+
}
|
|
76
|
+
// If currently blinking, update blink state
|
|
77
|
+
else if (this.state.currentEyeLidCount > 0) {
|
|
78
|
+
const blinkProgress = timeSinceBlink / this.state.blinkDuration;
|
|
79
|
+
if (blinkProgress < 0.5) {
|
|
80
|
+
// Closing phase (0-50%)
|
|
81
|
+
this.state.currentEyeLidState = 'half-closed';
|
|
82
|
+
}
|
|
83
|
+
else if (blinkProgress < 1.0) {
|
|
84
|
+
// Fully closed at midpoint (50-100%)
|
|
85
|
+
this.state.currentEyeLidState = 'closed';
|
|
86
|
+
}
|
|
87
|
+
else if (blinkProgress < 1.5) {
|
|
88
|
+
// Opening phase (100-150%)
|
|
89
|
+
this.state.currentEyeLidState = 'half-closed';
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
// Blink complete (>150%)
|
|
93
|
+
this.state.currentEyeLidState = 'open';
|
|
94
|
+
this.state.currentEyeLidCount = 0;
|
|
95
|
+
// Randomize next blink interval
|
|
96
|
+
this.state.eyeLidUpdateInterval = 3.0 + Math.random() * 2.0;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
this.state.currentEyeLidState = 'open';
|
|
101
|
+
}
|
|
102
|
+
// Log when eyelid state changes
|
|
103
|
+
if (oldState !== this.state.currentEyeLidState) {
|
|
104
|
+
console.log(`👁️ [${this.characterId}] Eyelid: ${oldState} → ${this.state.currentEyeLidState}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Update eye gaze direction
|
|
109
|
+
* @param currentTime - Current time in seconds
|
|
110
|
+
* @param config - Movement configuration (direction or target position)
|
|
111
|
+
*/
|
|
112
|
+
updateGazeDirection(currentTime, config) {
|
|
113
|
+
// Update last updated time
|
|
114
|
+
this.state.eyeLastUpdatedTime = currentTime;
|
|
115
|
+
// Direct iris position control (manual positioning)
|
|
116
|
+
if (config.leftIrisXCoor !== undefined || config.leftIrisYCoor !== undefined ||
|
|
117
|
+
config.rightIrisXCoor !== undefined || config.rightIrisYCoor !== undefined) {
|
|
118
|
+
if (config.leftIrisXCoor !== undefined) {
|
|
119
|
+
this.state.leftIrisX = config.leftIrisXCoor;
|
|
120
|
+
}
|
|
121
|
+
if (config.leftIrisYCoor !== undefined) {
|
|
122
|
+
this.state.leftIrisY = config.leftIrisYCoor;
|
|
123
|
+
}
|
|
124
|
+
if (config.rightIrisXCoor !== undefined) {
|
|
125
|
+
this.state.rightIrisX = config.rightIrisXCoor;
|
|
126
|
+
}
|
|
127
|
+
if (config.rightIrisYCoor !== undefined) {
|
|
128
|
+
this.state.rightIrisY = config.rightIrisYCoor;
|
|
129
|
+
}
|
|
130
|
+
this.state.currentDirection = ''; // Custom position
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
// Direction-based movement
|
|
134
|
+
if (config.direction !== undefined) {
|
|
135
|
+
this.setEyeDirection(config.direction);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
// Target position-based movement
|
|
139
|
+
if (config.targetPosition) {
|
|
140
|
+
const direction = this.calculateDirectionToPosition(config.targetPosition);
|
|
141
|
+
this.setEyeDirection(direction);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Set eye direction using predefined movement ranges
|
|
146
|
+
*/
|
|
147
|
+
setEyeDirection(direction) {
|
|
148
|
+
this.state.currentDirection = direction;
|
|
149
|
+
const movement = EyeSystem.EYE_MOVEMENT_RANGES[direction] || { x: 0, y: 0 };
|
|
150
|
+
// Apply movement to base positions from eyeData
|
|
151
|
+
const baseLeftX = this.eyeData.leftIrisXCoor ?? 0;
|
|
152
|
+
const baseLeftY = this.eyeData.leftIrisYCoor ?? 0;
|
|
153
|
+
const baseRightX = this.eyeData.rightIrisXCoor ?? 0;
|
|
154
|
+
const baseRightY = this.eyeData.rightIrisYCoor ?? 0;
|
|
155
|
+
this.state.leftIrisX = baseLeftX + movement.x;
|
|
156
|
+
this.state.leftIrisY = baseLeftY + movement.y;
|
|
157
|
+
this.state.rightIrisX = baseRightX + movement.x;
|
|
158
|
+
this.state.rightIrisY = baseRightY + movement.y;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Calculate eye direction to look at a target position
|
|
162
|
+
* @param targetPos - Target position in world space
|
|
163
|
+
* @param characterPos - Character position (optional, defaults to {x: 0, y: 0})
|
|
164
|
+
*/
|
|
165
|
+
calculateDirectionToPosition(targetPos, characterPos = { x: 0, y: 0 }) {
|
|
166
|
+
const dx = targetPos.x - characterPos.x;
|
|
167
|
+
const dy = targetPos.y - characterPos.y;
|
|
168
|
+
const angle = Math.atan2(dy, dx);
|
|
169
|
+
const degrees = angle * 180 / Math.PI;
|
|
170
|
+
// Map angle to direction
|
|
171
|
+
if (degrees >= -22.5 && degrees < 22.5)
|
|
172
|
+
return 'right';
|
|
173
|
+
if (degrees >= 22.5 && degrees < 67.5)
|
|
174
|
+
return 'down-right';
|
|
175
|
+
if (degrees >= 67.5 && degrees < 112.5)
|
|
176
|
+
return 'down';
|
|
177
|
+
if (degrees >= 112.5 && degrees < 157.5)
|
|
178
|
+
return 'down-left';
|
|
179
|
+
if (degrees >= 157.5 || degrees < -157.5)
|
|
180
|
+
return 'left';
|
|
181
|
+
if (degrees >= -157.5 && degrees < -112.5)
|
|
182
|
+
return 'up-left';
|
|
183
|
+
if (degrees >= -112.5 && degrees < -67.5)
|
|
184
|
+
return 'up';
|
|
185
|
+
if (degrees >= -67.5 && degrees < -22.5)
|
|
186
|
+
return 'up-right';
|
|
187
|
+
return 'center';
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Random eye movement (simulates natural eye wandering)
|
|
191
|
+
*/
|
|
192
|
+
randomEyeMovement() {
|
|
193
|
+
const directions = ['left', 'right', 'up', 'down', 'center', 'up-left', 'up-right', 'down-left', 'down-right'];
|
|
194
|
+
const randomDirection = directions[Math.floor(Math.random() * directions.length)];
|
|
195
|
+
this.setEyeDirection(randomDirection);
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Update eye system (handles both blinking and movement timing)
|
|
199
|
+
* @param currentTime - Current time in seconds
|
|
200
|
+
* @param isPlaying - Whether animation is playing (controls automatic movements)
|
|
201
|
+
* @param speakingCharacterPos - Position of speaking character (if any)
|
|
202
|
+
* @param characterPos - This character's position
|
|
203
|
+
*/
|
|
204
|
+
update(currentTime, isPlaying = false, speakingCharacterPos, characterPos = { x: 0, y: 0 }) {
|
|
205
|
+
console.log(`🔍 [${this.characterId}] EyeSystem.update called - time: ${currentTime.toFixed(2)}s, isPlaying: ${isPlaying}`);
|
|
206
|
+
// Handle timeline reset
|
|
207
|
+
if (currentTime < 0.1 || this.detectReset(currentTime)) {
|
|
208
|
+
console.log(`🔄 [${this.characterId}] Timeline reset detected, resetting timing`);
|
|
209
|
+
this.resetTiming(currentTime);
|
|
210
|
+
}
|
|
211
|
+
// Always update blinking (works even when paused)
|
|
212
|
+
console.log(`👁️ [${this.characterId}] Calling updateBlinking...`);
|
|
213
|
+
this.updateBlinking(currentTime);
|
|
214
|
+
// Eye movement only when playing
|
|
215
|
+
if (!isPlaying) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
const timeSinceUpdate = currentTime - this.state.eyeLastUpdatedTime;
|
|
219
|
+
const shouldUpdate = timeSinceUpdate >= this.state.eyeUpdateInterval;
|
|
220
|
+
if (!shouldUpdate) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
// Priority 1: Look at speaking character
|
|
224
|
+
if (speakingCharacterPos) {
|
|
225
|
+
const shouldLookAtSpeaker = Math.random() < 0.7; // 70% chance to look at speaker
|
|
226
|
+
if (shouldLookAtSpeaker) {
|
|
227
|
+
const direction = this.calculateDirectionToPosition(speakingCharacterPos, characterPos);
|
|
228
|
+
this.updateGazeDirection(currentTime, { direction });
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
this.randomEyeMovement();
|
|
232
|
+
this.state.eyeLastUpdatedTime = currentTime;
|
|
233
|
+
}
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
// Priority 2: Random eye movement (50% chance)
|
|
237
|
+
if (Math.random() < 0.5) {
|
|
238
|
+
this.randomEyeMovement();
|
|
239
|
+
this.state.eyeLastUpdatedTime = currentTime;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Get current eyelid image key based on state
|
|
244
|
+
*/
|
|
245
|
+
getEyelidImageKey(side) {
|
|
246
|
+
const prefix = side === 'left' ? 'leftEyeLid' : 'rightEyeLid';
|
|
247
|
+
switch (this.state.currentEyeLidState) {
|
|
248
|
+
case 'open':
|
|
249
|
+
return `eyes.${prefix}Open`;
|
|
250
|
+
case 'half-closed':
|
|
251
|
+
return `eyes.${prefix}HalfClosed`;
|
|
252
|
+
case 'closed':
|
|
253
|
+
return `eyes.${prefix}Closed`;
|
|
254
|
+
default:
|
|
255
|
+
return `eyes.${prefix}Open`;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Get current iris positions
|
|
260
|
+
*/
|
|
261
|
+
getIrisPositions() {
|
|
262
|
+
return {
|
|
263
|
+
left: { x: this.state.leftIrisX, y: this.state.leftIrisY },
|
|
264
|
+
right: { x: this.state.rightIrisX, y: this.state.rightIrisY }
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Get current eyelid state
|
|
269
|
+
*/
|
|
270
|
+
getEyelidState() {
|
|
271
|
+
return this.state.currentEyeLidState;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Set eye update interval (time between automatic eye movements)
|
|
275
|
+
*/
|
|
276
|
+
setEyeUpdateInterval(interval) {
|
|
277
|
+
this.state.eyeUpdateInterval = interval;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Set blink interval (time between blinks)
|
|
281
|
+
*/
|
|
282
|
+
setBlinkInterval(interval) {
|
|
283
|
+
this.state.eyeLidUpdateInterval = interval;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Force immediate blink
|
|
287
|
+
*/
|
|
288
|
+
forceBlink() {
|
|
289
|
+
this.state.currentEyeLidCount = 1;
|
|
290
|
+
this.state.currentEyeLidState = 'closed';
|
|
291
|
+
this.state.eyeLidLastUpdatedTime = Date.now() / 1000; // Use current time
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Get debug info
|
|
295
|
+
*/
|
|
296
|
+
getDebugInfo() {
|
|
297
|
+
return `Eye System [${this.characterId}]
|
|
298
|
+
Direction: ${this.state.currentDirection}
|
|
299
|
+
Eyelid: ${this.state.currentEyeLidState}
|
|
300
|
+
Iris L: (${this.state.leftIrisX.toFixed(1)}, ${this.state.leftIrisY.toFixed(1)})
|
|
301
|
+
Iris R: (${this.state.rightIrisX.toFixed(1)}, ${this.state.rightIrisY.toFixed(1)})
|
|
302
|
+
Last Update: ${this.state.eyeLastUpdatedTime.toFixed(2)}s`;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Default eye movement ranges for different directions
|
|
307
|
+
*/
|
|
308
|
+
EyeSystem.EYE_MOVEMENT_RANGES = {
|
|
309
|
+
'left': { x: -5, y: 0 },
|
|
310
|
+
'right': { x: 5, y: 0 },
|
|
311
|
+
'up': { x: 0, y: -3 },
|
|
312
|
+
'down': { x: 0, y: 3 },
|
|
313
|
+
'center': { x: 0, y: 0 },
|
|
314
|
+
'up-left': { x: -4, y: -2 },
|
|
315
|
+
'up-right': { x: 4, y: -2 },
|
|
316
|
+
'down-left': { x: -4, y: 2 },
|
|
317
|
+
'down-right': { x: 4, y: 2 },
|
|
318
|
+
'': { x: 0, y: 0 }
|
|
319
|
+
};
|
|
320
|
+
/**
|
|
321
|
+
* Factory function to create eye system from rig data
|
|
322
|
+
*/
|
|
323
|
+
export function createEyeSystem(characterId, eyeData) {
|
|
324
|
+
return new EyeSystem(characterId, eyeData);
|
|
325
|
+
}
|
|
326
|
+
//# sourceMappingURL=eyeSystem.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eyeSystem.js","sourceRoot":"","sources":["../../modules/eyeSystem.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image Loading Module
|
|
3
|
+
* Handles loading images from MD5 hashes or URLs with caching support
|
|
4
|
+
*/
|
|
5
|
+
import type { ImageLoadCallback, ImageErrorCallback, RigData } from '../types.js';
|
|
6
|
+
/**
|
|
7
|
+
* ImageLoader class - Handles loading and caching images for character rigs
|
|
8
|
+
*/
|
|
9
|
+
export declare class ImageLoader {
|
|
10
|
+
private baseHost;
|
|
11
|
+
private imageCache;
|
|
12
|
+
/**
|
|
13
|
+
* Creates a new ImageLoader instance
|
|
14
|
+
* @param baseHost - The base URL for the API (default: 'https://orchestrator.distark.com')
|
|
15
|
+
*/
|
|
16
|
+
constructor(baseHost?: string);
|
|
17
|
+
/**
|
|
18
|
+
* Set the base host for image loading
|
|
19
|
+
* @param host - The base URL for the API
|
|
20
|
+
*/
|
|
21
|
+
setBaseHost(host: string): void;
|
|
22
|
+
/**
|
|
23
|
+
* Get the current base host
|
|
24
|
+
* @returns The current base host URL
|
|
25
|
+
*/
|
|
26
|
+
getBaseHost(): string;
|
|
27
|
+
/**
|
|
28
|
+
* Resolve an image source (hash or URL) to a full URL
|
|
29
|
+
* @param imageData - Image hash, URL, or data URL
|
|
30
|
+
* @returns Full URL or null if invalid
|
|
31
|
+
*/
|
|
32
|
+
resolveImageSource(imageData: string | null | undefined): string | null;
|
|
33
|
+
/**
|
|
34
|
+
* Load an image from a URL/hash and invoke callbacks
|
|
35
|
+
* @param key - Unique key for the image
|
|
36
|
+
* @param imageData - Image hash or URL
|
|
37
|
+
* @param onLoad - Callback when image loads successfully
|
|
38
|
+
* @param onError - Callback when image fails to load (optional)
|
|
39
|
+
*/
|
|
40
|
+
loadImage(key: string, imageData: string | null | undefined, onLoad?: ImageLoadCallback, onError?: ImageErrorCallback): void;
|
|
41
|
+
/**
|
|
42
|
+
* Load multiple images in parallel
|
|
43
|
+
* @param imagesToLoad - Array of {key, hash} objects
|
|
44
|
+
* @param onProgress - Optional callback for progress updates
|
|
45
|
+
* @returns Promise that resolves with loaded images map
|
|
46
|
+
*/
|
|
47
|
+
loadImages(imagesToLoad: Array<{
|
|
48
|
+
key: string;
|
|
49
|
+
hash: string;
|
|
50
|
+
}>, onProgress?: (loaded: number, total: number, failed: number) => void): Promise<Record<string, HTMLImageElement>>;
|
|
51
|
+
/**
|
|
52
|
+
* Get the image cache
|
|
53
|
+
* @returns The image cache Map
|
|
54
|
+
*/
|
|
55
|
+
getImageCache(): Map<string, HTMLImageElement>;
|
|
56
|
+
/**
|
|
57
|
+
* Clear the image cache
|
|
58
|
+
*/
|
|
59
|
+
clearImageCache(): void;
|
|
60
|
+
/**
|
|
61
|
+
* Get image from cache or return undefined
|
|
62
|
+
* @param key - Image key
|
|
63
|
+
*/
|
|
64
|
+
getCachedImage(key: string): HTMLImageElement | undefined;
|
|
65
|
+
/**
|
|
66
|
+
* Manually add image to cache
|
|
67
|
+
* @param key - Image key
|
|
68
|
+
* @param image - Image element
|
|
69
|
+
*/
|
|
70
|
+
cacheImage(key: string, image: HTMLImageElement): void;
|
|
71
|
+
/**
|
|
72
|
+
* Load image with caching support
|
|
73
|
+
* Checks cache first, only loads if not cached
|
|
74
|
+
*/
|
|
75
|
+
loadImageWithCache(key: string, imageData: string | null | undefined, onLoad?: ImageLoadCallback, onError?: ImageErrorCallback): void;
|
|
76
|
+
/**
|
|
77
|
+
* Load all images for a character rig and populate the cache
|
|
78
|
+
* @param rigData - Character rig data
|
|
79
|
+
* @param useCache - Whether to use existing cache (default: true)
|
|
80
|
+
* @param onProgress - Progress callback
|
|
81
|
+
* @returns Promise that resolves with the image cache as a plain object
|
|
82
|
+
*/
|
|
83
|
+
loadAllRigImages(rigData: RigData, useCache?: boolean, onProgress?: (loaded: number, total: number, failed: number) => void): Promise<Record<string, HTMLImageElement>>;
|
|
84
|
+
}
|
|
85
|
+
export declare const defaultImageLoader: ImageLoader;
|
|
86
|
+
//# sourceMappingURL=imageLoad.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"imageLoad.d.ts","sourceRoot":"","sources":["../../modules/imageLoad.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAElF;;GAEG;AACH,qBAAa,WAAW;IACpB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAAgC;IAElD;;;OAGG;gBACS,QAAQ,GAAE,MAA2C;IAKjE;;;OAGG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI/B;;;OAGG;IACH,WAAW,IAAI,MAAM;IAIrB;;;;OAIG;IACH,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI;IA6BvE;;;;;;OAMG;IACH,SAAS,CACL,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACpC,MAAM,CAAC,EAAE,iBAAiB,EAC1B,OAAO,CAAC,EAAE,kBAAkB,GAC7B,IAAI;IAmCP;;;;;OAKG;IACG,UAAU,CACZ,YAAY,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,EAClD,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,GACrE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAkC5C;;;OAGG;IACH,aAAa,IAAI,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAI9C;;OAEG;IACH,eAAe,IAAI,IAAI;IAKvB;;;OAGG;IACH,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IAIzD;;;;OAIG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,IAAI;IAItD;;;OAGG;IACH,kBAAkB,CACd,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACpC,MAAM,CAAC,EAAE,iBAAiB,EAC1B,OAAO,CAAC,EAAE,kBAAkB,GAC7B,IAAI;IA2BP;;;;;;OAMG;IACG,gBAAgB,CAClB,OAAO,EAAE,OAAO,EAChB,QAAQ,GAAE,OAAc,EACxB,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,GACrE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CAqF/C;AAGD,eAAO,MAAM,kBAAkB,aAAoB,CAAC"}
|