@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.
@@ -0,0 +1,46 @@
1
+ 'use strict';
2
+
3
+ var host = require('./host.cjs');
4
+
5
+ /**
6
+ * Shadow Panel API namespace for controlling the application's shadow overlay.
7
+ *
8
+ * The shadow panel is a visual overlay that can be used to create atmospheric
9
+ * effects, focus attention, or provide visual feedback.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * await shadowPanel.setAlpha(0.7);
14
+ * const currentAlpha = await shadowPanel.alpha();
15
+ * await shadowPanel.setAlpha(0);
16
+ * ```
17
+ */
18
+ exports.shadowPanel = void 0;
19
+ (function (shadowPanel) {
20
+ /**
21
+ * Gets the current transparency level of the shadow panel.
22
+ *
23
+ * @returns A promise that resolves to the current alpha value (0-1)
24
+ */
25
+ async function alpha() {
26
+ const response = await host.host.get(host.host.createUrl("shadow-panel/alpha"));
27
+ return Number(await response.json());
28
+ }
29
+ shadowPanel.alpha = alpha;
30
+ /**
31
+ * Sets the transparency level of the shadow panel.
32
+ *
33
+ * @param alpha - The transparency value between 0 (invisible) and 1 (opaque)
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * await shadowPanel.setAlpha(0.7);
38
+ * ```
39
+ */
40
+ async function setAlpha(alpha) {
41
+ await host.host.put(host.host.createUrl("shadow-panel/alpha"), {
42
+ alpha,
43
+ });
44
+ }
45
+ shadowPanel.setAlpha = setAlpha;
46
+ })(exports.shadowPanel || (exports.shadowPanel = {}));
@@ -0,0 +1,46 @@
1
+ import { host } from './host.js';
2
+
3
+ /**
4
+ * Shadow Panel API namespace for controlling the application's shadow overlay.
5
+ *
6
+ * The shadow panel is a visual overlay that can be used to create atmospheric
7
+ * effects, focus attention, or provide visual feedback.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * await shadowPanel.setAlpha(0.7);
12
+ * const currentAlpha = await shadowPanel.alpha();
13
+ * await shadowPanel.setAlpha(0);
14
+ * ```
15
+ */
16
+ var shadowPanel;
17
+ (function (shadowPanel) {
18
+ /**
19
+ * Gets the current transparency level of the shadow panel.
20
+ *
21
+ * @returns A promise that resolves to the current alpha value (0-1)
22
+ */
23
+ async function alpha() {
24
+ const response = await host.get(host.createUrl("shadow-panel/alpha"));
25
+ return Number(await response.json());
26
+ }
27
+ shadowPanel.alpha = alpha;
28
+ /**
29
+ * Sets the transparency level of the shadow panel.
30
+ *
31
+ * @param alpha - The transparency value between 0 (invisible) and 1 (opaque)
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * await shadowPanel.setAlpha(0.7);
36
+ * ```
37
+ */
38
+ async function setAlpha(alpha) {
39
+ await host.put(host.createUrl("shadow-panel/alpha"), {
40
+ alpha,
41
+ });
42
+ }
43
+ shadowPanel.setAlpha = setAlpha;
44
+ })(shadowPanel || (shadowPanel = {}));
45
+
46
+ export { shadowPanel };
@@ -0,0 +1,158 @@
1
+ 'use strict';
2
+
3
+ var host = require('./host.cjs');
4
+ var eventsource = require('eventsource');
5
+
6
+ /**
7
+ * Signals API namespace for cross-process communication.
8
+ *
9
+ * Provides a pub/sub mechanism that allows external processes to communicate
10
+ * with the Desktop Homunculus application and its mods through event streaming.
11
+ *
12
+ * Key features:
13
+ * - Real-time event streaming via Server-Sent Events (SSE)
14
+ * - Signal broadcasting to multiple subscribers
15
+ * - Type-safe payload handling
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * // Listen for custom events from external processes
20
+ * const eventSource = signals.stream<{action: string, data: any}>(
21
+ * "my-custom-signal",
22
+ * (payload) => {
23
+ * console.log("Received signal:", payload.action, payload.data);
24
+ * }
25
+ * );
26
+ *
27
+ * // Send signals to all listeners
28
+ * await signals.send("my-custom-signal", {
29
+ * action: "update",
30
+ * data: { message: "Hello from external app!" }
31
+ * });
32
+ *
33
+ * // Clean up when done
34
+ * eventSource.close();
35
+ * ```
36
+ */
37
+ exports.signals = void 0;
38
+ (function (signals) {
39
+ /**
40
+ * Lists all active signal channels and their subscriber counts.
41
+ *
42
+ * Returns information about every signal channel that has been created.
43
+ * Useful for debugging, monitoring, and discovering available channels.
44
+ *
45
+ * @returns Array of active signal channel information
46
+ *
47
+ * @example
48
+ * ```typescript
49
+ * // List all active signal channels
50
+ * const channels = await signals.list();
51
+ * for (const ch of channels) {
52
+ * console.log(`${ch.signal}: ${ch.subscribers} subscribers`);
53
+ * }
54
+ *
55
+ * // Check if a specific signal has listeners before sending
56
+ * const channels = await signals.list();
57
+ * const target = channels.find(ch => ch.signal === "my-signal");
58
+ * if (target && target.subscribers > 0) {
59
+ * await signals.send("my-signal", { data: "hello" });
60
+ * }
61
+ * ```
62
+ */
63
+ async function list() {
64
+ const response = await host.host.get(host.host.createUrl("signals"));
65
+ return await response.json();
66
+ }
67
+ signals.list = list;
68
+ /**
69
+ * Creates a persistent connection to stream signal events of a specific type.
70
+ *
71
+ * This establishes a Server-Sent Events (SSE) connection that will receive
72
+ * all signals sent to the specified signal channel. The connection remains
73
+ * open until explicitly closed.
74
+ *
75
+ * @template V - The type of the payload that will be received
76
+ * @param signal - The signal channel name to subscribe to
77
+ * @param f - Callback function to handle received payloads
78
+ * @returns EventSource instance for managing the connection
79
+ *
80
+ * @example
81
+ * ```typescript
82
+ * // Listen for user interaction events
83
+ * interface UserAction {
84
+ * type: 'click' | 'hover' | 'scroll';
85
+ * position: [number, number];
86
+ * timestamp: number;
87
+ * }
88
+ *
89
+ * const userEventStream = signals.stream<UserAction>(
90
+ * "user-interactions",
91
+ * async (action) => {
92
+ * console.log(`User ${action.type} at`, action.position);
93
+ * // Process the user action...
94
+ * }
95
+ * );
96
+ *
97
+ * // Later, close the stream
98
+ * userEventStream.close();
99
+ * ```
100
+ */
101
+ function stream(signal, f) {
102
+ const url = host.host.createUrl(`signals/${signal}`);
103
+ const es = new eventsource.EventSource(url);
104
+ es.addEventListener("message", async (event) => {
105
+ try {
106
+ const payload = JSON.parse(event.data);
107
+ await f(payload);
108
+ }
109
+ catch (error) {
110
+ console.error(`Error processing signal ${signal}:`, error);
111
+ }
112
+ });
113
+ return es;
114
+ }
115
+ signals.stream = stream;
116
+ /**
117
+ * Sends a signal payload to all subscribers listening to the specified signal channel.
118
+ *
119
+ * This broadcasts the payload to all active EventSource connections that are
120
+ * streaming the same signal type. The operation is asynchronous and will
121
+ * complete once the signal has been distributed to all subscribers.
122
+ *
123
+ * @template V - The type of the payload being sent
124
+ * @param signal - The signal channel name to broadcast to
125
+ * @param payload - The data to send to all subscribers
126
+ *
127
+ * @throws Will throw an error if the signal broadcast fails
128
+ *
129
+ * @example
130
+ * ```typescript
131
+ * // Send a notification to all mod windows
132
+ * await signals.send("notifications", {
133
+ * type: "info",
134
+ * title: "Update Available",
135
+ * message: "A new version of the character is available",
136
+ * timestamp: Date.now()
137
+ * });
138
+ *
139
+ * // Send real-time data updates
140
+ * await signals.send("data-update", {
141
+ * source: "weather-api",
142
+ * temperature: 72,
143
+ * conditions: "sunny"
144
+ * });
145
+ *
146
+ * // Trigger actions in mods
147
+ * await signals.send("vrm-action", {
148
+ * action: "wave",
149
+ * target: vrmEntity,
150
+ * duration: 2000
151
+ * });
152
+ * ```
153
+ */
154
+ async function send(signal, payload) {
155
+ await host.host.post(host.host.createUrl(`signals/${signal}`), payload);
156
+ }
157
+ signals.send = send;
158
+ })(exports.signals || (exports.signals = {}));
@@ -0,0 +1,158 @@
1
+ import { host } from './host.js';
2
+ import { EventSource } from 'eventsource';
3
+
4
+ /**
5
+ * Signals API namespace for cross-process communication.
6
+ *
7
+ * Provides a pub/sub mechanism that allows external processes to communicate
8
+ * with the Desktop Homunculus application and its mods through event streaming.
9
+ *
10
+ * Key features:
11
+ * - Real-time event streaming via Server-Sent Events (SSE)
12
+ * - Signal broadcasting to multiple subscribers
13
+ * - Type-safe payload handling
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * // Listen for custom events from external processes
18
+ * const eventSource = signals.stream<{action: string, data: any}>(
19
+ * "my-custom-signal",
20
+ * (payload) => {
21
+ * console.log("Received signal:", payload.action, payload.data);
22
+ * }
23
+ * );
24
+ *
25
+ * // Send signals to all listeners
26
+ * await signals.send("my-custom-signal", {
27
+ * action: "update",
28
+ * data: { message: "Hello from external app!" }
29
+ * });
30
+ *
31
+ * // Clean up when done
32
+ * eventSource.close();
33
+ * ```
34
+ */
35
+ var signals;
36
+ (function (signals) {
37
+ /**
38
+ * Lists all active signal channels and their subscriber counts.
39
+ *
40
+ * Returns information about every signal channel that has been created.
41
+ * Useful for debugging, monitoring, and discovering available channels.
42
+ *
43
+ * @returns Array of active signal channel information
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * // List all active signal channels
48
+ * const channels = await signals.list();
49
+ * for (const ch of channels) {
50
+ * console.log(`${ch.signal}: ${ch.subscribers} subscribers`);
51
+ * }
52
+ *
53
+ * // Check if a specific signal has listeners before sending
54
+ * const channels = await signals.list();
55
+ * const target = channels.find(ch => ch.signal === "my-signal");
56
+ * if (target && target.subscribers > 0) {
57
+ * await signals.send("my-signal", { data: "hello" });
58
+ * }
59
+ * ```
60
+ */
61
+ async function list() {
62
+ const response = await host.get(host.createUrl("signals"));
63
+ return await response.json();
64
+ }
65
+ signals.list = list;
66
+ /**
67
+ * Creates a persistent connection to stream signal events of a specific type.
68
+ *
69
+ * This establishes a Server-Sent Events (SSE) connection that will receive
70
+ * all signals sent to the specified signal channel. The connection remains
71
+ * open until explicitly closed.
72
+ *
73
+ * @template V - The type of the payload that will be received
74
+ * @param signal - The signal channel name to subscribe to
75
+ * @param f - Callback function to handle received payloads
76
+ * @returns EventSource instance for managing the connection
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * // Listen for user interaction events
81
+ * interface UserAction {
82
+ * type: 'click' | 'hover' | 'scroll';
83
+ * position: [number, number];
84
+ * timestamp: number;
85
+ * }
86
+ *
87
+ * const userEventStream = signals.stream<UserAction>(
88
+ * "user-interactions",
89
+ * async (action) => {
90
+ * console.log(`User ${action.type} at`, action.position);
91
+ * // Process the user action...
92
+ * }
93
+ * );
94
+ *
95
+ * // Later, close the stream
96
+ * userEventStream.close();
97
+ * ```
98
+ */
99
+ function stream(signal, f) {
100
+ const url = host.createUrl(`signals/${signal}`);
101
+ const es = new EventSource(url);
102
+ es.addEventListener("message", async (event) => {
103
+ try {
104
+ const payload = JSON.parse(event.data);
105
+ await f(payload);
106
+ }
107
+ catch (error) {
108
+ console.error(`Error processing signal ${signal}:`, error);
109
+ }
110
+ });
111
+ return es;
112
+ }
113
+ signals.stream = stream;
114
+ /**
115
+ * Sends a signal payload to all subscribers listening to the specified signal channel.
116
+ *
117
+ * This broadcasts the payload to all active EventSource connections that are
118
+ * streaming the same signal type. The operation is asynchronous and will
119
+ * complete once the signal has been distributed to all subscribers.
120
+ *
121
+ * @template V - The type of the payload being sent
122
+ * @param signal - The signal channel name to broadcast to
123
+ * @param payload - The data to send to all subscribers
124
+ *
125
+ * @throws Will throw an error if the signal broadcast fails
126
+ *
127
+ * @example
128
+ * ```typescript
129
+ * // Send a notification to all mod windows
130
+ * await signals.send("notifications", {
131
+ * type: "info",
132
+ * title: "Update Available",
133
+ * message: "A new version of the character is available",
134
+ * timestamp: Date.now()
135
+ * });
136
+ *
137
+ * // Send real-time data updates
138
+ * await signals.send("data-update", {
139
+ * source: "weather-api",
140
+ * temperature: 72,
141
+ * conditions: "sunny"
142
+ * });
143
+ *
144
+ * // Trigger actions in mods
145
+ * await signals.send("vrm-action", {
146
+ * action: "wave",
147
+ * target: vrmEntity,
148
+ * duration: 2000
149
+ * });
150
+ * ```
151
+ */
152
+ async function send(signal, payload) {
153
+ await host.post(host.createUrl(`signals/${signal}`), payload);
154
+ }
155
+ signals.send = send;
156
+ })(signals || (signals = {}));
157
+
158
+ export { signals };
@@ -0,0 +1,48 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Speech utilities for converting phoneme data to Timeline keyframes.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { speech, Vrm } from "@hmcs/sdk";
9
+ *
10
+ * const keyframes = speech.fromPhonemes([
11
+ * ["aa", 0.1],
12
+ * [null, 0.05],
13
+ * ["oh", 0.12],
14
+ * ]);
15
+ * const vrm = await Vrm.findByName("MyAvatar");
16
+ * await vrm.speakWithTimeline(wavData, keyframes);
17
+ * ```
18
+ */
19
+ exports.speech = void 0;
20
+ (function (speech) {
21
+ /**
22
+ * Creates timeline keyframes from a simple phoneme list.
23
+ *
24
+ * Each entry is a tuple of [expression_name | null, duration_seconds].
25
+ * A null expression name creates a silent keyframe.
26
+ *
27
+ * @param phonemes - Array of [expression_name, duration] tuples.
28
+ * @returns An array of timeline keyframes.
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * const keyframes = speech.fromPhonemes([
33
+ * ["aa", 0.1],
34
+ * [null, 0.05],
35
+ * ["oh", 0.12],
36
+ * ]);
37
+ * ```
38
+ */
39
+ function fromPhonemes(phonemes) {
40
+ return phonemes.map(([name, duration]) => {
41
+ if (name) {
42
+ return { duration, targets: { [name]: 1.0 } };
43
+ }
44
+ return { duration };
45
+ });
46
+ }
47
+ speech.fromPhonemes = fromPhonemes;
48
+ })(exports.speech || (exports.speech = {}));
package/dist/speech.js ADDED
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Speech utilities for converting phoneme data to Timeline keyframes.
3
+ *
4
+ * @example
5
+ * ```typescript
6
+ * import { speech, Vrm } from "@hmcs/sdk";
7
+ *
8
+ * const keyframes = speech.fromPhonemes([
9
+ * ["aa", 0.1],
10
+ * [null, 0.05],
11
+ * ["oh", 0.12],
12
+ * ]);
13
+ * const vrm = await Vrm.findByName("MyAvatar");
14
+ * await vrm.speakWithTimeline(wavData, keyframes);
15
+ * ```
16
+ */
17
+ var speech;
18
+ (function (speech) {
19
+ /**
20
+ * Creates timeline keyframes from a simple phoneme list.
21
+ *
22
+ * Each entry is a tuple of [expression_name | null, duration_seconds].
23
+ * A null expression name creates a silent keyframe.
24
+ *
25
+ * @param phonemes - Array of [expression_name, duration] tuples.
26
+ * @returns An array of timeline keyframes.
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * const keyframes = speech.fromPhonemes([
31
+ * ["aa", 0.1],
32
+ * [null, 0.05],
33
+ * ["oh", 0.12],
34
+ * ]);
35
+ * ```
36
+ */
37
+ function fromPhonemes(phonemes) {
38
+ return phonemes.map(([name, duration]) => {
39
+ if (name) {
40
+ return { duration, targets: { [name]: 1.0 } };
41
+ }
42
+ return { duration };
43
+ });
44
+ }
45
+ speech.fromPhonemes = fromPhonemes;
46
+ })(speech || (speech = {}));
47
+
48
+ export { speech };
package/dist/utils.cjs ADDED
@@ -0,0 +1,13 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Resolves after `ms` milliseconds (non-blocking delay).
5
+ *
6
+ * @example
7
+ *
8
+ */
9
+ function sleep(ms) {
10
+ return new Promise((resolve) => setTimeout(resolve, ms));
11
+ }
12
+
13
+ exports.sleep = sleep;
package/dist/utils.js ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Resolves after `ms` milliseconds (non-blocking delay).
3
+ *
4
+ * @example
5
+ *
6
+ */
7
+ function sleep(ms) {
8
+ return new Promise((resolve) => setTimeout(resolve, ms));
9
+ }
10
+
11
+ export { sleep };