@hmcs/sdk 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 +30 -0
- package/dist/app.cjs +63 -0
- package/dist/app.js +63 -0
- package/dist/assets.cjs +52 -0
- package/dist/assets.js +52 -0
- package/dist/audio.cjs +159 -0
- package/dist/audio.js +159 -0
- package/dist/commands.cjs +298 -0
- package/dist/commands.d.ts +852 -0
- package/dist/commands.js +296 -0
- package/dist/coordinates.cjs +69 -0
- package/dist/coordinates.js +69 -0
- package/dist/displays.cjs +38 -0
- package/dist/displays.js +38 -0
- package/dist/effects.cjs +50 -0
- package/dist/effects.js +50 -0
- package/dist/entities.cjs +249 -0
- package/dist/entities.js +249 -0
- package/dist/host.cjs +297 -0
- package/dist/host.js +294 -0
- package/dist/index.cjs +98 -0
- package/dist/index.d.ts +2612 -0
- package/dist/index.js +17 -0
- package/dist/mods.cjs +207 -0
- package/dist/mods.js +207 -0
- package/dist/preferences.cjs +90 -0
- package/dist/preferences.js +90 -0
- package/dist/settings.cjs +46 -0
- package/dist/settings.js +46 -0
- package/dist/shadowPanel.cjs +46 -0
- package/dist/shadowPanel.js +46 -0
- package/dist/signals.cjs +158 -0
- package/dist/signals.js +158 -0
- package/dist/speech.cjs +48 -0
- package/dist/speech.js +48 -0
- package/dist/utils.cjs +13 -0
- package/dist/utils.js +11 -0
- package/dist/vrm.cjs +469 -0
- package/dist/vrm.js +466 -0
- package/dist/webviews.cjs +310 -0
- package/dist/webviews.js +302 -0
- package/package.json +61 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,2612 @@
|
|
|
1
|
+
import { EventSource } from 'eventsource';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Mathematical types and interfaces for 3D graphics and spatial calculations.
|
|
5
|
+
*
|
|
6
|
+
* This module provides type definitions for common mathematical concepts used
|
|
7
|
+
* throughout the Desktop Homunculus SDK, including transforms, vectors, and
|
|
8
|
+
* domain-specific request/response types.
|
|
9
|
+
* These types are designed to be compatible with Bevy's math system.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* // Working with transforms
|
|
14
|
+
* const transform: TransformArgs = {
|
|
15
|
+
* translation: [0, 100, 0],
|
|
16
|
+
* rotation: [0, 0, 0, 1],
|
|
17
|
+
* scale: [1, 1, 1]
|
|
18
|
+
* };
|
|
19
|
+
*
|
|
20
|
+
* // Working with vectors
|
|
21
|
+
* const position: Vec3 = [10, 20, 30];
|
|
22
|
+
* const screenPos: Vec2 = [1920, 1080];
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* Represents a 3D transformation containing position, rotation, and scale.
|
|
27
|
+
*
|
|
28
|
+
* This is the core type for positioning objects in 3D space. All spatial
|
|
29
|
+
* operations in Desktop Homunculus use this transform representation,
|
|
30
|
+
* which is compatible with Bevy's Transform component.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* const identity: Transform = {
|
|
35
|
+
* translation: [0, 0, 0],
|
|
36
|
+
* rotation: [0, 0, 0, 1],
|
|
37
|
+
* scale: [1, 1, 1]
|
|
38
|
+
* };
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
interface Transform {
|
|
42
|
+
/**
|
|
43
|
+
* The position of the entity in world space.
|
|
44
|
+
* Format: [x, y, z] where Y is typically up in Bevy's coordinate system.
|
|
45
|
+
*/
|
|
46
|
+
translation: [number, number, number];
|
|
47
|
+
/**
|
|
48
|
+
* The rotation of the entity in world space, represented as a quaternion.
|
|
49
|
+
* Format: [x, y, z, w] where [0, 0, 0, 1] represents no rotation (identity).
|
|
50
|
+
*/
|
|
51
|
+
rotation: [number, number, number, number];
|
|
52
|
+
/**
|
|
53
|
+
* The scale of the entity in world space.
|
|
54
|
+
* Format: [x, y, z] where [1, 1, 1] represents normal size.
|
|
55
|
+
*/
|
|
56
|
+
scale: [number, number, number];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Represents a 2D vector as [x, y].
|
|
60
|
+
* Used for screen coordinates, UI positions, and 2D math operations.
|
|
61
|
+
* Compatible with Bevy's Vec2 serialization format.
|
|
62
|
+
*/
|
|
63
|
+
type Vec2 = [number, number];
|
|
64
|
+
/**
|
|
65
|
+
* Represents a 3D vector as [x, y, z].
|
|
66
|
+
* Used for 3D positions, directions, and mathematical calculations.
|
|
67
|
+
* Compatible with Bevy's Vec3 serialization format.
|
|
68
|
+
*/
|
|
69
|
+
type Vec3 = [number, number, number];
|
|
70
|
+
/**
|
|
71
|
+
* Represents a quaternion rotation as [x, y, z, w].
|
|
72
|
+
* Compatible with Bevy's Quat serialization format.
|
|
73
|
+
*/
|
|
74
|
+
type Quat = [number, number, number, number];
|
|
75
|
+
/** Transform arguments for API requests. Partial version of Transform. */
|
|
76
|
+
interface TransformArgs {
|
|
77
|
+
translation?: Vec3;
|
|
78
|
+
rotation?: Quat;
|
|
79
|
+
scale?: Vec3;
|
|
80
|
+
}
|
|
81
|
+
/** A 2D rectangle defined by minimum and maximum points. */
|
|
82
|
+
interface Rect {
|
|
83
|
+
min: Vec2;
|
|
84
|
+
max: Vec2;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Coordinates API namespace provides coordinate system transformation utilities.
|
|
89
|
+
*
|
|
90
|
+
* Provides utilities for converting between different coordinate spaces used in the
|
|
91
|
+
* Desktop Homunculus 3D environment. This is essential for positioning UI elements,
|
|
92
|
+
* placing effects, and converting between screen coordinates and 3D world positions.
|
|
93
|
+
*
|
|
94
|
+
* Coordinate systems:
|
|
95
|
+
* - **Global Viewport**: Screen-space coordinates relative to the entire desktop
|
|
96
|
+
* - **World 2D**: 2D coordinates within the 3D world space
|
|
97
|
+
* - **World 3D**: Full 3D coordinates in world space
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```typescript
|
|
101
|
+
* // Convert mouse position to 3D world coordinates
|
|
102
|
+
* const worldPos2D = await coordinates.toWorld({ x: 150, y: 200 });
|
|
103
|
+
*
|
|
104
|
+
* // Convert 3D object position to screen coordinates
|
|
105
|
+
* const screenPos = await coordinates.toViewport({ x: 0, y: 1.5, z: 0 });
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
declare namespace coordinates {
|
|
109
|
+
/** 2D world coordinates within the 3D scene. */
|
|
110
|
+
type World2d = Vec2;
|
|
111
|
+
/** Full 3D world coordinates with x, y, and z components. */
|
|
112
|
+
type World3d = Vec3;
|
|
113
|
+
/**
|
|
114
|
+
* Converts global viewport coordinates to 2D world space coordinates.
|
|
115
|
+
*
|
|
116
|
+
* This transformation maps screen-space coordinates (like mouse positions or
|
|
117
|
+
* UI element positions) into the 2D coordinate system of the 3D world.
|
|
118
|
+
*
|
|
119
|
+
* @param viewport - Screen coordinates to convert (uses center if not provided)
|
|
120
|
+
* @returns A promise that resolves to the corresponding 2D world coordinates
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```typescript
|
|
124
|
+
* const worldPos = await coordinates.toWorld({ x: 150, y: 200 });
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
function toWorld(viewport?: {
|
|
128
|
+
x?: number;
|
|
129
|
+
y?: number;
|
|
130
|
+
}): Promise<Vec2>;
|
|
131
|
+
/**
|
|
132
|
+
* Converts 3D world coordinates to global viewport (screen) coordinates.
|
|
133
|
+
*
|
|
134
|
+
* This transformation projects 3D positions in the world onto screen space,
|
|
135
|
+
* allowing you to position UI elements, effects, or webviews relative to
|
|
136
|
+
* 3D objects like VRM characters or scene elements.
|
|
137
|
+
*
|
|
138
|
+
* @param world - 3D world coordinates to convert (uses origin if not provided)
|
|
139
|
+
* @returns A promise that resolves to the corresponding screen coordinates
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```typescript
|
|
143
|
+
* const screenPos = await coordinates.toViewport({ x: 0, y: 1.5, z: 0 });
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
function toViewport(world?: {
|
|
147
|
+
x?: number;
|
|
148
|
+
y?: number;
|
|
149
|
+
z?: number;
|
|
150
|
+
}): Promise<GlobalViewport>;
|
|
151
|
+
}
|
|
152
|
+
/** Information about a connected display/monitor. */
|
|
153
|
+
interface GlobalDisplay {
|
|
154
|
+
/** Unique display identifier. */
|
|
155
|
+
id: number;
|
|
156
|
+
/** Human-readable display name. */
|
|
157
|
+
title: string;
|
|
158
|
+
/** Display frame rectangle in screen coordinates. */
|
|
159
|
+
frame: Rect;
|
|
160
|
+
}
|
|
161
|
+
/** Global viewport coordinates (screen-space position) as [x, y]. */
|
|
162
|
+
type GlobalViewport = [number, number];
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Displays API namespace for monitor and screen management.
|
|
166
|
+
*
|
|
167
|
+
* Provides functionality to query information about connected displays/monitors,
|
|
168
|
+
* including their dimensions, positions, and frame rectangles.
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* ```typescript
|
|
172
|
+
* const allDisplays = await displays.findAll();
|
|
173
|
+
* console.log(`Found ${allDisplays.length} displays`);
|
|
174
|
+
* allDisplays.forEach((display) => {
|
|
175
|
+
* console.log(`${display.title}: (${display.frame.min.x}, ${display.frame.min.y}) - (${display.frame.max.x}, ${display.frame.max.y})`);
|
|
176
|
+
* });
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
declare namespace displays {
|
|
180
|
+
/**
|
|
181
|
+
* Retrieves information about all currently connected displays/monitors.
|
|
182
|
+
*
|
|
183
|
+
* @returns A promise that resolves to an array of display information
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* ```typescript
|
|
187
|
+
* const allDisplays = await displays.findAll();
|
|
188
|
+
* console.log(`System has ${allDisplays.length} displays`);
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
function findAll(): Promise<GlobalDisplay[]>;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Audio API namespace for playing sound effects and background music.
|
|
196
|
+
*
|
|
197
|
+
* Provides functionality for one-shot sound effects ({@link audio.se}) and
|
|
198
|
+
* looping background music with transport controls ({@link audio.bgm}).
|
|
199
|
+
*
|
|
200
|
+
* @example
|
|
201
|
+
* ```typescript
|
|
202
|
+
* // Play a sound effect
|
|
203
|
+
* await audio.se.play("click");
|
|
204
|
+
*
|
|
205
|
+
* // Play background music with fade-in
|
|
206
|
+
* await audio.bgm.play("heme", {
|
|
207
|
+
* volume: 0.8,
|
|
208
|
+
* fadeIn: { durationSecs: 2.0 }
|
|
209
|
+
* });
|
|
210
|
+
*
|
|
211
|
+
* // Stop BGM with fade-out
|
|
212
|
+
* await audio.bgm.stop({ fadeOut: { durationSecs: 1.5 } });
|
|
213
|
+
* ```
|
|
214
|
+
*/
|
|
215
|
+
declare namespace audio {
|
|
216
|
+
/**
|
|
217
|
+
* Configuration options for sound effect playback.
|
|
218
|
+
*/
|
|
219
|
+
interface SeOptions {
|
|
220
|
+
/** Volume level (0.0-1.0). Default: 1.0 */
|
|
221
|
+
volume?: number;
|
|
222
|
+
/** Playback speed. Default: 1.0 */
|
|
223
|
+
speed?: number;
|
|
224
|
+
/** Stereo panning (-1.0 left to 1.0 right). Default: 0.0 */
|
|
225
|
+
panning?: number;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Tween configuration for fade transitions.
|
|
229
|
+
*/
|
|
230
|
+
interface FadeTween {
|
|
231
|
+
/** Duration in seconds */
|
|
232
|
+
durationSecs: number;
|
|
233
|
+
/** Easing function. Default: "linear" */
|
|
234
|
+
easing?: "linear" | "easeIn" | "easeOut" | "easeInOut";
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Configuration options for starting BGM playback.
|
|
238
|
+
*/
|
|
239
|
+
interface BgmPlayOptions {
|
|
240
|
+
/** Loop playback. Default: true */
|
|
241
|
+
loop?: boolean;
|
|
242
|
+
/** Volume level (0.0-1.0). Default: 1.0 */
|
|
243
|
+
volume?: number;
|
|
244
|
+
/** Playback speed. Default: 1.0 */
|
|
245
|
+
speed?: number;
|
|
246
|
+
/** Fade-in settings */
|
|
247
|
+
fadeIn?: FadeTween;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Configuration options for stopping BGM playback.
|
|
251
|
+
*/
|
|
252
|
+
interface BgmStopOptions {
|
|
253
|
+
/** Fade-out settings. Omit for immediate stop */
|
|
254
|
+
fadeOut?: FadeTween;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Configuration options for updating BGM playback parameters.
|
|
258
|
+
*/
|
|
259
|
+
interface BgmUpdateOptions {
|
|
260
|
+
/** New volume level */
|
|
261
|
+
volume?: number;
|
|
262
|
+
/** New playback speed */
|
|
263
|
+
speed?: number;
|
|
264
|
+
/** Transition settings */
|
|
265
|
+
tween?: FadeTween;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Current BGM playback status.
|
|
269
|
+
*/
|
|
270
|
+
interface BgmStatus {
|
|
271
|
+
/** Current asset ID (null if stopped) */
|
|
272
|
+
asset: string | null;
|
|
273
|
+
/** Playback state */
|
|
274
|
+
state: "playing" | "paused" | "stopped";
|
|
275
|
+
/** Loop setting */
|
|
276
|
+
loop: boolean;
|
|
277
|
+
/** Current volume */
|
|
278
|
+
volume: number;
|
|
279
|
+
/** Current speed */
|
|
280
|
+
speed: number;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Sound effects (SE) sub-namespace for one-shot audio playback.
|
|
284
|
+
*
|
|
285
|
+
* @example
|
|
286
|
+
* ```typescript
|
|
287
|
+
* // Simple sound effect
|
|
288
|
+
* await audio.se.play("my-mod:notification");
|
|
289
|
+
*
|
|
290
|
+
* // With options
|
|
291
|
+
* await audio.se.play("my-mod:alert", {
|
|
292
|
+
* volume: 0.5,
|
|
293
|
+
* speed: 1.2,
|
|
294
|
+
* panning: -0.5
|
|
295
|
+
* });
|
|
296
|
+
* ```
|
|
297
|
+
*/
|
|
298
|
+
namespace se {
|
|
299
|
+
/**
|
|
300
|
+
* Plays a one-shot sound effect.
|
|
301
|
+
*
|
|
302
|
+
* @param asset - The asset ID of the sound effect (e.g., `"click"`)
|
|
303
|
+
* @param options - Optional playback configuration
|
|
304
|
+
*
|
|
305
|
+
* @example
|
|
306
|
+
* ```typescript
|
|
307
|
+
* await audio.se.play("click");
|
|
308
|
+
*
|
|
309
|
+
* await audio.se.play("coin", {
|
|
310
|
+
* volume: 0.7,
|
|
311
|
+
* speed: 1.5,
|
|
312
|
+
* panning: 0.3
|
|
313
|
+
* });
|
|
314
|
+
* ```
|
|
315
|
+
*/
|
|
316
|
+
function play(asset: string, options?: SeOptions): Promise<void>;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Background music (BGM) sub-namespace for continuous audio playback with transport controls.
|
|
320
|
+
*
|
|
321
|
+
* Only one BGM track plays at a time. Starting a new track replaces the current one.
|
|
322
|
+
*
|
|
323
|
+
* @example
|
|
324
|
+
* ```typescript
|
|
325
|
+
* // Play looping background music
|
|
326
|
+
* await audio.bgm.play("theme");
|
|
327
|
+
*
|
|
328
|
+
* // Pause and resume
|
|
329
|
+
* await audio.bgm.pause();
|
|
330
|
+
* await audio.bgm.resume();
|
|
331
|
+
*
|
|
332
|
+
* // Check current status
|
|
333
|
+
* const status = await audio.bgm.status();
|
|
334
|
+
* console.log(status.state); // "playing" | "paused" | "stopped"
|
|
335
|
+
* ```
|
|
336
|
+
*/
|
|
337
|
+
namespace bgm {
|
|
338
|
+
/**
|
|
339
|
+
* Plays background music, replacing any currently playing BGM.
|
|
340
|
+
*
|
|
341
|
+
* @param asset - The asset ID of the music track (e.g., `"theme"`)
|
|
342
|
+
* @param options - Optional playback configuration
|
|
343
|
+
*
|
|
344
|
+
* @example
|
|
345
|
+
* ```typescript
|
|
346
|
+
* // Simple playback (loops by default)
|
|
347
|
+
* await audio.bgm.play("my-mod:battle");
|
|
348
|
+
*
|
|
349
|
+
* // With options
|
|
350
|
+
* await audio.bgm.play("my-mod:intro", {
|
|
351
|
+
* loop: false,
|
|
352
|
+
* volume: 0.6,
|
|
353
|
+
* fadeIn: { durationSecs: 3.0, easing: "easeIn" }
|
|
354
|
+
* });
|
|
355
|
+
* ```
|
|
356
|
+
*/
|
|
357
|
+
function play(asset: string, options?: BgmPlayOptions): Promise<void>;
|
|
358
|
+
/**
|
|
359
|
+
* Stops the currently playing BGM.
|
|
360
|
+
*
|
|
361
|
+
* @param options - Optional stop configuration (e.g., fade-out)
|
|
362
|
+
*
|
|
363
|
+
* @example
|
|
364
|
+
* ```typescript
|
|
365
|
+
* // Immediate stop
|
|
366
|
+
* await audio.bgm.stop();
|
|
367
|
+
*
|
|
368
|
+
* // Fade out over 2 seconds
|
|
369
|
+
* await audio.bgm.stop({
|
|
370
|
+
* fadeOut: { durationSecs: 2.0, easing: "easeOut" }
|
|
371
|
+
* });
|
|
372
|
+
* ```
|
|
373
|
+
*/
|
|
374
|
+
function stop(options?: BgmStopOptions): Promise<void>;
|
|
375
|
+
/**
|
|
376
|
+
* Pauses the currently playing BGM.
|
|
377
|
+
*
|
|
378
|
+
* @example
|
|
379
|
+
* ```typescript
|
|
380
|
+
* await audio.bgm.pause();
|
|
381
|
+
* ```
|
|
382
|
+
*/
|
|
383
|
+
function pause(): Promise<void>;
|
|
384
|
+
/**
|
|
385
|
+
* Resumes paused BGM playback.
|
|
386
|
+
*
|
|
387
|
+
* @example
|
|
388
|
+
* ```typescript
|
|
389
|
+
* await audio.bgm.resume();
|
|
390
|
+
* ```
|
|
391
|
+
*/
|
|
392
|
+
function resume(): Promise<void>;
|
|
393
|
+
/**
|
|
394
|
+
* Updates playback parameters of the currently playing BGM.
|
|
395
|
+
*
|
|
396
|
+
* @param options - The parameters to update
|
|
397
|
+
*
|
|
398
|
+
* @example
|
|
399
|
+
* ```typescript
|
|
400
|
+
* // Fade volume to 0.3 over 1 second
|
|
401
|
+
* await audio.bgm.update({
|
|
402
|
+
* volume: 0.3,
|
|
403
|
+
* tween: { durationSecs: 1.0, easing: "easeInOut" }
|
|
404
|
+
* });
|
|
405
|
+
*
|
|
406
|
+
* // Change speed immediately
|
|
407
|
+
* await audio.bgm.update({ speed: 0.8 });
|
|
408
|
+
* ```
|
|
409
|
+
*/
|
|
410
|
+
function update(options: BgmUpdateOptions): Promise<void>;
|
|
411
|
+
/**
|
|
412
|
+
* Gets the current BGM playback status.
|
|
413
|
+
*
|
|
414
|
+
* @returns The current BGM status including asset, state, volume, and speed
|
|
415
|
+
*
|
|
416
|
+
* @example
|
|
417
|
+
* ```typescript
|
|
418
|
+
* const status = await audio.bgm.status();
|
|
419
|
+
* if (status.state === "playing") {
|
|
420
|
+
* console.log(`Now playing: ${status.asset} at volume ${status.volume}`);
|
|
421
|
+
* }
|
|
422
|
+
* ```
|
|
423
|
+
*/
|
|
424
|
+
function status(): Promise<BgmStatus>;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/** Request body for creating a stamp effect. */
|
|
429
|
+
interface StampRequestBody {
|
|
430
|
+
asset: string;
|
|
431
|
+
x?: number;
|
|
432
|
+
y?: number;
|
|
433
|
+
width?: number;
|
|
434
|
+
height?: number;
|
|
435
|
+
alpha?: number;
|
|
436
|
+
duration?: number;
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Effects API namespace for visual effects.
|
|
440
|
+
*
|
|
441
|
+
* Provides functionality to trigger visual stamp effects that enhance the user experience.
|
|
442
|
+
*
|
|
443
|
+
* For audio playback, see the {@link audio} namespace.
|
|
444
|
+
*
|
|
445
|
+
* @example
|
|
446
|
+
* ```typescript
|
|
447
|
+
* // Show a stamp effect
|
|
448
|
+
* await effects.stamp("heart-reaction", {
|
|
449
|
+
* width: 100,
|
|
450
|
+
* height: 100,
|
|
451
|
+
* duration: 2.0
|
|
452
|
+
* });
|
|
453
|
+
* ```
|
|
454
|
+
*/
|
|
455
|
+
declare namespace effects {
|
|
456
|
+
/**
|
|
457
|
+
* Configuration options for stamp visual effects.
|
|
458
|
+
*/
|
|
459
|
+
interface StampOptions {
|
|
460
|
+
/** X position on screen. */
|
|
461
|
+
x?: number;
|
|
462
|
+
/** Y position on screen. */
|
|
463
|
+
y?: number;
|
|
464
|
+
/** Width in pixels. */
|
|
465
|
+
width?: number;
|
|
466
|
+
/** Height in pixels. */
|
|
467
|
+
height?: number;
|
|
468
|
+
/** Opacity (0-1). */
|
|
469
|
+
alpha?: number;
|
|
470
|
+
/** Duration in seconds. */
|
|
471
|
+
duration?: number;
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Displays a visual stamp effect on the screen.
|
|
475
|
+
*
|
|
476
|
+
* @param asset - The asset ID of the stamp image.
|
|
477
|
+
* @param options - Optional configuration for the stamp appearance
|
|
478
|
+
*
|
|
479
|
+
* @example
|
|
480
|
+
* ```typescript
|
|
481
|
+
* await effects.stamp("thumbs-up");
|
|
482
|
+
*
|
|
483
|
+
* await effects.stamp("heart", {
|
|
484
|
+
* x: 100,
|
|
485
|
+
* y: 200,
|
|
486
|
+
* width: 80,
|
|
487
|
+
* height: 80,
|
|
488
|
+
* duration: 1.5
|
|
489
|
+
* });
|
|
490
|
+
* ```
|
|
491
|
+
*/
|
|
492
|
+
function stamp(asset: string, options?: StampOptions): Promise<void>;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Host API namespace for low-level HTTP communication with the Desktop Homunculus server.
|
|
497
|
+
*
|
|
498
|
+
* This module provides the foundational HTTP client functionality used internally
|
|
499
|
+
* by all other SDK modules. It handles the base URL configuration, URL construction,
|
|
500
|
+
* and HTTP methods with automatic error handling.
|
|
501
|
+
*
|
|
502
|
+
* **Note:** This module is primarily for internal SDK use. Most developers should
|
|
503
|
+
* use the higher-level namespaces like `vrm`, `signals`, etc.
|
|
504
|
+
*
|
|
505
|
+
* @example
|
|
506
|
+
* ```typescript
|
|
507
|
+
* // Internal SDK usage (you typically won't need this directly)
|
|
508
|
+
* const response = await host.get(host.createUrl("vrm"));
|
|
509
|
+
* const vrms = await response.json();
|
|
510
|
+
*
|
|
511
|
+
* // URL construction with parameters
|
|
512
|
+
* const url = host.createUrl("vrm", { name: "MyCharacter" });
|
|
513
|
+
* // Results in: http://localhost:3100/vrm?name=MyCharacter
|
|
514
|
+
*
|
|
515
|
+
* // Configure the base URL (e.g., from an MCP server)
|
|
516
|
+
* host.configure({ baseUrl: "http://localhost:4000" });
|
|
517
|
+
* ```
|
|
518
|
+
*/
|
|
519
|
+
/** Error thrown when the Homunculus HTTP API returns a non-OK response. */
|
|
520
|
+
declare class HomunculusApiError extends Error {
|
|
521
|
+
/** HTTP status code (e.g. 404, 500) */
|
|
522
|
+
readonly statusCode: number;
|
|
523
|
+
/** The request endpoint URL */
|
|
524
|
+
readonly endpoint: string;
|
|
525
|
+
/** The response body text */
|
|
526
|
+
readonly body: string;
|
|
527
|
+
constructor(statusCode: number, endpoint: string, body: string);
|
|
528
|
+
}
|
|
529
|
+
/** Error thrown when an NDJSON stream contains malformed data. */
|
|
530
|
+
declare class HomunculusStreamError extends Error {
|
|
531
|
+
/** The raw line that failed to parse */
|
|
532
|
+
readonly rawLine: string;
|
|
533
|
+
constructor(rawLine: string, cause?: unknown);
|
|
534
|
+
}
|
|
535
|
+
declare namespace host {
|
|
536
|
+
/**
|
|
537
|
+
* Configures the SDK's base URL for the Desktop Homunculus HTTP server.
|
|
538
|
+
*
|
|
539
|
+
* @param options - Configuration options
|
|
540
|
+
*
|
|
541
|
+
* @example
|
|
542
|
+
* ```typescript
|
|
543
|
+
* host.configure({ baseUrl: "http://localhost:4000" });
|
|
544
|
+
* ```
|
|
545
|
+
*/
|
|
546
|
+
function configure(options: {
|
|
547
|
+
baseUrl: string;
|
|
548
|
+
}): void;
|
|
549
|
+
/** Returns the base URL for the Desktop Homunculus HTTP server. */
|
|
550
|
+
function base(): string;
|
|
551
|
+
/** Creates a new URL instance pointing to the base server. */
|
|
552
|
+
function baseUrl(): URL;
|
|
553
|
+
/**
|
|
554
|
+
* Creates a URL for the Desktop Homunculus API with optional query parameters.
|
|
555
|
+
*
|
|
556
|
+
* @param path - The API endpoint path (relative to base URL)
|
|
557
|
+
* @param params - Optional query parameters to append to the URL
|
|
558
|
+
* @returns A URL instance ready for use in HTTP requests
|
|
559
|
+
*
|
|
560
|
+
* @example
|
|
561
|
+
* ```typescript
|
|
562
|
+
* // Simple path
|
|
563
|
+
* const url = host.createUrl("vrm");
|
|
564
|
+
* // Result: http://localhost:3100/vrm
|
|
565
|
+
*
|
|
566
|
+
* // With query parameters
|
|
567
|
+
* const url = host.createUrl("entities", { name: "VRM", root: 123 });
|
|
568
|
+
* // Result: http://localhost:3100/entities?name=VRM&root=123
|
|
569
|
+
* ```
|
|
570
|
+
*/
|
|
571
|
+
function createUrl(path: string, params?: object): URL;
|
|
572
|
+
/**
|
|
573
|
+
* Performs a GET request to the specified URL with automatic error handling.
|
|
574
|
+
*
|
|
575
|
+
* @param url - The URL to send the GET request to
|
|
576
|
+
* @returns The Response object if successful
|
|
577
|
+
* @throws {HomunculusApiError} If the response status is >= 400
|
|
578
|
+
*
|
|
579
|
+
* @example
|
|
580
|
+
* ```typescript
|
|
581
|
+
* const response = await host.get(host.createUrl("vrm"));
|
|
582
|
+
* const data = await response.json();
|
|
583
|
+
* ```
|
|
584
|
+
*/
|
|
585
|
+
function get(url: URL): Promise<Response>;
|
|
586
|
+
/**
|
|
587
|
+
* Performs a POST request with JSON payload and automatic error handling.
|
|
588
|
+
*
|
|
589
|
+
* @param url - The URL to send the POST request to
|
|
590
|
+
* @param body - Optional request body that will be JSON-serialized
|
|
591
|
+
* @returns The Response object if successful
|
|
592
|
+
* @throws {HomunculusApiError} If the response status is >= 400
|
|
593
|
+
*
|
|
594
|
+
* @example
|
|
595
|
+
* ```typescript
|
|
596
|
+
* const response = await host.post(
|
|
597
|
+
* host.createUrl("vrm"),
|
|
598
|
+
* { asset: "my-mod::character.vrm" }
|
|
599
|
+
* );
|
|
600
|
+
* ```
|
|
601
|
+
*/
|
|
602
|
+
function post<B>(url: URL, body?: B): Promise<Response>;
|
|
603
|
+
/**
|
|
604
|
+
* Performs a PUT request with JSON payload and automatic error handling.
|
|
605
|
+
*
|
|
606
|
+
* @param url - The URL to send the PUT request to
|
|
607
|
+
* @param body - Optional request body that will be JSON-serialized
|
|
608
|
+
* @returns The Response object if successful
|
|
609
|
+
* @throws {HomunculusApiError} If the response status is >= 400
|
|
610
|
+
*
|
|
611
|
+
* @example
|
|
612
|
+
* ```typescript
|
|
613
|
+
* await host.put(
|
|
614
|
+
* host.createUrl("vrm/123/state"),
|
|
615
|
+
* { state: "idle" }
|
|
616
|
+
* );
|
|
617
|
+
* ```
|
|
618
|
+
*/
|
|
619
|
+
function put<B>(url: URL, body?: B): Promise<Response>;
|
|
620
|
+
/**
|
|
621
|
+
* Performs a PATCH request with JSON payload and automatic error handling.
|
|
622
|
+
*
|
|
623
|
+
* @param url - The URL to send the PATCH request to
|
|
624
|
+
* @param body - Optional request body that will be JSON-serialized
|
|
625
|
+
* @returns The Response object if successful
|
|
626
|
+
* @throws {HomunculusApiError} If the response status is >= 400
|
|
627
|
+
*/
|
|
628
|
+
function patch<B>(url: URL, body?: B): Promise<Response>;
|
|
629
|
+
function deleteMethod(url: URL): Promise<Response>;
|
|
630
|
+
/**
|
|
631
|
+
* Performs a POST request and returns an async generator that yields
|
|
632
|
+
* parsed NDJSON objects from the streaming response.
|
|
633
|
+
*
|
|
634
|
+
* @param url - The URL to send the POST request to
|
|
635
|
+
* @param body - Optional request body that will be JSON-serialized
|
|
636
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
637
|
+
* @returns An async generator yielding parsed JSON objects of type T
|
|
638
|
+
* @throws {HomunculusApiError} If the response status is >= 400
|
|
639
|
+
* @throws {HomunculusStreamError} If an NDJSON line cannot be parsed
|
|
640
|
+
*
|
|
641
|
+
* @example
|
|
642
|
+
* ```typescript
|
|
643
|
+
* const stream = host.postStream<MyEvent>(
|
|
644
|
+
* host.createUrl("mods/my-mod/commands/execute"),
|
|
645
|
+
* { command: "build" }
|
|
646
|
+
* );
|
|
647
|
+
* for await (const event of stream) {
|
|
648
|
+
* console.log(event);
|
|
649
|
+
* }
|
|
650
|
+
* ```
|
|
651
|
+
*/
|
|
652
|
+
function postStream<T>(url: URL, body?: unknown, signal?: AbortSignal): AsyncGenerator<T>;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/**
|
|
656
|
+
* Preferences API namespace for persistent data storage and user settings.
|
|
657
|
+
*
|
|
658
|
+
* Provides a key-value store for saving and loading application data that persists
|
|
659
|
+
* across sessions.
|
|
660
|
+
*
|
|
661
|
+
* @example
|
|
662
|
+
* ```typescript
|
|
663
|
+
* await preferences.save('user-settings', { theme: 'dark', volume: 0.8 });
|
|
664
|
+
* const settings = await preferences.load<{ theme: string; volume: number }>('user-settings');
|
|
665
|
+
* ```
|
|
666
|
+
*/
|
|
667
|
+
declare namespace preferences {
|
|
668
|
+
/**
|
|
669
|
+
* List all saved preference keys.
|
|
670
|
+
*
|
|
671
|
+
* Returns an array of key names that have been stored.
|
|
672
|
+
* Use {@link preferences.load} to retrieve the value for a specific key.
|
|
673
|
+
*
|
|
674
|
+
* @returns Array of preference key names
|
|
675
|
+
*
|
|
676
|
+
* @example
|
|
677
|
+
* ```typescript
|
|
678
|
+
* const keys = await preferences.list();
|
|
679
|
+
* console.log(`${keys.length} preferences stored`);
|
|
680
|
+
*
|
|
681
|
+
* // Load all preferences
|
|
682
|
+
* for (const key of keys) {
|
|
683
|
+
* const value = await preferences.load(key);
|
|
684
|
+
* console.log(`${key}:`, value);
|
|
685
|
+
* }
|
|
686
|
+
* ```
|
|
687
|
+
*/
|
|
688
|
+
function list(): Promise<string[]>;
|
|
689
|
+
/**
|
|
690
|
+
* Loads a value from the preference store with type safety.
|
|
691
|
+
*
|
|
692
|
+
* Returns `undefined` if the key does not exist.
|
|
693
|
+
*
|
|
694
|
+
* @template V - The expected type of the stored value
|
|
695
|
+
* @param key - The unique identifier for the stored data
|
|
696
|
+
* @returns A promise that resolves to the deserialized value, or `undefined` if the key does not exist
|
|
697
|
+
*
|
|
698
|
+
* @example
|
|
699
|
+
* ```typescript
|
|
700
|
+
* const username = await preferences.load<string>('username');
|
|
701
|
+
* if (username !== null) {
|
|
702
|
+
* console.log(`Hello, ${username}`);
|
|
703
|
+
* }
|
|
704
|
+
* ```
|
|
705
|
+
*/
|
|
706
|
+
function load<V>(key: string): Promise<V | undefined>;
|
|
707
|
+
/**
|
|
708
|
+
* Saves a value to the preference store with automatic serialization.
|
|
709
|
+
*
|
|
710
|
+
* @template V - The type of the value being saved
|
|
711
|
+
* @param key - The unique identifier for storing the data
|
|
712
|
+
* @param value - The data to save (must be JSON-serializable)
|
|
713
|
+
*
|
|
714
|
+
* @example
|
|
715
|
+
* ```typescript
|
|
716
|
+
* await preferences.save('username', 'Alice');
|
|
717
|
+
* ```
|
|
718
|
+
*/
|
|
719
|
+
function save<V>(key: string, value: V): Promise<void>;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
/** Request body for setting frame rate. */
|
|
723
|
+
interface SetFpsBody {
|
|
724
|
+
fps: number;
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* Settings API namespace for controlling application-level configuration.
|
|
728
|
+
*
|
|
729
|
+
* @example
|
|
730
|
+
* ```typescript
|
|
731
|
+
* const currentFps = await settings.fps();
|
|
732
|
+
* await settings.setFps(30);
|
|
733
|
+
* ```
|
|
734
|
+
*/
|
|
735
|
+
declare namespace settings {
|
|
736
|
+
/**
|
|
737
|
+
* Gets the current frame rate (FPS).
|
|
738
|
+
*
|
|
739
|
+
* @returns A promise that resolves to the current FPS value
|
|
740
|
+
*
|
|
741
|
+
* @example
|
|
742
|
+
* ```typescript
|
|
743
|
+
* const fps = await settings.fps();
|
|
744
|
+
* console.log(`Current FPS: ${fps}`);
|
|
745
|
+
* ```
|
|
746
|
+
*/
|
|
747
|
+
function fps(): Promise<number>;
|
|
748
|
+
/**
|
|
749
|
+
* Sets the frame rate (FPS). Persists and applies immediately.
|
|
750
|
+
*
|
|
751
|
+
* @param fps - The target frame rate in frames per second (1-120)
|
|
752
|
+
*
|
|
753
|
+
* @example
|
|
754
|
+
* ```typescript
|
|
755
|
+
* await settings.setFps(30);
|
|
756
|
+
* ```
|
|
757
|
+
*/
|
|
758
|
+
function setFps(fps: number): Promise<void>;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
/** Request body for setting shadow panel alpha. */
|
|
762
|
+
interface ShadowPanelPutBody {
|
|
763
|
+
alpha: number;
|
|
764
|
+
}
|
|
765
|
+
/**
|
|
766
|
+
* Shadow Panel API namespace for controlling the application's shadow overlay.
|
|
767
|
+
*
|
|
768
|
+
* The shadow panel is a visual overlay that can be used to create atmospheric
|
|
769
|
+
* effects, focus attention, or provide visual feedback.
|
|
770
|
+
*
|
|
771
|
+
* @example
|
|
772
|
+
* ```typescript
|
|
773
|
+
* await shadowPanel.setAlpha(0.7);
|
|
774
|
+
* const currentAlpha = await shadowPanel.alpha();
|
|
775
|
+
* await shadowPanel.setAlpha(0);
|
|
776
|
+
* ```
|
|
777
|
+
*/
|
|
778
|
+
declare namespace shadowPanel {
|
|
779
|
+
/**
|
|
780
|
+
* Gets the current transparency level of the shadow panel.
|
|
781
|
+
*
|
|
782
|
+
* @returns A promise that resolves to the current alpha value (0-1)
|
|
783
|
+
*/
|
|
784
|
+
function alpha(): Promise<number>;
|
|
785
|
+
/**
|
|
786
|
+
* Sets the transparency level of the shadow panel.
|
|
787
|
+
*
|
|
788
|
+
* @param alpha - The transparency value between 0 (invisible) and 1 (opaque)
|
|
789
|
+
*
|
|
790
|
+
* @example
|
|
791
|
+
* ```typescript
|
|
792
|
+
* await shadowPanel.setAlpha(0.7);
|
|
793
|
+
* ```
|
|
794
|
+
*/
|
|
795
|
+
function setAlpha(alpha: number): Promise<void>;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
/**
|
|
799
|
+
* Big Five personality traits (OCEAN model).
|
|
800
|
+
*
|
|
801
|
+
* @example
|
|
802
|
+
* ```typescript
|
|
803
|
+
* const ocean: Ocean = {
|
|
804
|
+
* openness: 0.8,
|
|
805
|
+
* conscientiousness: 0.6,
|
|
806
|
+
* extraversion: 0.7,
|
|
807
|
+
* };
|
|
808
|
+
* ```
|
|
809
|
+
*/
|
|
810
|
+
interface Ocean {
|
|
811
|
+
/** Openness (0.0=conservative, 1.0=curious) */
|
|
812
|
+
openness?: number;
|
|
813
|
+
/** Conscientiousness (0.0=spontaneous, 1.0=organized) */
|
|
814
|
+
conscientiousness?: number;
|
|
815
|
+
/** Extraversion (0.0=introverted, 1.0=extroverted) */
|
|
816
|
+
extraversion?: number;
|
|
817
|
+
/** Agreeableness (0.0=independent, 1.0=cooperative) */
|
|
818
|
+
agreeableness?: number;
|
|
819
|
+
/** Neuroticism (0.0=stable, 1.0=sensitive) */
|
|
820
|
+
neuroticism?: number;
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* Persona data for a VRM character.
|
|
824
|
+
*
|
|
825
|
+
* @example
|
|
826
|
+
* ```typescript
|
|
827
|
+
* const persona: Persona = {
|
|
828
|
+
* profile: "A cheerful virtual assistant",
|
|
829
|
+
* personality: "Friendly and helpful",
|
|
830
|
+
* ocean: { openness: 0.8, extraversion: 0.7 },
|
|
831
|
+
* metadata: {},
|
|
832
|
+
* };
|
|
833
|
+
* ```
|
|
834
|
+
*/
|
|
835
|
+
interface Persona {
|
|
836
|
+
/** Character profile/background description. */
|
|
837
|
+
profile: string;
|
|
838
|
+
/** Personality description in natural language. */
|
|
839
|
+
personality?: string | null;
|
|
840
|
+
/** Big Five personality parameters. */
|
|
841
|
+
ocean: Ocean;
|
|
842
|
+
/** Extension metadata for MODs. */
|
|
843
|
+
metadata: Record<string, unknown>;
|
|
844
|
+
}
|
|
845
|
+
/** Response for VRM state queries. */
|
|
846
|
+
interface VrmStateResponse {
|
|
847
|
+
state: string;
|
|
848
|
+
}
|
|
849
|
+
/** Request body for setting VRM state. */
|
|
850
|
+
interface VrmStateRequest {
|
|
851
|
+
state: string;
|
|
852
|
+
}
|
|
853
|
+
/** Override type for expression override settings. */
|
|
854
|
+
type OverrideType = "none" | "blend" | "block";
|
|
855
|
+
/**
|
|
856
|
+
* Information about a single VRM expression.
|
|
857
|
+
*
|
|
858
|
+
* @example
|
|
859
|
+
* ```typescript
|
|
860
|
+
* const vrm = await Vrm.findByName("MyAvatar");
|
|
861
|
+
* const { expressions } = await vrm.expressions();
|
|
862
|
+
* for (const expr of expressions) {
|
|
863
|
+
* console.log(`${expr.name}: weight=${expr.weight}, binary=${expr.isBinary}`);
|
|
864
|
+
* }
|
|
865
|
+
* ```
|
|
866
|
+
*/
|
|
867
|
+
interface ExpressionInfo {
|
|
868
|
+
/** Expression name (e.g. "happy", "aa", "blink"). */
|
|
869
|
+
name: string;
|
|
870
|
+
/** Current weight value (0.0-1.0). */
|
|
871
|
+
weight: number;
|
|
872
|
+
/** Whether this expression is binary (snaps to 0 or 1). */
|
|
873
|
+
isBinary: boolean;
|
|
874
|
+
/** Override type for blink expressions. */
|
|
875
|
+
overrideBlink: OverrideType;
|
|
876
|
+
/** Override type for lookAt expressions. */
|
|
877
|
+
overrideLookAt: OverrideType;
|
|
878
|
+
/** Override type for mouth expressions. */
|
|
879
|
+
overrideMouth: OverrideType;
|
|
880
|
+
}
|
|
881
|
+
/** Response for VRM expression queries. */
|
|
882
|
+
interface ExpressionsResponse {
|
|
883
|
+
expressions: ExpressionInfo[];
|
|
884
|
+
}
|
|
885
|
+
/** Arguments for moving a VRM to a viewport position. */
|
|
886
|
+
interface MoveToArgs {
|
|
887
|
+
globalViewport: GlobalViewport;
|
|
888
|
+
}
|
|
889
|
+
/** Spring bone physics properties. */
|
|
890
|
+
interface SpringBoneProps {
|
|
891
|
+
stiffness: number;
|
|
892
|
+
dragForce: number;
|
|
893
|
+
gravityPower: number;
|
|
894
|
+
gravityDir: [number, number, number];
|
|
895
|
+
hitRadius: number;
|
|
896
|
+
}
|
|
897
|
+
/** A single spring bone chain. */
|
|
898
|
+
interface SpringBoneChain {
|
|
899
|
+
entity: number;
|
|
900
|
+
joints: string[];
|
|
901
|
+
props: SpringBoneProps;
|
|
902
|
+
}
|
|
903
|
+
/** Response for spring bone chains query. */
|
|
904
|
+
interface SpringBoneChainsResponse {
|
|
905
|
+
chains: SpringBoneChain[];
|
|
906
|
+
}
|
|
907
|
+
/** Repeat settings for VRMA playback. */
|
|
908
|
+
interface VrmaRepeat {
|
|
909
|
+
type: "forever" | "never" | "count";
|
|
910
|
+
count?: number;
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* Helper functions for building {@link VrmaRepeat} values.
|
|
914
|
+
*
|
|
915
|
+
* @example
|
|
916
|
+
* ```typescript
|
|
917
|
+
* await vrm.playVrma({
|
|
918
|
+
* asset: "vrma:idle-maid",
|
|
919
|
+
* repeat: repeat.forever(),
|
|
920
|
+
* });
|
|
921
|
+
*
|
|
922
|
+
* await vrm.playVrma({
|
|
923
|
+
* asset: "vrma:grabbed",
|
|
924
|
+
* repeat: repeat.count(3),
|
|
925
|
+
* });
|
|
926
|
+
* ```
|
|
927
|
+
*/
|
|
928
|
+
declare namespace repeat {
|
|
929
|
+
/**
|
|
930
|
+
* Repeat the animation forever.
|
|
931
|
+
*/
|
|
932
|
+
function forever(): VrmaRepeat;
|
|
933
|
+
/**
|
|
934
|
+
* Play the animation once (no repeat).
|
|
935
|
+
*/
|
|
936
|
+
function never(): VrmaRepeat;
|
|
937
|
+
/**
|
|
938
|
+
* Repeat the animation a fixed number of times.
|
|
939
|
+
*
|
|
940
|
+
* @param n Positive integer repeat count.
|
|
941
|
+
* @throws {RangeError} If `n` is not a positive integer.
|
|
942
|
+
*/
|
|
943
|
+
function count(n: number): VrmaRepeat;
|
|
944
|
+
}
|
|
945
|
+
/** Request body for playing a VRMA animation. */
|
|
946
|
+
interface VrmaPlayRequest {
|
|
947
|
+
asset: string;
|
|
948
|
+
transitionSecs?: number;
|
|
949
|
+
repeat?: VrmaRepeat;
|
|
950
|
+
waitForCompletion?: boolean;
|
|
951
|
+
/** If true, resets SpringBone velocities to prevent bouncing during animation transitions. */
|
|
952
|
+
resetSpringBones?: boolean;
|
|
953
|
+
}
|
|
954
|
+
/** State of a VRMA animation. */
|
|
955
|
+
interface VrmaState {
|
|
956
|
+
playing: boolean;
|
|
957
|
+
repeat: string;
|
|
958
|
+
speed: number;
|
|
959
|
+
elapsedSecs: number;
|
|
960
|
+
}
|
|
961
|
+
/** Info about a VRMA animation entity. */
|
|
962
|
+
interface VrmaInfo {
|
|
963
|
+
entity: number;
|
|
964
|
+
name: string;
|
|
965
|
+
playing: boolean;
|
|
966
|
+
}
|
|
967
|
+
/** Current look-at state of a VRM. */
|
|
968
|
+
type LookAtState = {
|
|
969
|
+
type: "cursor";
|
|
970
|
+
} | {
|
|
971
|
+
type: "target";
|
|
972
|
+
entity: number;
|
|
973
|
+
};
|
|
974
|
+
/**
|
|
975
|
+
* Snapshot of a VRM instance with full runtime state.
|
|
976
|
+
*
|
|
977
|
+
* @example
|
|
978
|
+
* ```typescript
|
|
979
|
+
* const snapshots = await Vrm.findAllDetailed();
|
|
980
|
+
* for (const s of snapshots) {
|
|
981
|
+
* console.log(`${s.name}: ${s.state} at (${s.globalViewport?.[0]}, ${s.globalViewport?.[1]})`);
|
|
982
|
+
* }
|
|
983
|
+
* ```
|
|
984
|
+
*/
|
|
985
|
+
interface VrmSnapshot {
|
|
986
|
+
entity: number;
|
|
987
|
+
name: string;
|
|
988
|
+
state: string;
|
|
989
|
+
transform: Transform;
|
|
990
|
+
globalViewport: GlobalViewport | null;
|
|
991
|
+
expressions: ExpressionsResponse;
|
|
992
|
+
animations: VrmaInfo[];
|
|
993
|
+
lookAt: LookAtState | null;
|
|
994
|
+
linkedWebviews: number[];
|
|
995
|
+
persona: Persona;
|
|
996
|
+
}
|
|
997
|
+
/**
|
|
998
|
+
* Response from the VRM position endpoint.
|
|
999
|
+
*
|
|
1000
|
+
* @example
|
|
1001
|
+
* ```ts
|
|
1002
|
+
* const vrm = await Vrm.findByName("MyCharacter");
|
|
1003
|
+
* const pos = await vrm.position();
|
|
1004
|
+
* console.log(`Screen: (${pos.globalViewport?.[0]}, ${pos.globalViewport?.[1]})`);
|
|
1005
|
+
* console.log(`World: (${pos.world[0]}, ${pos.world[1]}, ${pos.world[2]})`);
|
|
1006
|
+
* ```
|
|
1007
|
+
*/
|
|
1008
|
+
interface PositionResponse {
|
|
1009
|
+
/** Global screen coordinates (multi-monitor origin at leftmost screen). Null if not visible. */
|
|
1010
|
+
globalViewport: GlobalViewport | null;
|
|
1011
|
+
/** Bevy world coordinates. */
|
|
1012
|
+
world: Vec3;
|
|
1013
|
+
}
|
|
1014
|
+
/** Request body for setting VRMA playback speed. */
|
|
1015
|
+
interface VrmaSpeedBody {
|
|
1016
|
+
asset: string;
|
|
1017
|
+
speed: number;
|
|
1018
|
+
}
|
|
1019
|
+
interface SpawnVrmOptions {
|
|
1020
|
+
transform?: TransformArgs;
|
|
1021
|
+
persona?: Persona;
|
|
1022
|
+
}
|
|
1023
|
+
/**
|
|
1024
|
+
* A single keyframe in a speech timeline.
|
|
1025
|
+
*/
|
|
1026
|
+
interface TimelineKeyframe {
|
|
1027
|
+
/**
|
|
1028
|
+
* Duration of this keyframe in seconds.
|
|
1029
|
+
*/
|
|
1030
|
+
duration: number;
|
|
1031
|
+
/**
|
|
1032
|
+
* Expression targets to set during this keyframe.
|
|
1033
|
+
* Keys are expression names (e.g. "aa", "ih", "happy"), values are weights (0.0-1.0).
|
|
1034
|
+
*/
|
|
1035
|
+
targets?: Record<string, number>;
|
|
1036
|
+
}
|
|
1037
|
+
/**
|
|
1038
|
+
* Options for the timeline speech API.
|
|
1039
|
+
*/
|
|
1040
|
+
interface SpeakTimelineOptions {
|
|
1041
|
+
/**
|
|
1042
|
+
* If true, the method will wait for the speech to complete.
|
|
1043
|
+
* Defaults to true.
|
|
1044
|
+
*/
|
|
1045
|
+
waitForCompletion?: boolean;
|
|
1046
|
+
/**
|
|
1047
|
+
* Duration in seconds for smoothstep blending between adjacent keyframes.
|
|
1048
|
+
* Defaults to 0.05 (50ms). Clamped to 40% of each keyframe's duration.
|
|
1049
|
+
*/
|
|
1050
|
+
transitionDuration?: number;
|
|
1051
|
+
}
|
|
1052
|
+
interface VrmPointerEvent {
|
|
1053
|
+
/**
|
|
1054
|
+
* The cursor position in the global viewport.
|
|
1055
|
+
*/
|
|
1056
|
+
globalViewport: [number, number];
|
|
1057
|
+
}
|
|
1058
|
+
interface VrmDragEvent extends VrmPointerEvent {
|
|
1059
|
+
/**
|
|
1060
|
+
* The change in cursor position since the last event.
|
|
1061
|
+
*/
|
|
1062
|
+
delta: [number, number];
|
|
1063
|
+
}
|
|
1064
|
+
type Button = "Primary" | "Secondary" | "Middle";
|
|
1065
|
+
interface VrmMouseEvent extends VrmPointerEvent {
|
|
1066
|
+
/**
|
|
1067
|
+
* The button that was pressed or released.
|
|
1068
|
+
*/
|
|
1069
|
+
button: Button;
|
|
1070
|
+
}
|
|
1071
|
+
interface VrmStateChangeEvent {
|
|
1072
|
+
/**
|
|
1073
|
+
* The new state of the VRM.
|
|
1074
|
+
*/
|
|
1075
|
+
state: string;
|
|
1076
|
+
}
|
|
1077
|
+
interface PersonaChangeEvent {
|
|
1078
|
+
/**
|
|
1079
|
+
* The updated persona.
|
|
1080
|
+
*/
|
|
1081
|
+
persona: Persona;
|
|
1082
|
+
}
|
|
1083
|
+
type EventMap = {
|
|
1084
|
+
"drag-start": VrmPointerEvent;
|
|
1085
|
+
"drag": VrmDragEvent;
|
|
1086
|
+
"drag-end": VrmPointerEvent;
|
|
1087
|
+
"pointer-press": VrmMouseEvent;
|
|
1088
|
+
"pointer-click": VrmMouseEvent;
|
|
1089
|
+
"pointer-release": VrmMouseEvent;
|
|
1090
|
+
"pointer-over": VrmPointerEvent;
|
|
1091
|
+
"pointer-out": VrmPointerEvent;
|
|
1092
|
+
"pointer-cancel": VrmPointerEvent;
|
|
1093
|
+
"pointer-move": VrmPointerEvent;
|
|
1094
|
+
"state-change": VrmStateChangeEvent;
|
|
1095
|
+
"expression-change": VrmStateChangeEvent;
|
|
1096
|
+
"vrma-play": VrmStateChangeEvent;
|
|
1097
|
+
"vrma-finish": VrmStateChangeEvent;
|
|
1098
|
+
"persona-change": PersonaChangeEvent;
|
|
1099
|
+
};
|
|
1100
|
+
interface VrmMetadata {
|
|
1101
|
+
name: string;
|
|
1102
|
+
entity: number;
|
|
1103
|
+
}
|
|
1104
|
+
type Bones = "hips" | "spine" | "chest" | "neck" | "head" | "leftShoulder" | "leftArm" | "leftForeArm" | "leftHand" | "rightShoulder" | "rightArm" | "rightForeArm" | "rightHand" | "leftUpLeg" | "leftLeg" | "leftFoot" | "rightUpLeg" | "rightLeg" | "rightFoot";
|
|
1105
|
+
declare class VrmEventSource implements Disposable {
|
|
1106
|
+
readonly eventSource: EventSource;
|
|
1107
|
+
constructor(eventSource: EventSource);
|
|
1108
|
+
/**
|
|
1109
|
+
* Registers an event listener for the specified event type.
|
|
1110
|
+
*/
|
|
1111
|
+
on<K extends keyof EventMap>(event: K, callback: (event: EventMap[K]) => (void | Promise<void>)): void;
|
|
1112
|
+
/**
|
|
1113
|
+
* Closes the EventSource connection.
|
|
1114
|
+
*/
|
|
1115
|
+
close(): void;
|
|
1116
|
+
[Symbol.dispose](): void;
|
|
1117
|
+
}
|
|
1118
|
+
declare class Vrm {
|
|
1119
|
+
readonly entity: number;
|
|
1120
|
+
constructor(entity: number);
|
|
1121
|
+
/**
|
|
1122
|
+
* Returns an EventSource for receiving events related to this VRM entity.
|
|
1123
|
+
*/
|
|
1124
|
+
events(): VrmEventSource;
|
|
1125
|
+
/**
|
|
1126
|
+
* Returns the current state of the VRM.
|
|
1127
|
+
*/
|
|
1128
|
+
state(): Promise<string>;
|
|
1129
|
+
/**
|
|
1130
|
+
* Sets the state of the VRM.
|
|
1131
|
+
*
|
|
1132
|
+
* @param state The new state to set.
|
|
1133
|
+
*/
|
|
1134
|
+
setState(state: string): Promise<void>;
|
|
1135
|
+
/**
|
|
1136
|
+
* Returns the persona of the VRM.
|
|
1137
|
+
*
|
|
1138
|
+
* @example
|
|
1139
|
+
* ```typescript
|
|
1140
|
+
* const vrm = await Vrm.findByName("MyAvatar");
|
|
1141
|
+
* const persona = await vrm.persona();
|
|
1142
|
+
* console.log(persona.profile);
|
|
1143
|
+
* ```
|
|
1144
|
+
*/
|
|
1145
|
+
persona(): Promise<Persona>;
|
|
1146
|
+
/**
|
|
1147
|
+
* Sets the persona of the VRM.
|
|
1148
|
+
*
|
|
1149
|
+
* @param persona The persona data to set.
|
|
1150
|
+
*
|
|
1151
|
+
* @example
|
|
1152
|
+
* ```typescript
|
|
1153
|
+
* const vrm = await Vrm.findByName("MyAvatar");
|
|
1154
|
+
* await vrm.setPersona({
|
|
1155
|
+
* profile: "A cheerful assistant",
|
|
1156
|
+
* ocean: { openness: 0.8, extraversion: 0.7 },
|
|
1157
|
+
* metadata: {},
|
|
1158
|
+
* });
|
|
1159
|
+
* ```
|
|
1160
|
+
*/
|
|
1161
|
+
setPersona(persona: Persona): Promise<void>;
|
|
1162
|
+
/**
|
|
1163
|
+
* Returns the name of the VRM avatar.
|
|
1164
|
+
*/
|
|
1165
|
+
name(): Promise<string>;
|
|
1166
|
+
/**
|
|
1167
|
+
* Finds the entity ID of a bone by its name.
|
|
1168
|
+
*/
|
|
1169
|
+
findBoneEntity(bone: Bones): Promise<number>;
|
|
1170
|
+
/**
|
|
1171
|
+
* Despawns this VRM entity.
|
|
1172
|
+
*/
|
|
1173
|
+
despawn(): Promise<void>;
|
|
1174
|
+
/**
|
|
1175
|
+
* Gets the current position of this VRM in both screen and world coordinates.
|
|
1176
|
+
*
|
|
1177
|
+
* @example
|
|
1178
|
+
* ```ts
|
|
1179
|
+
* const vrm = await Vrm.findByName("MyCharacter");
|
|
1180
|
+
* const pos = await vrm.position();
|
|
1181
|
+
* console.log(`Screen: (${pos.globalViewport?.[0]}, ${pos.globalViewport?.[1]})`);
|
|
1182
|
+
* console.log(`World: (${pos.world[0]}, ${pos.world[1]}, ${pos.world[2]})`);
|
|
1183
|
+
* ```
|
|
1184
|
+
*/
|
|
1185
|
+
position(): Promise<PositionResponse>;
|
|
1186
|
+
/**
|
|
1187
|
+
* Gets all expressions and their current weights, including metadata
|
|
1188
|
+
* such as binary status and override settings.
|
|
1189
|
+
*
|
|
1190
|
+
* @example
|
|
1191
|
+
* ```typescript
|
|
1192
|
+
* const vrm = await Vrm.findByName("MyAvatar");
|
|
1193
|
+
* const { expressions } = await vrm.expressions();
|
|
1194
|
+
* for (const expr of expressions) {
|
|
1195
|
+
* console.log(`${expr.name}: ${expr.weight}`);
|
|
1196
|
+
* }
|
|
1197
|
+
* ```
|
|
1198
|
+
*/
|
|
1199
|
+
expressions(): Promise<ExpressionsResponse>;
|
|
1200
|
+
/**
|
|
1201
|
+
* Sets expression weights, replacing all previous overrides.
|
|
1202
|
+
* Expressions not included will return to VRMA animation control.
|
|
1203
|
+
*
|
|
1204
|
+
* @param weights A record of expression names to weight values (0.0-1.0).
|
|
1205
|
+
*
|
|
1206
|
+
* @example
|
|
1207
|
+
* ```typescript
|
|
1208
|
+
* const vrm = await Vrm.findByName("MyAvatar");
|
|
1209
|
+
* await vrm.setExpressions({ happy: 1.0, blink: 0.5 });
|
|
1210
|
+
* ```
|
|
1211
|
+
*/
|
|
1212
|
+
setExpressions(weights: Record<string, number>): Promise<void>;
|
|
1213
|
+
/**
|
|
1214
|
+
* Modifies specific expression weights without affecting others (partial update).
|
|
1215
|
+
* Existing overrides not mentioned remain unchanged.
|
|
1216
|
+
*
|
|
1217
|
+
* @param weights A record of expression names to weight values (0.0-1.0).
|
|
1218
|
+
*
|
|
1219
|
+
* @example
|
|
1220
|
+
* ```typescript
|
|
1221
|
+
* const vrm = await Vrm.findByName("MyAvatar");
|
|
1222
|
+
* // Only modifies "happy", leaves other overrides intact
|
|
1223
|
+
* await vrm.modifyExpressions({ happy: 1.0 });
|
|
1224
|
+
* ```
|
|
1225
|
+
*/
|
|
1226
|
+
modifyExpressions(weights: Record<string, number>): Promise<void>;
|
|
1227
|
+
/**
|
|
1228
|
+
* Clears all expression overrides, returning control to VRMA animation.
|
|
1229
|
+
*
|
|
1230
|
+
* @example
|
|
1231
|
+
* ```typescript
|
|
1232
|
+
* const vrm = await Vrm.findByName("MyAvatar");
|
|
1233
|
+
* await vrm.clearExpressions();
|
|
1234
|
+
* ```
|
|
1235
|
+
*/
|
|
1236
|
+
clearExpressions(): Promise<void>;
|
|
1237
|
+
/**
|
|
1238
|
+
* Modifies mouth expression weights for lip-sync.
|
|
1239
|
+
* Unspecified mouth expressions are reset to 0.0.
|
|
1240
|
+
* Non-mouth expression overrides are preserved.
|
|
1241
|
+
*
|
|
1242
|
+
* @param weights A record of mouth expression names to weight values (0.0-1.0).
|
|
1243
|
+
*
|
|
1244
|
+
* @example
|
|
1245
|
+
* ```typescript
|
|
1246
|
+
* const vrm = await Vrm.findByName("MyAvatar");
|
|
1247
|
+
* await vrm.modifyMouth({ aa: 0.8, oh: 0.2 });
|
|
1248
|
+
* ```
|
|
1249
|
+
*/
|
|
1250
|
+
modifyMouth(weights: Record<string, number>): Promise<void>;
|
|
1251
|
+
/**
|
|
1252
|
+
* Gets all spring bone chains.
|
|
1253
|
+
*/
|
|
1254
|
+
springBones(): Promise<SpringBoneChainsResponse>;
|
|
1255
|
+
/**
|
|
1256
|
+
* Gets a single spring bone chain by entity ID.
|
|
1257
|
+
*
|
|
1258
|
+
* @param chainId The chain entity ID.
|
|
1259
|
+
*/
|
|
1260
|
+
springBone(chainId: number): Promise<SpringBoneChain>;
|
|
1261
|
+
/**
|
|
1262
|
+
* Updates spring bone properties for a chain.
|
|
1263
|
+
*
|
|
1264
|
+
* @param chainId The chain entity ID.
|
|
1265
|
+
* @param props Partial properties to update.
|
|
1266
|
+
*/
|
|
1267
|
+
setSpringBone(chainId: number, props: Partial<SpringBoneProps>): Promise<void>;
|
|
1268
|
+
/**
|
|
1269
|
+
* Gets all VRMA animations for this VRM.
|
|
1270
|
+
*/
|
|
1271
|
+
listVrma(): Promise<VrmaInfo[]>;
|
|
1272
|
+
/**
|
|
1273
|
+
* Plays a VRMA animation.
|
|
1274
|
+
*
|
|
1275
|
+
* @param options Play request options including asset, repeat, transition.
|
|
1276
|
+
*/
|
|
1277
|
+
playVrma(options: VrmaPlayRequest): Promise<void>;
|
|
1278
|
+
/**
|
|
1279
|
+
* Stops a VRMA animation.
|
|
1280
|
+
*
|
|
1281
|
+
* @param asset The asset ID of the VRMA animation to stop.
|
|
1282
|
+
*/
|
|
1283
|
+
stopVrma(asset: string): Promise<void>;
|
|
1284
|
+
/**
|
|
1285
|
+
* Gets the state of a VRMA animation.
|
|
1286
|
+
*
|
|
1287
|
+
* @param asset The asset ID of the VRMA animation to query.
|
|
1288
|
+
*/
|
|
1289
|
+
vrmaState(asset: string): Promise<VrmaState>;
|
|
1290
|
+
/**
|
|
1291
|
+
* Sets the playback speed of a VRMA animation.
|
|
1292
|
+
*
|
|
1293
|
+
* @param asset The asset ID of the VRMA animation.
|
|
1294
|
+
* @param speed The playback speed.
|
|
1295
|
+
*/
|
|
1296
|
+
setVrmaSpeed(asset: string, speed: number): Promise<void>;
|
|
1297
|
+
/**
|
|
1298
|
+
* Speaks using pre-generated audio with a timeline of expression keyframes.
|
|
1299
|
+
* This allows any TTS engine to be used — the engine receives WAV audio and
|
|
1300
|
+
* frame-synchronized lip-sync data.
|
|
1301
|
+
*
|
|
1302
|
+
* @param audio - WAV audio data as ArrayBuffer or Uint8Array.
|
|
1303
|
+
* @param keyframes - Timeline keyframes specifying expression targets and durations.
|
|
1304
|
+
* @param options - Optional settings (e.g. waitForCompletion).
|
|
1305
|
+
*
|
|
1306
|
+
* @example
|
|
1307
|
+
* ```typescript
|
|
1308
|
+
* const vrm = await Vrm.findByName("MyAvatar");
|
|
1309
|
+
* const wavData = await fetchWavFromTTS("Hello world");
|
|
1310
|
+
* await vrm.speakWithTimeline(wavData, [
|
|
1311
|
+
* { duration: 0.1, targets: { aa: 1.0 } },
|
|
1312
|
+
* { duration: 0.05 },
|
|
1313
|
+
* { duration: 0.12, targets: { oh: 1.0, happy: 0.5 } },
|
|
1314
|
+
* ]);
|
|
1315
|
+
* ```
|
|
1316
|
+
*/
|
|
1317
|
+
speakWithTimeline(audio: ArrayBuffer | Uint8Array, keyframes: TimelineKeyframe[], options?: SpeakTimelineOptions): Promise<void>;
|
|
1318
|
+
/**
|
|
1319
|
+
* Looks at the mouse cursor.
|
|
1320
|
+
*/
|
|
1321
|
+
lookAtCursor(): Promise<void>;
|
|
1322
|
+
/**
|
|
1323
|
+
* Sets the VRM's look-at target to a specific entity.
|
|
1324
|
+
*
|
|
1325
|
+
* @param target The entity ID to look at.
|
|
1326
|
+
*/
|
|
1327
|
+
lookAtTarget(target: number): Promise<void>;
|
|
1328
|
+
/**
|
|
1329
|
+
* Disables the VRM's look-at functionality.
|
|
1330
|
+
*/
|
|
1331
|
+
unlook(): Promise<void>;
|
|
1332
|
+
/**
|
|
1333
|
+
* Spawns a new VRM instance from the given mod asset ID.
|
|
1334
|
+
*/
|
|
1335
|
+
static spawn(asset: string, options?: SpawnVrmOptions): Promise<Vrm>;
|
|
1336
|
+
/**
|
|
1337
|
+
* Finds a VRM instance by its name.
|
|
1338
|
+
*
|
|
1339
|
+
* @param vrmName VRM avatar name
|
|
1340
|
+
*/
|
|
1341
|
+
static findByName(vrmName: string): Promise<Vrm>;
|
|
1342
|
+
/**
|
|
1343
|
+
* Waits for a VRM instance to be spawned and initialized by its name.
|
|
1344
|
+
*
|
|
1345
|
+
* @param vrmName VRM avatar name
|
|
1346
|
+
*/
|
|
1347
|
+
static waitLoadByName(vrmName: string): Promise<Vrm>;
|
|
1348
|
+
/**
|
|
1349
|
+
* Returns entity IDs of all currently loaded VRM instances.
|
|
1350
|
+
*
|
|
1351
|
+
* @example
|
|
1352
|
+
* ```typescript
|
|
1353
|
+
* const entities = await Vrm.findAllEntities();
|
|
1354
|
+
* console.log(`Found ${entities.length} VRM entities`);
|
|
1355
|
+
* ```
|
|
1356
|
+
*/
|
|
1357
|
+
static findAllEntities(): Promise<number[]>;
|
|
1358
|
+
/**
|
|
1359
|
+
* Returns detailed snapshot of all VRM instances.
|
|
1360
|
+
*
|
|
1361
|
+
* @example
|
|
1362
|
+
* ```typescript
|
|
1363
|
+
* const snapshots = await Vrm.findAllDetailed();
|
|
1364
|
+
* for (const s of snapshots) {
|
|
1365
|
+
* console.log(`${s.name}: ${s.state} at (${s.globalViewport?.[0]}, ${s.globalViewport?.[1]})`);
|
|
1366
|
+
* }
|
|
1367
|
+
* ```
|
|
1368
|
+
*/
|
|
1369
|
+
static findAllDetailed(): Promise<VrmSnapshot[]>;
|
|
1370
|
+
static streamMetadata(f: (vrm: VrmMetadata) => (void | Promise<void>)): EventSource;
|
|
1371
|
+
/**
|
|
1372
|
+
* Streams all currently existing VRM instances and any VRM instances that will be created in the future.
|
|
1373
|
+
* @param f
|
|
1374
|
+
*/
|
|
1375
|
+
static stream(f: (vrm: Vrm) => (void | Promise<void>)): EventSource;
|
|
1376
|
+
/**
|
|
1377
|
+
* Returns all VRM instances that are currently loaded.
|
|
1378
|
+
*/
|
|
1379
|
+
static findAll(): Promise<Vrm[]>;
|
|
1380
|
+
private fetch;
|
|
1381
|
+
private post;
|
|
1382
|
+
private put;
|
|
1383
|
+
private patch;
|
|
1384
|
+
private delete;
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
/**
|
|
1388
|
+
* Speech utilities for converting phoneme data to Timeline keyframes.
|
|
1389
|
+
*
|
|
1390
|
+
* @example
|
|
1391
|
+
* ```typescript
|
|
1392
|
+
* import { speech, Vrm } from "@hmcs/sdk";
|
|
1393
|
+
*
|
|
1394
|
+
* const keyframes = speech.fromPhonemes([
|
|
1395
|
+
* ["aa", 0.1],
|
|
1396
|
+
* [null, 0.05],
|
|
1397
|
+
* ["oh", 0.12],
|
|
1398
|
+
* ]);
|
|
1399
|
+
* const vrm = await Vrm.findByName("MyAvatar");
|
|
1400
|
+
* await vrm.speakWithTimeline(wavData, keyframes);
|
|
1401
|
+
* ```
|
|
1402
|
+
*/
|
|
1403
|
+
declare namespace speech {
|
|
1404
|
+
/**
|
|
1405
|
+
* Creates timeline keyframes from a simple phoneme list.
|
|
1406
|
+
*
|
|
1407
|
+
* Each entry is a tuple of [expression_name | null, duration_seconds].
|
|
1408
|
+
* A null expression name creates a silent keyframe.
|
|
1409
|
+
*
|
|
1410
|
+
* @param phonemes - Array of [expression_name, duration] tuples.
|
|
1411
|
+
* @returns An array of timeline keyframes.
|
|
1412
|
+
*
|
|
1413
|
+
* @example
|
|
1414
|
+
* ```typescript
|
|
1415
|
+
* const keyframes = speech.fromPhonemes([
|
|
1416
|
+
* ["aa", 0.1],
|
|
1417
|
+
* [null, 0.05],
|
|
1418
|
+
* ["oh", 0.12],
|
|
1419
|
+
* ]);
|
|
1420
|
+
* ```
|
|
1421
|
+
*/
|
|
1422
|
+
function fromPhonemes(phonemes: Array<[string | null, number]>): TimelineKeyframe[];
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
/**
|
|
1426
|
+
* Represets a local webview source.
|
|
1427
|
+
*/
|
|
1428
|
+
interface WebviewSourceLocal {
|
|
1429
|
+
type: "local";
|
|
1430
|
+
id: string;
|
|
1431
|
+
}
|
|
1432
|
+
/**
|
|
1433
|
+
* Represents a inline-html webview source.
|
|
1434
|
+
*/
|
|
1435
|
+
interface WebviewSourceHtml {
|
|
1436
|
+
type: "html";
|
|
1437
|
+
content: string;
|
|
1438
|
+
}
|
|
1439
|
+
/**
|
|
1440
|
+
* Represents a remott webview source.
|
|
1441
|
+
*/
|
|
1442
|
+
interface WebviewSourceUrl {
|
|
1443
|
+
type: "url";
|
|
1444
|
+
url: string;
|
|
1445
|
+
}
|
|
1446
|
+
/**
|
|
1447
|
+
* Webview source specification (request): URL/path, inline HTML, or local asset ID.
|
|
1448
|
+
*
|
|
1449
|
+
* @example
|
|
1450
|
+
* ```typescript
|
|
1451
|
+
* // URL or mod asset path
|
|
1452
|
+
* const urlSource: WebviewSource = webviewSource.url("my-mod::ui.html");
|
|
1453
|
+
* // Inline HTML content
|
|
1454
|
+
* const htmlSource: WebviewSource = webviewSource.html("<h1>Hello</h1>");
|
|
1455
|
+
* // Local asset by ID
|
|
1456
|
+
* const localSource: WebviewSource = webviewSource.local("my-mod::panel.html");
|
|
1457
|
+
* ```
|
|
1458
|
+
*/
|
|
1459
|
+
type WebviewSource = WebviewSourceUrl | WebviewSourceHtml | WebviewSourceLocal;
|
|
1460
|
+
/**
|
|
1461
|
+
* Returns whether webview source is local.
|
|
1462
|
+
*/
|
|
1463
|
+
declare function isWebviewSourceLocal(source: WebviewSource): source is WebviewSourceLocal;
|
|
1464
|
+
/**
|
|
1465
|
+
* Returns whether webview source is url.
|
|
1466
|
+
*/
|
|
1467
|
+
declare function isWebviewSourceUrl(source: WebviewSource): source is WebviewSourceUrl;
|
|
1468
|
+
/**
|
|
1469
|
+
* Returns whether webview source is inline-html.
|
|
1470
|
+
*/
|
|
1471
|
+
declare function isWebviewSourceHtml(source: WebviewSource): source is WebviewSourceHtml;
|
|
1472
|
+
/**
|
|
1473
|
+
* Factory functions for creating {@link WebviewSource} objects.
|
|
1474
|
+
*
|
|
1475
|
+
* @example
|
|
1476
|
+
* ```typescript
|
|
1477
|
+
* import { Webview, webviewSource } from "@hmcs/sdk";
|
|
1478
|
+
*
|
|
1479
|
+
* await Webview.open({ source: webviewSource.local("menu:ui") });
|
|
1480
|
+
* await Webview.open({ source: webviewSource.url("https://example.com") });
|
|
1481
|
+
* await wv.navigate(webviewSource.html("<h1>Hello</h1>"));
|
|
1482
|
+
* ```
|
|
1483
|
+
*/
|
|
1484
|
+
declare namespace webviewSource {
|
|
1485
|
+
/**
|
|
1486
|
+
* Create a local asset source.
|
|
1487
|
+
*
|
|
1488
|
+
* @param id - Asset ID (e.g., `"menu:ui"`, `"settings:ui"`)
|
|
1489
|
+
*
|
|
1490
|
+
* @example
|
|
1491
|
+
* ```typescript
|
|
1492
|
+
* const source = webviewSource.local("menu:ui");
|
|
1493
|
+
* // { type: "local", id: "menu:ui" }
|
|
1494
|
+
* ```
|
|
1495
|
+
*/
|
|
1496
|
+
function local(id: string): WebviewSourceLocal;
|
|
1497
|
+
/**
|
|
1498
|
+
* Create a URL source.
|
|
1499
|
+
*
|
|
1500
|
+
* @param url - URL string
|
|
1501
|
+
*
|
|
1502
|
+
* @example
|
|
1503
|
+
* ```typescript
|
|
1504
|
+
* const source = webviewSource.url("https://example.com");
|
|
1505
|
+
* // { type: "url", url: "https://example.com" }
|
|
1506
|
+
* ```
|
|
1507
|
+
*/
|
|
1508
|
+
function url(url: string): WebviewSourceUrl;
|
|
1509
|
+
/**
|
|
1510
|
+
* Create an inline HTML source.
|
|
1511
|
+
*
|
|
1512
|
+
* @param content - HTML string
|
|
1513
|
+
*
|
|
1514
|
+
* @example
|
|
1515
|
+
* ```typescript
|
|
1516
|
+
* const source = webviewSource.html("<h1>Hello</h1>");
|
|
1517
|
+
* // { type: "html", content: "<h1>Hello</h1>" }
|
|
1518
|
+
* ```
|
|
1519
|
+
*/
|
|
1520
|
+
function html(content: string): WebviewSourceHtml;
|
|
1521
|
+
}
|
|
1522
|
+
/**
|
|
1523
|
+
* Represents a url webview source info
|
|
1524
|
+
*/
|
|
1525
|
+
interface WebviewSourceInfoUrl {
|
|
1526
|
+
type: "url";
|
|
1527
|
+
url: string;
|
|
1528
|
+
}
|
|
1529
|
+
/**
|
|
1530
|
+
* Represents a local webview source info.
|
|
1531
|
+
*/
|
|
1532
|
+
interface WebviewSourceInfoLocal {
|
|
1533
|
+
type: "local";
|
|
1534
|
+
id: string;
|
|
1535
|
+
}
|
|
1536
|
+
/**
|
|
1537
|
+
* Repsents a inline-html source info.
|
|
1538
|
+
*/
|
|
1539
|
+
interface WebviewSourceInfoHtml {
|
|
1540
|
+
type: "html";
|
|
1541
|
+
content?: string;
|
|
1542
|
+
}
|
|
1543
|
+
/**
|
|
1544
|
+
* Webview source information (response).
|
|
1545
|
+
* In list responses, Html content is omitted.
|
|
1546
|
+
* In detail responses, Html content is included.
|
|
1547
|
+
*/
|
|
1548
|
+
type WebviewSourceInfo = WebviewSourceInfoHtml | WebviewSourceInfoLocal | WebviewSourceInfoUrl;
|
|
1549
|
+
declare function isWebviewSourceInfoLocal(source: WebviewSourceInfo): source is WebviewSourceInfoLocal;
|
|
1550
|
+
declare function isWebviewSourceInfoUrl(source: WebviewSourceInfo): source is WebviewSourceInfoUrl;
|
|
1551
|
+
declare function isWebviewSourceInfoHtml(source: WebviewSourceInfoHtml): source is WebviewSourceInfoHtml;
|
|
1552
|
+
/** Information about a webview instance. */
|
|
1553
|
+
interface WebviewInfo {
|
|
1554
|
+
entity: number;
|
|
1555
|
+
source: WebviewSourceInfo;
|
|
1556
|
+
size: Vec2;
|
|
1557
|
+
viewportSize: Vec2;
|
|
1558
|
+
offset: Vec2;
|
|
1559
|
+
linkedVrm?: number | null;
|
|
1560
|
+
}
|
|
1561
|
+
/**
|
|
1562
|
+
* Options for opening a webview.
|
|
1563
|
+
*
|
|
1564
|
+
* @example
|
|
1565
|
+
* ```typescript
|
|
1566
|
+
* const options: WebviewOpenOptions = {
|
|
1567
|
+
* source: webviewSource.url("my-mod::ui.html"),
|
|
1568
|
+
* size: [0.7, 0.7],
|
|
1569
|
+
* viewportSize: [800, 600],
|
|
1570
|
+
* offset: [0, 0.5],
|
|
1571
|
+
* };
|
|
1572
|
+
* ```
|
|
1573
|
+
*/
|
|
1574
|
+
interface WebviewOpenOptions {
|
|
1575
|
+
source: WebviewSource;
|
|
1576
|
+
size?: Vec2;
|
|
1577
|
+
viewportSize?: Vec2;
|
|
1578
|
+
offset?: Vec2;
|
|
1579
|
+
linkedVrm?: number;
|
|
1580
|
+
}
|
|
1581
|
+
/** Request body for patching webview properties. */
|
|
1582
|
+
interface WebviewPatchRequest {
|
|
1583
|
+
offset?: Vec2;
|
|
1584
|
+
size?: Vec2;
|
|
1585
|
+
viewportSize?: Vec2;
|
|
1586
|
+
}
|
|
1587
|
+
/** Request body for navigating a webview to a new source. */
|
|
1588
|
+
interface WebviewNavigateRequest {
|
|
1589
|
+
source: WebviewSource;
|
|
1590
|
+
}
|
|
1591
|
+
/** Request body for setting a webview's linked VRM. */
|
|
1592
|
+
interface SetLinkedVrmRequest {
|
|
1593
|
+
vrm: number;
|
|
1594
|
+
}
|
|
1595
|
+
/**
|
|
1596
|
+
* Webview management for creating and controlling embedded web interfaces.
|
|
1597
|
+
*
|
|
1598
|
+
* Desktop Homunculus uses webviews to provide rich UI experiences that can be
|
|
1599
|
+
* positioned anywhere in 3D space or attached to VRM characters.
|
|
1600
|
+
*
|
|
1601
|
+
* @example
|
|
1602
|
+
* ```typescript
|
|
1603
|
+
* const webview = await Webview.open({
|
|
1604
|
+
* source: webviewSource.url("my-mod::ui.html"),
|
|
1605
|
+
* size: [0.7, 0.7],
|
|
1606
|
+
* viewportSize: [800, 600],
|
|
1607
|
+
* offset: [0, 0.5],
|
|
1608
|
+
* });
|
|
1609
|
+
*
|
|
1610
|
+
* if (!(await webview.isClosed())) {
|
|
1611
|
+
* await webview.close();
|
|
1612
|
+
* }
|
|
1613
|
+
* ```
|
|
1614
|
+
*/
|
|
1615
|
+
/**
|
|
1616
|
+
* Represents a webview instance that can display HTML content in 3D space.
|
|
1617
|
+
*/
|
|
1618
|
+
declare class Webview {
|
|
1619
|
+
readonly entity: number;
|
|
1620
|
+
constructor(entity: number);
|
|
1621
|
+
/**
|
|
1622
|
+
* Closes the webview.
|
|
1623
|
+
*/
|
|
1624
|
+
close(): Promise<void>;
|
|
1625
|
+
/**
|
|
1626
|
+
* Checks whether this webview has been closed.
|
|
1627
|
+
*
|
|
1628
|
+
* @returns A promise that resolves to true if the webview is closed
|
|
1629
|
+
*/
|
|
1630
|
+
isClosed(): Promise<boolean>;
|
|
1631
|
+
/**
|
|
1632
|
+
* Gets information about this webview.
|
|
1633
|
+
*
|
|
1634
|
+
* @returns A promise that resolves to the webview info
|
|
1635
|
+
*/
|
|
1636
|
+
info(): Promise<WebviewInfo>;
|
|
1637
|
+
/**
|
|
1638
|
+
* Patches webview properties (offset, size, viewportSize).
|
|
1639
|
+
*
|
|
1640
|
+
* @param options - The properties to update
|
|
1641
|
+
*/
|
|
1642
|
+
patch(options: WebviewPatchRequest): Promise<void>;
|
|
1643
|
+
/**
|
|
1644
|
+
* Sets the offset of the webview.
|
|
1645
|
+
*
|
|
1646
|
+
* @param offset - The new offset
|
|
1647
|
+
*/
|
|
1648
|
+
setOffset(offset: Vec2): Promise<void>;
|
|
1649
|
+
/**
|
|
1650
|
+
* Sets the size of the webview.
|
|
1651
|
+
*
|
|
1652
|
+
* @param size - The new size
|
|
1653
|
+
*/
|
|
1654
|
+
setSize(size: Vec2): Promise<void>;
|
|
1655
|
+
/**
|
|
1656
|
+
* Sets the viewport size of the webview.
|
|
1657
|
+
*
|
|
1658
|
+
* @param size - The new viewport size
|
|
1659
|
+
*/
|
|
1660
|
+
setViewportSize(size: Vec2): Promise<void>;
|
|
1661
|
+
/**
|
|
1662
|
+
* Navigates the webview to a new source.
|
|
1663
|
+
*
|
|
1664
|
+
* @param source - The new source (URL/path, inline HTML, or local asset ID)
|
|
1665
|
+
*
|
|
1666
|
+
* @example
|
|
1667
|
+
* ```typescript
|
|
1668
|
+
* const wv = new Webview(entity);
|
|
1669
|
+
* // Navigate to a mod asset
|
|
1670
|
+
* await wv.navigate(webviewSource.url("my-mod::page.html"));
|
|
1671
|
+
* // Navigate to inline HTML
|
|
1672
|
+
* await wv.navigate(webviewSource.html("<h1>Hello</h1>"));
|
|
1673
|
+
* // Navigate to a local asset by ID
|
|
1674
|
+
* await wv.navigate(webviewSource.local("my-mod::panel.html"));
|
|
1675
|
+
* ```
|
|
1676
|
+
*/
|
|
1677
|
+
navigate(source: WebviewSource): Promise<void>;
|
|
1678
|
+
/**
|
|
1679
|
+
* Reloads the webview content.
|
|
1680
|
+
*/
|
|
1681
|
+
reload(): Promise<void>;
|
|
1682
|
+
/**
|
|
1683
|
+
* Navigates the webview back in history.
|
|
1684
|
+
*
|
|
1685
|
+
* @example
|
|
1686
|
+
* ```typescript
|
|
1687
|
+
* const wv = (await Webview.list())[0];
|
|
1688
|
+
* await new Webview(wv.entity).navigateBack();
|
|
1689
|
+
* ```
|
|
1690
|
+
*/
|
|
1691
|
+
navigateBack(): Promise<void>;
|
|
1692
|
+
/**
|
|
1693
|
+
* Navigates the webview forward in history.
|
|
1694
|
+
*
|
|
1695
|
+
* @example
|
|
1696
|
+
* ```typescript
|
|
1697
|
+
* const wv = (await Webview.list())[0];
|
|
1698
|
+
* await new Webview(wv.entity).navigateForward();
|
|
1699
|
+
* ```
|
|
1700
|
+
*/
|
|
1701
|
+
navigateForward(): Promise<void>;
|
|
1702
|
+
/**
|
|
1703
|
+
* Gets the VRM linked to this webview.
|
|
1704
|
+
*
|
|
1705
|
+
* @returns The linked VRM instance, or undefined if no VRM is linked
|
|
1706
|
+
*/
|
|
1707
|
+
linkedVrm(): Promise<Vrm | undefined>;
|
|
1708
|
+
/**
|
|
1709
|
+
* Links this webview to a VRM entity.
|
|
1710
|
+
*
|
|
1711
|
+
* @param vrm - The VRM to link to this webview
|
|
1712
|
+
*/
|
|
1713
|
+
setLinkedVrm(vrm: Vrm): Promise<void>;
|
|
1714
|
+
/**
|
|
1715
|
+
* Removes the VRM link from this webview.
|
|
1716
|
+
*/
|
|
1717
|
+
unlinkVrm(): Promise<void>;
|
|
1718
|
+
/**
|
|
1719
|
+
* Gets all open webviews.
|
|
1720
|
+
*
|
|
1721
|
+
* @returns A promise that resolves to an array of webview info
|
|
1722
|
+
*/
|
|
1723
|
+
static list(): Promise<WebviewInfo[]>;
|
|
1724
|
+
/**
|
|
1725
|
+
* Creates and opens a webview positioned in world space.
|
|
1726
|
+
*
|
|
1727
|
+
* @param options - Configuration for the webview
|
|
1728
|
+
* @returns A promise that resolves to a new Webview instance
|
|
1729
|
+
*
|
|
1730
|
+
* @example
|
|
1731
|
+
* ```typescript
|
|
1732
|
+
* // Open with a mod asset URL
|
|
1733
|
+
* const panel = await Webview.open({
|
|
1734
|
+
* source: webviewSource.url("my-mod::settings.html"),
|
|
1735
|
+
* size: [0.7, 0.5],
|
|
1736
|
+
* viewportSize: [800, 600],
|
|
1737
|
+
* offset: [0, 1.0],
|
|
1738
|
+
* });
|
|
1739
|
+
*
|
|
1740
|
+
* // Open with inline HTML
|
|
1741
|
+
* const inline = await Webview.open({
|
|
1742
|
+
* source: webviewSource.html("<h1>Hello World</h1>"),
|
|
1743
|
+
* });
|
|
1744
|
+
*
|
|
1745
|
+
* // Open with a local asset
|
|
1746
|
+
* const local = await Webview.open({
|
|
1747
|
+
* source: webviewSource.local("my-mod::panel.html"),
|
|
1748
|
+
* offset: [0.5, 0],
|
|
1749
|
+
* });
|
|
1750
|
+
* ```
|
|
1751
|
+
*/
|
|
1752
|
+
static open(options: WebviewOpenOptions): Promise<Webview>;
|
|
1753
|
+
/**
|
|
1754
|
+
* Gets the current webview instance if called from within a webview context.
|
|
1755
|
+
*
|
|
1756
|
+
* @returns The current Webview instance, or undefined if not in a webview context
|
|
1757
|
+
*/
|
|
1758
|
+
static current(): Webview | undefined;
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
/**
|
|
1762
|
+
* Signals API namespace for cross-process communication.
|
|
1763
|
+
*
|
|
1764
|
+
* Provides a pub/sub mechanism that allows external processes to communicate
|
|
1765
|
+
* with the Desktop Homunculus application and its mods through event streaming.
|
|
1766
|
+
*
|
|
1767
|
+
* Key features:
|
|
1768
|
+
* - Real-time event streaming via Server-Sent Events (SSE)
|
|
1769
|
+
* - Signal broadcasting to multiple subscribers
|
|
1770
|
+
* - Type-safe payload handling
|
|
1771
|
+
*
|
|
1772
|
+
* @example
|
|
1773
|
+
* ```typescript
|
|
1774
|
+
* // Listen for custom events from external processes
|
|
1775
|
+
* const eventSource = signals.stream<{action: string, data: any}>(
|
|
1776
|
+
* "my-custom-signal",
|
|
1777
|
+
* (payload) => {
|
|
1778
|
+
* console.log("Received signal:", payload.action, payload.data);
|
|
1779
|
+
* }
|
|
1780
|
+
* );
|
|
1781
|
+
*
|
|
1782
|
+
* // Send signals to all listeners
|
|
1783
|
+
* await signals.send("my-custom-signal", {
|
|
1784
|
+
* action: "update",
|
|
1785
|
+
* data: { message: "Hello from external app!" }
|
|
1786
|
+
* });
|
|
1787
|
+
*
|
|
1788
|
+
* // Clean up when done
|
|
1789
|
+
* eventSource.close();
|
|
1790
|
+
* ```
|
|
1791
|
+
*/
|
|
1792
|
+
declare namespace signals {
|
|
1793
|
+
/**
|
|
1794
|
+
* Information about an active signal channel.
|
|
1795
|
+
*/
|
|
1796
|
+
interface SignalChannelInfo {
|
|
1797
|
+
/** The signal channel name. */
|
|
1798
|
+
signal: string;
|
|
1799
|
+
/** The number of active subscribers. */
|
|
1800
|
+
subscribers: number;
|
|
1801
|
+
}
|
|
1802
|
+
/**
|
|
1803
|
+
* Lists all active signal channels and their subscriber counts.
|
|
1804
|
+
*
|
|
1805
|
+
* Returns information about every signal channel that has been created.
|
|
1806
|
+
* Useful for debugging, monitoring, and discovering available channels.
|
|
1807
|
+
*
|
|
1808
|
+
* @returns Array of active signal channel information
|
|
1809
|
+
*
|
|
1810
|
+
* @example
|
|
1811
|
+
* ```typescript
|
|
1812
|
+
* // List all active signal channels
|
|
1813
|
+
* const channels = await signals.list();
|
|
1814
|
+
* for (const ch of channels) {
|
|
1815
|
+
* console.log(`${ch.signal}: ${ch.subscribers} subscribers`);
|
|
1816
|
+
* }
|
|
1817
|
+
*
|
|
1818
|
+
* // Check if a specific signal has listeners before sending
|
|
1819
|
+
* const channels = await signals.list();
|
|
1820
|
+
* const target = channels.find(ch => ch.signal === "my-signal");
|
|
1821
|
+
* if (target && target.subscribers > 0) {
|
|
1822
|
+
* await signals.send("my-signal", { data: "hello" });
|
|
1823
|
+
* }
|
|
1824
|
+
* ```
|
|
1825
|
+
*/
|
|
1826
|
+
function list(): Promise<SignalChannelInfo[]>;
|
|
1827
|
+
/**
|
|
1828
|
+
* Creates a persistent connection to stream signal events of a specific type.
|
|
1829
|
+
*
|
|
1830
|
+
* This establishes a Server-Sent Events (SSE) connection that will receive
|
|
1831
|
+
* all signals sent to the specified signal channel. The connection remains
|
|
1832
|
+
* open until explicitly closed.
|
|
1833
|
+
*
|
|
1834
|
+
* @template V - The type of the payload that will be received
|
|
1835
|
+
* @param signal - The signal channel name to subscribe to
|
|
1836
|
+
* @param f - Callback function to handle received payloads
|
|
1837
|
+
* @returns EventSource instance for managing the connection
|
|
1838
|
+
*
|
|
1839
|
+
* @example
|
|
1840
|
+
* ```typescript
|
|
1841
|
+
* // Listen for user interaction events
|
|
1842
|
+
* interface UserAction {
|
|
1843
|
+
* type: 'click' | 'hover' | 'scroll';
|
|
1844
|
+
* position: [number, number];
|
|
1845
|
+
* timestamp: number;
|
|
1846
|
+
* }
|
|
1847
|
+
*
|
|
1848
|
+
* const userEventStream = signals.stream<UserAction>(
|
|
1849
|
+
* "user-interactions",
|
|
1850
|
+
* async (action) => {
|
|
1851
|
+
* console.log(`User ${action.type} at`, action.position);
|
|
1852
|
+
* // Process the user action...
|
|
1853
|
+
* }
|
|
1854
|
+
* );
|
|
1855
|
+
*
|
|
1856
|
+
* // Later, close the stream
|
|
1857
|
+
* userEventStream.close();
|
|
1858
|
+
* ```
|
|
1859
|
+
*/
|
|
1860
|
+
function stream<V>(signal: string, f: (payload: V) => (void | Promise<void>)): EventSource;
|
|
1861
|
+
/**
|
|
1862
|
+
* Sends a signal payload to all subscribers listening to the specified signal channel.
|
|
1863
|
+
*
|
|
1864
|
+
* This broadcasts the payload to all active EventSource connections that are
|
|
1865
|
+
* streaming the same signal type. The operation is asynchronous and will
|
|
1866
|
+
* complete once the signal has been distributed to all subscribers.
|
|
1867
|
+
*
|
|
1868
|
+
* @template V - The type of the payload being sent
|
|
1869
|
+
* @param signal - The signal channel name to broadcast to
|
|
1870
|
+
* @param payload - The data to send to all subscribers
|
|
1871
|
+
*
|
|
1872
|
+
* @throws Will throw an error if the signal broadcast fails
|
|
1873
|
+
*
|
|
1874
|
+
* @example
|
|
1875
|
+
* ```typescript
|
|
1876
|
+
* // Send a notification to all mod windows
|
|
1877
|
+
* await signals.send("notifications", {
|
|
1878
|
+
* type: "info",
|
|
1879
|
+
* title: "Update Available",
|
|
1880
|
+
* message: "A new version of the character is available",
|
|
1881
|
+
* timestamp: Date.now()
|
|
1882
|
+
* });
|
|
1883
|
+
*
|
|
1884
|
+
* // Send real-time data updates
|
|
1885
|
+
* await signals.send("data-update", {
|
|
1886
|
+
* source: "weather-api",
|
|
1887
|
+
* temperature: 72,
|
|
1888
|
+
* conditions: "sunny"
|
|
1889
|
+
* });
|
|
1890
|
+
*
|
|
1891
|
+
* // Trigger actions in mods
|
|
1892
|
+
* await signals.send("vrm-action", {
|
|
1893
|
+
* action: "wave",
|
|
1894
|
+
* target: vrmEntity,
|
|
1895
|
+
* duration: 2000
|
|
1896
|
+
* });
|
|
1897
|
+
* ```
|
|
1898
|
+
*/
|
|
1899
|
+
function send<V>(signal: string, payload: V): Promise<void>;
|
|
1900
|
+
}
|
|
1901
|
+
|
|
1902
|
+
/**
|
|
1903
|
+
* Entities API namespace for managing ECS (Entity Component System) entities.
|
|
1904
|
+
*
|
|
1905
|
+
* In Desktop Homunculus, everything is represented as entities in Bevy's ECS system.
|
|
1906
|
+
* This includes VRM models, bones, UI elements, and other game objects. This namespace
|
|
1907
|
+
* provides core functionality for finding entities by name and manipulating their
|
|
1908
|
+
* transforms (position, rotation, scale).
|
|
1909
|
+
*
|
|
1910
|
+
* Key concepts:
|
|
1911
|
+
* - **Entity**: A unique identifier in the ECS system
|
|
1912
|
+
* - **Name**: Human-readable identifier for entities
|
|
1913
|
+
* - **Transform**: Position, rotation, and scale data
|
|
1914
|
+
* - **Hierarchy**: Entities can have parent-child relationships
|
|
1915
|
+
*
|
|
1916
|
+
* @example
|
|
1917
|
+
* ```typescript
|
|
1918
|
+
* // Find a VRM entity by name
|
|
1919
|
+
* const vrmEntity = await entities.findByName("MyCharacter");
|
|
1920
|
+
*
|
|
1921
|
+
* // Get the current transform (position, rotation, scale)
|
|
1922
|
+
* const transform = await entities.transform(vrmEntity);
|
|
1923
|
+
* console.log("Position:", transform.translation);
|
|
1924
|
+
*
|
|
1925
|
+
* // Move the VRM to a new position
|
|
1926
|
+
* await entities.setTransform(vrmEntity, {
|
|
1927
|
+
* translation: [100, 0, 50]
|
|
1928
|
+
* });
|
|
1929
|
+
*
|
|
1930
|
+
* // Find a bone within a specific VRM
|
|
1931
|
+
* const headBone = await entities.findByName("head", { root: vrmEntity });
|
|
1932
|
+
* ```
|
|
1933
|
+
*/
|
|
1934
|
+
declare namespace entities {
|
|
1935
|
+
/**
|
|
1936
|
+
* Options for entity search operations.
|
|
1937
|
+
*/
|
|
1938
|
+
interface FindOptions {
|
|
1939
|
+
/**
|
|
1940
|
+
* Optional root entity to search within.
|
|
1941
|
+
* If specified, the search will be limited to children of this entity.
|
|
1942
|
+
* If not specified, the search will be global across all entities.
|
|
1943
|
+
*/
|
|
1944
|
+
root?: number;
|
|
1945
|
+
}
|
|
1946
|
+
/**
|
|
1947
|
+
* Gets the current transform (position, rotation, scale) of an entity.
|
|
1948
|
+
*
|
|
1949
|
+
* The transform defines where the entity is positioned in 3D space,
|
|
1950
|
+
* how it's rotated, and its scale factor.
|
|
1951
|
+
*
|
|
1952
|
+
* @param entity - The entity ID to get the transform for
|
|
1953
|
+
* @returns A promise that resolves to the entity's transform data
|
|
1954
|
+
*
|
|
1955
|
+
* @example
|
|
1956
|
+
* ```typescript
|
|
1957
|
+
* const vrmEntity = await entities.findByName("MyCharacter");
|
|
1958
|
+
* const transform = await entities.transform(vrmEntity);
|
|
1959
|
+
*
|
|
1960
|
+
* console.log("Position:", transform.translation);
|
|
1961
|
+
* console.log("Rotation:", transform.rotation);
|
|
1962
|
+
* console.log("Scale:", transform.scale);
|
|
1963
|
+
* ```
|
|
1964
|
+
*/
|
|
1965
|
+
function transform(entity: number): Promise<Transform>;
|
|
1966
|
+
/**
|
|
1967
|
+
* Updates the transform (position, rotation, scale) of an entity.
|
|
1968
|
+
*
|
|
1969
|
+
* You can provide a partial transform to update only specific components.
|
|
1970
|
+
* For example, you can change just the position while leaving rotation
|
|
1971
|
+
* and scale unchanged.
|
|
1972
|
+
*
|
|
1973
|
+
* @param entity - The entity ID to update
|
|
1974
|
+
* @param transform - Partial transform data with the values to update
|
|
1975
|
+
*
|
|
1976
|
+
* @example
|
|
1977
|
+
* ```typescript
|
|
1978
|
+
* // Move entity to a new position
|
|
1979
|
+
* await entities.setTransform(vrmEntity, {
|
|
1980
|
+
* translation: [0, 100, 0] // Move up 100 units
|
|
1981
|
+
* });
|
|
1982
|
+
*
|
|
1983
|
+
* // Rotate and scale the entity
|
|
1984
|
+
* await entities.setTransform(vrmEntity, {
|
|
1985
|
+
* rotation: [0, 0, 0, 1], // Reset rotation to identity
|
|
1986
|
+
* scale: [2, 2, 2] // Double the size
|
|
1987
|
+
* });
|
|
1988
|
+
*
|
|
1989
|
+
* // Update all transform components at once
|
|
1990
|
+
* await entities.setTransform(vrmEntity, {
|
|
1991
|
+
* translation: [50, 0, -25],
|
|
1992
|
+
* rotation: [0, 0.707, 0, 0.707], // 90 degree Y rotation
|
|
1993
|
+
* scale: [1.5, 1.5, 1.5]
|
|
1994
|
+
* });
|
|
1995
|
+
* ```
|
|
1996
|
+
*/
|
|
1997
|
+
function setTransform(entity: number, transform: Partial<Transform>): Promise<void>;
|
|
1998
|
+
/**
|
|
1999
|
+
* Gets the human-readable name of an entity.
|
|
2000
|
+
*
|
|
2001
|
+
* Most entities in Desktop Homunculus have names that make them easier
|
|
2002
|
+
* to identify and work with. VRM models use their character names,
|
|
2003
|
+
* bones use standard bone names like "head", "leftHand", etc.
|
|
2004
|
+
*
|
|
2005
|
+
* @param entity - The entity ID to get the name for
|
|
2006
|
+
* @returns A promise that resolves to the entity's name
|
|
2007
|
+
*
|
|
2008
|
+
* @example
|
|
2009
|
+
* ```typescript
|
|
2010
|
+
* const vrmEntity = await entities.findByName("MyCharacter");
|
|
2011
|
+
* const name = await entities.name(vrmEntity);
|
|
2012
|
+
* console.log("Entity name:", name); // "MyCharacter"
|
|
2013
|
+
*
|
|
2014
|
+
* // Get bone names
|
|
2015
|
+
* const headBone = await entities.findByName("head", { root: vrmEntity });
|
|
2016
|
+
* const boneName = await entities.name(headBone);
|
|
2017
|
+
* console.log("Bone name:", boneName); // "head"
|
|
2018
|
+
* ```
|
|
2019
|
+
*/
|
|
2020
|
+
function name(entity: number): Promise<string>;
|
|
2021
|
+
/**
|
|
2022
|
+
* Finds an entity by its name, optionally within a specific parent entity.
|
|
2023
|
+
*
|
|
2024
|
+
* This is the primary method for locating entities in the ECS system.
|
|
2025
|
+
* Names are unique within their scope (global or under a specific parent).
|
|
2026
|
+
*
|
|
2027
|
+
* @param name - The name of the entity to find
|
|
2028
|
+
* @param options - Optional search parameters
|
|
2029
|
+
* @returns A promise that resolves to the entity ID
|
|
2030
|
+
* @throws Will throw an error if no entity with the given name is found
|
|
2031
|
+
*
|
|
2032
|
+
* @example
|
|
2033
|
+
* ```typescript
|
|
2034
|
+
* // Find a VRM character globally
|
|
2035
|
+
* const vrmEntity = await entities.findByName("MyCharacter");
|
|
2036
|
+
*
|
|
2037
|
+
* // Find a bone within a specific VRM
|
|
2038
|
+
* const headBone = await entities.findByName("head", {
|
|
2039
|
+
* root: vrmEntity
|
|
2040
|
+
* });
|
|
2041
|
+
*
|
|
2042
|
+
* // Find UI elements or other named entities
|
|
2043
|
+
* const settingsPanel = await entities.findByName("SettingsPanel");
|
|
2044
|
+
* const chatWindow = await entities.findByName("ChatWindow");
|
|
2045
|
+
* ```
|
|
2046
|
+
*/
|
|
2047
|
+
function findByName(name: string, options?: FindOptions): Promise<number>;
|
|
2048
|
+
interface MoveTargetWorld {
|
|
2049
|
+
type: "world";
|
|
2050
|
+
position: Vec2;
|
|
2051
|
+
z?: number;
|
|
2052
|
+
}
|
|
2053
|
+
interface MoveTargetViewport {
|
|
2054
|
+
type: "viewport";
|
|
2055
|
+
position: Vec2;
|
|
2056
|
+
}
|
|
2057
|
+
/**
|
|
2058
|
+
* Target position for entity movement.
|
|
2059
|
+
*
|
|
2060
|
+
* Use `type: "world"` for direct world-space coordinates (position as [x, y], z optional).
|
|
2061
|
+
* Use `type: "viewport"` for screen-space coordinates that are automatically converted to world space.
|
|
2062
|
+
*/
|
|
2063
|
+
type MoveTarget = MoveTargetWorld | MoveTargetViewport;
|
|
2064
|
+
/**
|
|
2065
|
+
* Moves an entity to the specified position.
|
|
2066
|
+
*
|
|
2067
|
+
* Supports two coordinate types:
|
|
2068
|
+
* - **World coordinates**: Sets the entity's position directly in 3D world space.
|
|
2069
|
+
* `z` is optional — if omitted, the entity keeps its current z position.
|
|
2070
|
+
* - **Viewport coordinates**: Screen-space position that is automatically converted
|
|
2071
|
+
* to world coordinates internally.
|
|
2072
|
+
*
|
|
2073
|
+
* @param entity - The entity ID to move
|
|
2074
|
+
* @param target - The target position (world or viewport coordinates)
|
|
2075
|
+
*
|
|
2076
|
+
* @example
|
|
2077
|
+
* ```typescript
|
|
2078
|
+
* // Move to world coordinates
|
|
2079
|
+
* await entities.move(vrmEntity, { type: "world", position: [0, 1.5], z: -2 });
|
|
2080
|
+
*
|
|
2081
|
+
* // Move to world coordinates (keep current z)
|
|
2082
|
+
* await entities.move(vrmEntity, { type: "world", position: [0, 1.5] });
|
|
2083
|
+
*
|
|
2084
|
+
* // Move to a screen position
|
|
2085
|
+
* await entities.move(vrmEntity, { type: "viewport", position: [500, 300] });
|
|
2086
|
+
* ```
|
|
2087
|
+
*/
|
|
2088
|
+
function move(entity: number, target: MoveTarget): Promise<void>;
|
|
2089
|
+
/**
|
|
2090
|
+
* Easing functions for tween animations.
|
|
2091
|
+
* Controls the acceleration curve of the animation.
|
|
2092
|
+
*/
|
|
2093
|
+
type EasingFunction = "linear" | "quadraticIn" | "quadraticOut" | "quadraticInOut" | "cubicIn" | "cubicOut" | "cubicInOut" | "quarticIn" | "quarticOut" | "quarticInOut" | "quinticIn" | "quinticOut" | "quinticInOut" | "sineIn" | "sineOut" | "sineInOut" | "circularIn" | "circularOut" | "circularInOut" | "exponentialIn" | "exponentialOut" | "exponentialInOut" | "elasticIn" | "elasticOut" | "elasticInOut" | "backIn" | "backOut" | "backInOut" | "bounceIn" | "bounceOut" | "bounceInOut" | "smoothStepIn" | "smoothStepOut" | "smoothStep" | "smootherStepIn" | "smootherStepOut" | "smootherStep";
|
|
2094
|
+
/**
|
|
2095
|
+
* Request parameters for tweening an entity's position.
|
|
2096
|
+
*/
|
|
2097
|
+
interface TweenPositionRequest {
|
|
2098
|
+
/** Target position as [x, y, z] */
|
|
2099
|
+
target: [number, number, number];
|
|
2100
|
+
/** Duration in milliseconds */
|
|
2101
|
+
durationMs: number;
|
|
2102
|
+
/** Easing function (default: "linear") */
|
|
2103
|
+
easing?: EasingFunction;
|
|
2104
|
+
/** Whether to wait for the tween to complete before returning (default: false) */
|
|
2105
|
+
wait?: boolean;
|
|
2106
|
+
}
|
|
2107
|
+
/**
|
|
2108
|
+
* Request parameters for tweening an entity's rotation.
|
|
2109
|
+
*/
|
|
2110
|
+
interface TweenRotationRequest {
|
|
2111
|
+
/** Target rotation as quaternion [x, y, z, w] */
|
|
2112
|
+
target: [number, number, number, number];
|
|
2113
|
+
/** Duration in milliseconds */
|
|
2114
|
+
durationMs: number;
|
|
2115
|
+
/** Easing function (default: "linear") */
|
|
2116
|
+
easing?: EasingFunction;
|
|
2117
|
+
/** Whether to wait for the tween to complete before returning (default: false) */
|
|
2118
|
+
wait?: boolean;
|
|
2119
|
+
}
|
|
2120
|
+
/**
|
|
2121
|
+
* Request parameters for tweening an entity's scale.
|
|
2122
|
+
*/
|
|
2123
|
+
interface TweenScaleRequest {
|
|
2124
|
+
/** Target scale as [x, y, z] */
|
|
2125
|
+
target: [number, number, number];
|
|
2126
|
+
/** Duration in milliseconds */
|
|
2127
|
+
durationMs: number;
|
|
2128
|
+
/** Easing function (default: "linear") */
|
|
2129
|
+
easing?: EasingFunction;
|
|
2130
|
+
/** Whether to wait for the tween to complete before returning (default: false) */
|
|
2131
|
+
wait?: boolean;
|
|
2132
|
+
}
|
|
2133
|
+
/**
|
|
2134
|
+
* Smoothly animate an entity's position to a target value.
|
|
2135
|
+
*
|
|
2136
|
+
* @param entityId - The entity ID to tween
|
|
2137
|
+
* @param request - Tween parameters
|
|
2138
|
+
* @returns Promise that resolves when the request completes (or when animation finishes if wait=true)
|
|
2139
|
+
*
|
|
2140
|
+
* @example
|
|
2141
|
+
* ```typescript
|
|
2142
|
+
* await entities.tweenPosition(myEntity, {
|
|
2143
|
+
* target: [100, 50, 0],
|
|
2144
|
+
* durationMs: 1000,
|
|
2145
|
+
* easing: "quadraticInOut",
|
|
2146
|
+
* wait: true,
|
|
2147
|
+
* });
|
|
2148
|
+
* ```
|
|
2149
|
+
*/
|
|
2150
|
+
function tweenPosition(entityId: number, request: TweenPositionRequest): Promise<void>;
|
|
2151
|
+
/**
|
|
2152
|
+
* Smoothly animate an entity's rotation to a target value.
|
|
2153
|
+
*
|
|
2154
|
+
* @param entityId - The entity ID to tween
|
|
2155
|
+
* @param request - Tween parameters
|
|
2156
|
+
* @returns Promise that resolves when the request completes (or when animation finishes if wait=true)
|
|
2157
|
+
*
|
|
2158
|
+
* @example
|
|
2159
|
+
* ```typescript
|
|
2160
|
+
* await entities.tweenRotation(myEntity, {
|
|
2161
|
+
* target: [0, 0, 0.7071, 0.7071], // 90 degrees around Z axis
|
|
2162
|
+
* durationMs: 500,
|
|
2163
|
+
* easing: "elasticOut",
|
|
2164
|
+
* });
|
|
2165
|
+
* ```
|
|
2166
|
+
*/
|
|
2167
|
+
function tweenRotation(entityId: number, request: TweenRotationRequest): Promise<void>;
|
|
2168
|
+
/**
|
|
2169
|
+
* Smoothly animate an entity's scale to a target value.
|
|
2170
|
+
*
|
|
2171
|
+
* @param entityId - The entity ID to tween
|
|
2172
|
+
* @param request - Tween parameters
|
|
2173
|
+
* @returns Promise that resolves when the request completes (or when animation finishes if wait=true)
|
|
2174
|
+
*
|
|
2175
|
+
* @example
|
|
2176
|
+
* ```typescript
|
|
2177
|
+
* await entities.tweenScale(myEntity, {
|
|
2178
|
+
* target: [2, 2, 2],
|
|
2179
|
+
* durationMs: 800,
|
|
2180
|
+
* easing: "bounceOut",
|
|
2181
|
+
* wait: false,
|
|
2182
|
+
* });
|
|
2183
|
+
* ```
|
|
2184
|
+
*/
|
|
2185
|
+
function tweenScale(entityId: number, request: TweenScaleRequest): Promise<void>;
|
|
2186
|
+
}
|
|
2187
|
+
|
|
2188
|
+
/**
|
|
2189
|
+
* Provides access to the application API.
|
|
2190
|
+
*/
|
|
2191
|
+
declare namespace app {
|
|
2192
|
+
/**
|
|
2193
|
+
* Exits the application without any problems.
|
|
2194
|
+
*/
|
|
2195
|
+
function exit(): Promise<void>;
|
|
2196
|
+
/**
|
|
2197
|
+
* Checks if the Desktop Homunculus server is running and healthy.
|
|
2198
|
+
*
|
|
2199
|
+
* Returns `true` if the server responds with a successful health check,
|
|
2200
|
+
* `false` if the server is unreachable or unhealthy.
|
|
2201
|
+
*
|
|
2202
|
+
* @example
|
|
2203
|
+
* ```typescript
|
|
2204
|
+
* const alive = await app.health();
|
|
2205
|
+
* if (!alive) {
|
|
2206
|
+
* console.error("Homunculus server is not running");
|
|
2207
|
+
* }
|
|
2208
|
+
* ```
|
|
2209
|
+
*/
|
|
2210
|
+
function health(): Promise<boolean>;
|
|
2211
|
+
/**
|
|
2212
|
+
* Platform information about the running system.
|
|
2213
|
+
*/
|
|
2214
|
+
interface PlatformInfo {
|
|
2215
|
+
/** Operating system name (e.g., "macos", "windows", "linux"). */
|
|
2216
|
+
os: string;
|
|
2217
|
+
/** CPU architecture (e.g., "aarch64", "x86_64"). */
|
|
2218
|
+
arch: string;
|
|
2219
|
+
}
|
|
2220
|
+
/**
|
|
2221
|
+
* Summary of a loaded mod as returned by the info endpoint.
|
|
2222
|
+
*/
|
|
2223
|
+
interface InfoMod {
|
|
2224
|
+
/** The mod package name. */
|
|
2225
|
+
name: string;
|
|
2226
|
+
/** The mod package version. */
|
|
2227
|
+
version: string;
|
|
2228
|
+
/** Human-readable description. */
|
|
2229
|
+
description: string | null;
|
|
2230
|
+
/** The mod author. */
|
|
2231
|
+
author: string | null;
|
|
2232
|
+
/** The mod license. */
|
|
2233
|
+
license: string | null;
|
|
2234
|
+
/** Whether the mod has a running main process. */
|
|
2235
|
+
hasMain: boolean;
|
|
2236
|
+
/** Available bin command names. */
|
|
2237
|
+
binCommands: string[];
|
|
2238
|
+
/** Registered asset IDs. */
|
|
2239
|
+
assetIds: string[];
|
|
2240
|
+
}
|
|
2241
|
+
/**
|
|
2242
|
+
* Application metadata returned by the info endpoint.
|
|
2243
|
+
*/
|
|
2244
|
+
interface AppInfo {
|
|
2245
|
+
/** The engine version string (e.g., "0.1.0-alpha.3.2"). */
|
|
2246
|
+
version: string;
|
|
2247
|
+
/** Platform information. */
|
|
2248
|
+
platform: PlatformInfo;
|
|
2249
|
+
/** Engine-level features available in this build. */
|
|
2250
|
+
features: string[];
|
|
2251
|
+
/** All loaded mods with metadata. */
|
|
2252
|
+
mods: InfoMod[];
|
|
2253
|
+
}
|
|
2254
|
+
/**
|
|
2255
|
+
* Returns metadata about the running Desktop Homunculus instance.
|
|
2256
|
+
*
|
|
2257
|
+
* Provides the engine version, platform info, compiled features,
|
|
2258
|
+
* and loaded mods in a single request. Useful for startup checks,
|
|
2259
|
+
* feature detection, and status displays.
|
|
2260
|
+
*
|
|
2261
|
+
* @returns Application info including version, platform, features, and mods
|
|
2262
|
+
*
|
|
2263
|
+
* @example
|
|
2264
|
+
* ```typescript
|
|
2265
|
+
* const info = await app.info();
|
|
2266
|
+
* console.log(`Engine v${info.version} on ${info.platform.os}/${info.platform.arch}`);
|
|
2267
|
+
* console.log(`Features: ${info.features.join(", ")}`);
|
|
2268
|
+
* console.log(`${info.mods.length} mods loaded`);
|
|
2269
|
+
* ```
|
|
2270
|
+
*/
|
|
2271
|
+
function info(): Promise<AppInfo>;
|
|
2272
|
+
}
|
|
2273
|
+
|
|
2274
|
+
/**
|
|
2275
|
+
* Mod management namespace for executing commands defined in mod packages.
|
|
2276
|
+
*
|
|
2277
|
+
* Provides functions to run on-demand scripts from installed mods,
|
|
2278
|
+
* with support for passing arguments, stdin data, configuring timeouts,
|
|
2279
|
+
* and real-time NDJSON streaming of command output.
|
|
2280
|
+
*
|
|
2281
|
+
* @example
|
|
2282
|
+
* ```typescript
|
|
2283
|
+
* // Execute a command and collect the result
|
|
2284
|
+
* const result = await mods.executeCommand({ command: "greet" });
|
|
2285
|
+
* console.log(result.stdout);
|
|
2286
|
+
*
|
|
2287
|
+
* // Stream command output in real-time
|
|
2288
|
+
* for await (const event of mods.streamCommand({ command: "build" })) {
|
|
2289
|
+
* if (event.type === "stdout") console.log(event.data);
|
|
2290
|
+
* if (event.type === "stderr") console.error(event.data);
|
|
2291
|
+
* if (event.type === "exit") console.log("Exit code:", event.exitCode);
|
|
2292
|
+
* }
|
|
2293
|
+
* ```
|
|
2294
|
+
*/
|
|
2295
|
+
declare namespace mods {
|
|
2296
|
+
/**
|
|
2297
|
+
* Summary information about a loaded mod.
|
|
2298
|
+
*
|
|
2299
|
+
* @example
|
|
2300
|
+
* ```typescript
|
|
2301
|
+
* const allMods = await mods.list();
|
|
2302
|
+
* for (const mod of allMods) {
|
|
2303
|
+
* console.log(`${mod.name}@${mod.version} (${mod.commands.length} commands)`);
|
|
2304
|
+
* }
|
|
2305
|
+
* ```
|
|
2306
|
+
*/
|
|
2307
|
+
interface ModInfo {
|
|
2308
|
+
/** The mod package name. */
|
|
2309
|
+
name: string;
|
|
2310
|
+
/** The mod package version. */
|
|
2311
|
+
version: string;
|
|
2312
|
+
/** Optional description from package.json. */
|
|
2313
|
+
description?: string;
|
|
2314
|
+
/** Optional author from package.json. */
|
|
2315
|
+
author?: string;
|
|
2316
|
+
/** Optional license from package.json. */
|
|
2317
|
+
license?: string;
|
|
2318
|
+
/** Service script path (auto-launched at startup), or null if no service. */
|
|
2319
|
+
serviceScriptPath?: string;
|
|
2320
|
+
/** Available bin command names. */
|
|
2321
|
+
commands: string[];
|
|
2322
|
+
/** Asset declarations keyed by asset ID. */
|
|
2323
|
+
assets: Record<string, {
|
|
2324
|
+
path: string;
|
|
2325
|
+
type: string;
|
|
2326
|
+
description: string;
|
|
2327
|
+
}>;
|
|
2328
|
+
/** Menu entries registered by this mod. */
|
|
2329
|
+
menus: Array<{
|
|
2330
|
+
id: string;
|
|
2331
|
+
text: string;
|
|
2332
|
+
command: string;
|
|
2333
|
+
}>;
|
|
2334
|
+
/** Absolute path to the mod's root directory. */
|
|
2335
|
+
modDir: string;
|
|
2336
|
+
}
|
|
2337
|
+
/**
|
|
2338
|
+
* List all loaded mods and their metadata.
|
|
2339
|
+
*
|
|
2340
|
+
* Returns summary information for every mod discovered at startup,
|
|
2341
|
+
* including available bin commands and registered asset IDs.
|
|
2342
|
+
*
|
|
2343
|
+
* @returns Array of mod information objects
|
|
2344
|
+
*
|
|
2345
|
+
* @example
|
|
2346
|
+
* ```typescript
|
|
2347
|
+
* // List all installed mods
|
|
2348
|
+
* const allMods = await mods.list();
|
|
2349
|
+
* console.log(`${allMods.length} mods installed`);
|
|
2350
|
+
*
|
|
2351
|
+
* // Find mods with bin commands
|
|
2352
|
+
* const withCommands = allMods.filter(m => m.commands.length > 0);
|
|
2353
|
+
*
|
|
2354
|
+
* // Get assets from a specific mod
|
|
2355
|
+
* const elmer = allMods.find(m => m.name === "elmer");
|
|
2356
|
+
* if (elmer) {
|
|
2357
|
+
* console.log("Elmer assets:", Object.keys(elmer.assets));
|
|
2358
|
+
* }
|
|
2359
|
+
* ```
|
|
2360
|
+
*/
|
|
2361
|
+
function list(): Promise<ModInfo[]>;
|
|
2362
|
+
/**
|
|
2363
|
+
* Get detailed information about a specific mod by name.
|
|
2364
|
+
*
|
|
2365
|
+
* @param modName - The mod package name
|
|
2366
|
+
* @returns Mod information
|
|
2367
|
+
*
|
|
2368
|
+
* @example
|
|
2369
|
+
* ```typescript
|
|
2370
|
+
* const elmer = await mods.get("elmer");
|
|
2371
|
+
* console.log(`${elmer.name}@${elmer.version}`);
|
|
2372
|
+
* console.log("Commands:", elmer.commands);
|
|
2373
|
+
* ```
|
|
2374
|
+
*/
|
|
2375
|
+
function get(modName: string): Promise<ModInfo>;
|
|
2376
|
+
/**
|
|
2377
|
+
* Request parameters for executing a mod command.
|
|
2378
|
+
*
|
|
2379
|
+
* @example
|
|
2380
|
+
* ```typescript
|
|
2381
|
+
* const request: mods.ExecuteCommandRequest = {
|
|
2382
|
+
* command: "build",
|
|
2383
|
+
* args: ["--verbose"],
|
|
2384
|
+
* stdin: "input data",
|
|
2385
|
+
* timeoutMs: 5000,
|
|
2386
|
+
* };
|
|
2387
|
+
* ```
|
|
2388
|
+
*/
|
|
2389
|
+
interface ExecuteCommandRequest {
|
|
2390
|
+
/** The command name to execute (resolved via npx from installed mod packages). */
|
|
2391
|
+
command: string;
|
|
2392
|
+
/** Arguments to pass to the script (after the script path). Max 64 args, each max 4096 chars. */
|
|
2393
|
+
args?: string[];
|
|
2394
|
+
/** Data to write to the process stdin. Stdin is closed after writing. Max 1 MiB. */
|
|
2395
|
+
stdin?: string;
|
|
2396
|
+
/** Timeout in milliseconds (1–300000). Defaults to 30000 (30s). */
|
|
2397
|
+
timeoutMs?: number;
|
|
2398
|
+
}
|
|
2399
|
+
/** A stdout line event from a streaming command execution. */
|
|
2400
|
+
interface CommandStdoutEvent {
|
|
2401
|
+
type: "stdout";
|
|
2402
|
+
data: string;
|
|
2403
|
+
}
|
|
2404
|
+
/** A stderr line event from a streaming command execution. */
|
|
2405
|
+
interface CommandStderrEvent {
|
|
2406
|
+
type: "stderr";
|
|
2407
|
+
data: string;
|
|
2408
|
+
}
|
|
2409
|
+
/** The exit event from a streaming command execution. Always the last event. */
|
|
2410
|
+
interface CommandExitEvent {
|
|
2411
|
+
type: "exit";
|
|
2412
|
+
/** Process exit code, or null if the process was killed by a signal. */
|
|
2413
|
+
exitCode: number | null;
|
|
2414
|
+
/** Whether the process was killed due to timeout. */
|
|
2415
|
+
timedOut: boolean;
|
|
2416
|
+
/** Unix signal name if the process was killed by a signal. */
|
|
2417
|
+
signal?: string;
|
|
2418
|
+
}
|
|
2419
|
+
/** Union of all command event types emitted during streaming execution. */
|
|
2420
|
+
type CommandEvent = CommandStdoutEvent | CommandStderrEvent | CommandExitEvent;
|
|
2421
|
+
/**
|
|
2422
|
+
* Buffered result of a command execution.
|
|
2423
|
+
*
|
|
2424
|
+
* @example
|
|
2425
|
+
* ```typescript
|
|
2426
|
+
* const result = await mods.executeCommand({ command: "hello" });
|
|
2427
|
+
* if (result.exitCode === 0) {
|
|
2428
|
+
* console.log("Output:", result.stdout);
|
|
2429
|
+
* } else {
|
|
2430
|
+
* console.error("Error:", result.stderr);
|
|
2431
|
+
* }
|
|
2432
|
+
* ```
|
|
2433
|
+
*/
|
|
2434
|
+
interface CommandResult {
|
|
2435
|
+
/** Process exit code, or null if the process was killed by a signal. */
|
|
2436
|
+
exitCode: number | null;
|
|
2437
|
+
/** Whether the process was killed due to timeout. */
|
|
2438
|
+
timedOut: boolean;
|
|
2439
|
+
/** Unix signal name if the process was killed by a signal. */
|
|
2440
|
+
signal?: string;
|
|
2441
|
+
/** All stdout output joined by newlines. */
|
|
2442
|
+
stdout: string;
|
|
2443
|
+
/** All stderr output joined by newlines. */
|
|
2444
|
+
stderr: string;
|
|
2445
|
+
}
|
|
2446
|
+
/**
|
|
2447
|
+
* Execute a mod command with real-time NDJSON streaming output.
|
|
2448
|
+
*
|
|
2449
|
+
* Returns an async generator that yields {@link CommandEvent} objects
|
|
2450
|
+
* as the command produces output. The last event is always an `exit` event.
|
|
2451
|
+
*
|
|
2452
|
+
* @param request - Command execution parameters
|
|
2453
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
2454
|
+
* @returns An async generator yielding command events
|
|
2455
|
+
*
|
|
2456
|
+
* @example
|
|
2457
|
+
* ```typescript
|
|
2458
|
+
* // Stream output from a long-running build
|
|
2459
|
+
* for await (const event of mods.streamCommand({ command: "build" })) {
|
|
2460
|
+
* switch (event.type) {
|
|
2461
|
+
* case "stdout": console.log(event.data); break;
|
|
2462
|
+
* case "stderr": console.error(event.data); break;
|
|
2463
|
+
* case "exit": console.log("Done, exit code:", event.exitCode); break;
|
|
2464
|
+
* }
|
|
2465
|
+
* }
|
|
2466
|
+
* ```
|
|
2467
|
+
*/
|
|
2468
|
+
function streamCommand(request: ExecuteCommandRequest, signal?: AbortSignal): AsyncGenerator<CommandEvent>;
|
|
2469
|
+
/**
|
|
2470
|
+
* Execute a mod command and collect the full result.
|
|
2471
|
+
*
|
|
2472
|
+
* This is a convenience wrapper around {@link streamCommand} that buffers
|
|
2473
|
+
* all output and returns a single {@link CommandResult}.
|
|
2474
|
+
*
|
|
2475
|
+
* @param request - Command execution parameters
|
|
2476
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
2477
|
+
* @returns The collected command result with exit code, stdout, and stderr
|
|
2478
|
+
*
|
|
2479
|
+
* @example
|
|
2480
|
+
* ```typescript
|
|
2481
|
+
* // Simple execution
|
|
2482
|
+
* const result = await mods.executeCommand({ command: "build" });
|
|
2483
|
+
*
|
|
2484
|
+
* // With arguments
|
|
2485
|
+
* const result = await mods.executeCommand({
|
|
2486
|
+
* command: "compile",
|
|
2487
|
+
* args: ["--target", "es2020"],
|
|
2488
|
+
* });
|
|
2489
|
+
*
|
|
2490
|
+
* // With stdin data and custom timeout
|
|
2491
|
+
* const result = await mods.executeCommand({
|
|
2492
|
+
* command: "transform",
|
|
2493
|
+
* stdin: JSON.stringify({ input: "data" }),
|
|
2494
|
+
* timeoutMs: 60000,
|
|
2495
|
+
* });
|
|
2496
|
+
* ```
|
|
2497
|
+
*/
|
|
2498
|
+
function executeCommand(request: ExecuteCommandRequest, signal?: AbortSignal): Promise<CommandResult>;
|
|
2499
|
+
/**
|
|
2500
|
+
* Metadata for a mod-registered context menu item.
|
|
2501
|
+
*
|
|
2502
|
+
* @example
|
|
2503
|
+
* ```typescript
|
|
2504
|
+
* const items = await mods.menus();
|
|
2505
|
+
* for (const item of items) {
|
|
2506
|
+
* console.log(`${item.modName}: ${item.text}`);
|
|
2507
|
+
* }
|
|
2508
|
+
* ```
|
|
2509
|
+
*/
|
|
2510
|
+
interface ModMenuMetadata {
|
|
2511
|
+
/** Unique identifier for the menu item. */
|
|
2512
|
+
id: string;
|
|
2513
|
+
/** The mod package name that registered this menu item. */
|
|
2514
|
+
modName: string;
|
|
2515
|
+
/** Display text shown in the context menu. */
|
|
2516
|
+
text: string;
|
|
2517
|
+
/** Bin command to execute when the menu item is selected. */
|
|
2518
|
+
command: string;
|
|
2519
|
+
}
|
|
2520
|
+
/**
|
|
2521
|
+
* Returns all registered mod menu items.
|
|
2522
|
+
*
|
|
2523
|
+
* Menu items are declared in each mod's `package.json` under the
|
|
2524
|
+
* `homunculus.menus` field and collected at startup.
|
|
2525
|
+
*
|
|
2526
|
+
* @example
|
|
2527
|
+
* ```typescript
|
|
2528
|
+
* import { mods } from "@hmcs/sdk";
|
|
2529
|
+
*
|
|
2530
|
+
* const menuItems = await mods.menus();
|
|
2531
|
+
* for (const item of menuItems) {
|
|
2532
|
+
* console.log(`${item.modName}: ${item.text}`);
|
|
2533
|
+
* }
|
|
2534
|
+
* ```
|
|
2535
|
+
*/
|
|
2536
|
+
function menus(): Promise<ModMenuMetadata[]>;
|
|
2537
|
+
}
|
|
2538
|
+
|
|
2539
|
+
/**
|
|
2540
|
+
* Assets API namespace for querying available mod assets.
|
|
2541
|
+
*
|
|
2542
|
+
* Provides access to the asset registry, which contains all assets declared
|
|
2543
|
+
* by installed mods. Assets are referenced by their globally unique ID using
|
|
2544
|
+
* the format `"mod-name:asset-name"` (e.g., `"elmer:idle"`, `"my-mod:click"`).
|
|
2545
|
+
*
|
|
2546
|
+
* @example
|
|
2547
|
+
* ```typescript
|
|
2548
|
+
* // List all available assets
|
|
2549
|
+
* const all = await assets.list();
|
|
2550
|
+
*
|
|
2551
|
+
* // Filter by type
|
|
2552
|
+
* const vrms = await assets.list({ type: "vrm" });
|
|
2553
|
+
*
|
|
2554
|
+
* // Filter by mod
|
|
2555
|
+
* const elmerAssets = await assets.list({ mod: "elmer" });
|
|
2556
|
+
* ```
|
|
2557
|
+
*/
|
|
2558
|
+
declare namespace assets {
|
|
2559
|
+
/** The type of an asset. */
|
|
2560
|
+
type AssetType = "vrm" | "vrma" | "sound" | "image" | "html";
|
|
2561
|
+
/** Information about a registered asset. */
|
|
2562
|
+
interface AssetInfo {
|
|
2563
|
+
/** Globally unique asset ID. */
|
|
2564
|
+
id: string;
|
|
2565
|
+
/** The asset type. */
|
|
2566
|
+
type: AssetType;
|
|
2567
|
+
/** The mod that provides this asset. */
|
|
2568
|
+
mod: string;
|
|
2569
|
+
/** Optional description of the asset. */
|
|
2570
|
+
description?: string;
|
|
2571
|
+
}
|
|
2572
|
+
/** Filter options for listing assets. */
|
|
2573
|
+
interface AssetFilter {
|
|
2574
|
+
/** Filter by asset type. */
|
|
2575
|
+
type?: AssetType;
|
|
2576
|
+
/** Filter by mod name. */
|
|
2577
|
+
mod?: string;
|
|
2578
|
+
}
|
|
2579
|
+
/**
|
|
2580
|
+
* Lists available assets, optionally filtered by type and/or mod.
|
|
2581
|
+
*
|
|
2582
|
+
* @param filter - Optional filter criteria
|
|
2583
|
+
* @returns Array of matching asset info objects
|
|
2584
|
+
*
|
|
2585
|
+
* @example
|
|
2586
|
+
* ```typescript
|
|
2587
|
+
* // Get all assets
|
|
2588
|
+
* const all = await assets.list();
|
|
2589
|
+
*
|
|
2590
|
+
* // Get only VRM models
|
|
2591
|
+
* const vrms = await assets.list({ type: "vrm" });
|
|
2592
|
+
*
|
|
2593
|
+
* // Get assets from a specific mod
|
|
2594
|
+
* const modAssets = await assets.list({ mod: "elmer" });
|
|
2595
|
+
*
|
|
2596
|
+
* // Combine filters
|
|
2597
|
+
* const sounds = await assets.list({ type: "sound", mod: "my-mod" });
|
|
2598
|
+
* ```
|
|
2599
|
+
*/
|
|
2600
|
+
function list(filter?: AssetFilter): Promise<AssetInfo[]>;
|
|
2601
|
+
}
|
|
2602
|
+
|
|
2603
|
+
/**
|
|
2604
|
+
* Resolves after `ms` milliseconds (non-blocking delay).
|
|
2605
|
+
*
|
|
2606
|
+
* @example
|
|
2607
|
+
*
|
|
2608
|
+
*/
|
|
2609
|
+
declare function sleep(ms: number): Promise<unknown>;
|
|
2610
|
+
|
|
2611
|
+
export { HomunculusApiError, HomunculusStreamError, Vrm, VrmEventSource, Webview, app, assets, audio, coordinates, displays, effects, entities, host, isWebviewSourceHtml, isWebviewSourceInfoHtml, isWebviewSourceInfoLocal, isWebviewSourceInfoUrl, isWebviewSourceLocal, isWebviewSourceUrl, mods, preferences, repeat, settings, shadowPanel, signals, sleep, speech, webviewSource };
|
|
2612
|
+
export type { Bones, Button, EventMap, ExpressionInfo, ExpressionsResponse, GlobalDisplay, GlobalViewport, LookAtState, MoveToArgs, Ocean, OverrideType, Persona, PersonaChangeEvent, PositionResponse, Quat, Rect, SetFpsBody, SetLinkedVrmRequest, ShadowPanelPutBody, SpawnVrmOptions, SpeakTimelineOptions, SpringBoneChain, SpringBoneChainsResponse, SpringBoneProps, StampRequestBody, TimelineKeyframe, Transform, TransformArgs, Vec2, Vec3, VrmDragEvent, VrmMetadata, VrmMouseEvent, VrmPointerEvent, VrmSnapshot, VrmStateChangeEvent, VrmStateRequest, VrmStateResponse, VrmaInfo, VrmaPlayRequest, VrmaRepeat, VrmaSpeedBody, VrmaState, WebviewInfo, WebviewNavigateRequest, WebviewOpenOptions, WebviewPatchRequest, WebviewSource, WebviewSourceHtml, WebviewSourceInfo, WebviewSourceInfoHtml, WebviewSourceInfoLocal, WebviewSourceInfoUrl, WebviewSourceLocal, WebviewSourceUrl };
|