@starcried/starlite-inochi2d 0.1.0-alpha.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/dialogue.js CHANGED
@@ -1,4 +1,32 @@
1
1
  // ../core/dist/dialogue.js
2
+ function resolveDialogueContext(input) {
3
+ if (!input || typeof input !== "object" || Array.isArray(input))
4
+ throw new Error("dialogue context must be an object");
5
+ const value = input;
6
+ if (Object.keys(value).some((key) => !["id", "lines", "animation", "triggers", "mode", "order"].includes(key)))
7
+ throw new Error("dialogue context has an unknown field");
8
+ const text = (item, maximum, field) => {
9
+ if (typeof item !== "string" || !item.trim() || new TextEncoder().encode(item.trim()).byteLength > maximum)
10
+ throw new Error(`dialogue context ${field} is invalid`);
11
+ return item.trim();
12
+ };
13
+ const id = text(value.id, 2048, "id");
14
+ const lines = resolveDialogueSentences({ lines: value.lines }, [], "dialogue context").lines;
15
+ if (!Array.isArray(value.triggers) || !value.triggers.length || value.triggers.length > 2 || new Set(value.triggers).size !== value.triggers.length || value.triggers.some((trigger) => trigger !== "click" && trigger !== "idle"))
16
+ throw new Error("dialogue context triggers are invalid");
17
+ if (value.mode !== "replace" && value.mode !== "merge")
18
+ throw new Error("dialogue context mode is invalid");
19
+ if (value.order !== "sequential" && value.order !== "random")
20
+ throw new Error("dialogue context order is invalid");
21
+ return {
22
+ id,
23
+ lines,
24
+ ...value.animation !== void 0 ? { animation: text(value.animation, 1024, "animation") } : {},
25
+ triggers: ["click", "idle"].filter((trigger) => value.triggers.includes(trigger)),
26
+ mode: value.mode,
27
+ order: value.order
28
+ };
29
+ }
2
30
  function resolveDialogueSentences(input, animations, field) {
3
31
  const resolve = (value, path) => {
4
32
  if (!Array.isArray(value) || value.length < 1 || value.length > 128) {
@@ -40,6 +68,10 @@ var DialogueScheduler = class {
40
68
  #started = false;
41
69
  #enterDueAt;
42
70
  #nextIdleAt;
71
+ #context = null;
72
+ #contextSignature = "null";
73
+ #contextEntries = [];
74
+ #contextCursor = 0;
43
75
  constructor(config, random) {
44
76
  this.#config = config;
45
77
  this.#random = random;
@@ -54,6 +86,25 @@ var DialogueScheduler = class {
54
86
  }
55
87
  this.#scheduleIdle(timestampMs);
56
88
  }
89
+ /** Preserve the model and first entrance while replacing host-owned text. */
90
+ setContext(input, timestampMs) {
91
+ if (!Number.isFinite(timestampMs))
92
+ throw new Error("dialogue context timestamp is invalid");
93
+ const context = input === null ? null : resolveDialogueContext(input);
94
+ const signature = JSON.stringify(context);
95
+ if (signature === this.#contextSignature)
96
+ return false;
97
+ this.#context = context;
98
+ this.#contextSignature = signature;
99
+ this.#contextCursor = 0;
100
+ this.#contextEntries = context ? [
101
+ ...context.lines.map((line) => ({ line, ...context.animation !== void 0 ? { animation: context.animation } : {}, triggers: context.triggers })),
102
+ ...context.mode === "merge" ? context.triggers.flatMap((scene) => this.#entries(scene)) : []
103
+ ] : [];
104
+ if (this.#started)
105
+ this.#scheduleIdle(timestampMs);
106
+ return true;
107
+ }
57
108
  poll(timestampMs, foregroundActive) {
58
109
  if (!this.#started || foregroundActive) {
59
110
  return void 0;
@@ -64,8 +115,8 @@ var DialogueScheduler = class {
64
115
  this.#scheduleIdle(timestampMs + action.durationMs);
65
116
  return action;
66
117
  }
67
- if (this.#config.idle && this.#nextIdleAt !== void 0 && timestampMs >= this.#nextIdleAt) {
68
- const action = this.#action("idle", this.#config.idle);
118
+ if ((this.#config.idle || this.#context?.triggers.includes("idle")) && this.#nextIdleAt !== void 0 && timestampMs >= this.#nextIdleAt) {
119
+ const action = this.#contextAction("idle") ?? this.#action("idle", this.#config.idle);
69
120
  this.#scheduleIdle(timestampMs + action.durationMs);
70
121
  return action;
71
122
  }
@@ -73,10 +124,10 @@ var DialogueScheduler = class {
73
124
  }
74
125
  triggerClick(timestampMs) {
75
126
  this.deferIdle(timestampMs);
76
- if (!this.#config.click) {
127
+ if (!this.#config.click && !this.#context?.triggers.includes("click")) {
77
128
  return void 0;
78
129
  }
79
- const action = this.#action("click", this.#config.click);
130
+ const action = this.#contextAction("click") ?? this.#action("click", this.#config.click);
80
131
  this.#scheduleIdle(timestampMs + action.durationMs);
81
132
  return action;
82
133
  }
@@ -86,6 +137,39 @@ var DialogueScheduler = class {
86
137
  this.#scheduleIdle(timestampMs);
87
138
  }
88
139
  }
140
+ #entries(scene) {
141
+ const config = this.#config[scene];
142
+ if (!config)
143
+ return [];
144
+ const animations = config.animations?.length ? config.animations : config.animation ? [config.animation] : [];
145
+ if (config.linesByAnimation)
146
+ return animations.flatMap((animation) => (config.linesByAnimation[animation] ?? []).map((line) => ({ line, animation, durationMs: config.durationMs, triggers: [scene] })));
147
+ return (animations.length ? animations : [void 0]).flatMap((animation) => (config.lines ?? []).map((line) => ({ line, ...animation !== void 0 ? { animation } : {}, durationMs: config.durationMs, triggers: [scene] })));
148
+ }
149
+ #contextAction(scene) {
150
+ const context = this.#context;
151
+ if (!context?.triggers.includes(scene))
152
+ return void 0;
153
+ let entry;
154
+ if (context.order === "random") {
155
+ const eligible = this.#contextEntries.filter((item) => item.triggers.includes(scene));
156
+ entry = eligible[Math.floor(this.#unitRandom() * eligible.length)];
157
+ } else {
158
+ for (let offset = 0; offset < this.#contextEntries.length; offset++) {
159
+ const index = (this.#contextCursor + offset) % this.#contextEntries.length;
160
+ const item = this.#contextEntries[index];
161
+ if (!item.triggers.includes(scene))
162
+ continue;
163
+ entry = item;
164
+ this.#contextCursor = (index + 1) % this.#contextEntries.length;
165
+ break;
166
+ }
167
+ }
168
+ if (!entry)
169
+ return void 0;
170
+ const config = this.#config[scene];
171
+ return { scene, line: entry.line, ...entry.animation !== void 0 ? { animation: entry.animation } : {}, durationMs: entry.durationMs ?? (config ? config.durationMs : 4e3) };
172
+ }
89
173
  #action(scene, config) {
90
174
  const chooseAnimation = () => config.animations?.length ? config.animations[Math.floor(this.#unitRandom() * config.animations.length)] : config.animation;
91
175
  const animation = config.linesByAnimation ? chooseAnimation() : void 0;
@@ -105,11 +189,11 @@ var DialogueScheduler = class {
105
189
  return;
106
190
  }
107
191
  const idle = this.#config.idle;
108
- if (!idle) {
192
+ if (!idle && !this.#context?.triggers.includes("idle")) {
109
193
  this.#nextIdleAt = void 0;
110
194
  return;
111
195
  }
112
- const interval = idle.intervalMinMs + (idle.intervalMaxMs - idle.intervalMinMs) * this.#unitRandom();
196
+ const interval = (idle ? idle.intervalMinMs : 3e4) + ((idle ? idle.intervalMaxMs : 6e4) - (idle ? idle.intervalMinMs : 3e4)) * this.#unitRandom();
113
197
  this.#nextIdleAt = timestampMs + interval;
114
198
  }
115
199
  #unitRandom() {
@@ -125,10 +209,12 @@ var DialogueScheduler = class {
125
209
  var DialogueBubble = class {
126
210
  element;
127
211
  #host;
212
+ #anchor;
128
213
  #until = 0;
129
214
  #timeout;
130
- constructor(host) {
215
+ constructor(host, anchor) {
131
216
  this.#host = host;
217
+ this.#anchor = anchor;
132
218
  this.element = document.createElement("div");
133
219
  this.element.className = "model-widget__bubble";
134
220
  this.element.hidden = true;
@@ -170,8 +256,20 @@ var DialogueBubble = class {
170
256
  return;
171
257
  const host = this.#host.getBoundingClientRect(), bubble = this.element.getBoundingClientRect();
172
258
  const width = Math.max(1, document.documentElement.clientWidth || window.innerWidth);
173
- const margin = 12, centered = host.left + host.width / 2 - bubble.width / 2;
174
- this.element.dataset.modelPlacement = host.top >= bubble.height + margin * 2 ? "above" : "below";
259
+ const candidate = this.#anchor?.();
260
+ const anchor = candidate && Number.isFinite(candidate.x) && Number.isFinite(candidate.y) ? candidate : void 0;
261
+ const margin = 12, centered = host.left + (anchor?.x ?? host.width / 2) - bubble.width / 2;
262
+ const above = host.top + (anchor?.y ?? 0) >= bubble.height + margin * 2;
263
+ this.element.dataset.modelPlacement = above ? "above" : "below";
264
+ if (anchor) {
265
+ const height = Math.max(1, document.documentElement.clientHeight || window.innerHeight);
266
+ const preferredTop = above ? host.top + anchor.y - margin - bubble.height : host.top + host.height + margin;
267
+ const top = Math.max(margin, Math.min(Math.max(margin, height - bubble.height - margin), preferredTop));
268
+ Object.assign(this.element.style, { left: `${anchor.x}px`, top: `${top - host.top}px`, bottom: "auto" });
269
+ } else {
270
+ for (const property of ["left", "top", "bottom"])
271
+ this.element.style.removeProperty(property);
272
+ }
175
273
  const left = Math.max(margin, Math.min(Math.max(margin, width - bubble.width - margin), centered));
176
274
  this.element.style.setProperty("--model-bubble-shift-x", `${Math.round(left - centered)}px`);
177
275
  }
@@ -186,6 +284,8 @@ function observePassThroughClicks(surface, onClick) {
186
284
  let down;
187
285
  let ready;
188
286
  const inside = (event) => {
287
+ if (event.composedPath().some((target) => target instanceof Element && target.matches("[data-starlite-quick-settings],[data-starlite-widget-restore]")))
288
+ return false;
189
289
  const rect = surface.getBoundingClientRect();
190
290
  return rect.width > 0 && rect.height > 0 && event.clientX >= rect.left && event.clientX < rect.right && event.clientY >= rect.top && event.clientY < rect.bottom;
191
291
  };
@@ -242,5 +342,6 @@ export {
242
342
  DialogueBubble,
243
343
  DialogueScheduler,
244
344
  observePassThroughClicks,
345
+ resolveDialogueContext,
245
346
  resolveDialogueSentences
246
347
  };
@@ -1 +1 @@
1
- {"version":3,"file":"dialogue.js","sourceRoot":"","sources":["../src/dialogue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,wBAAwB,EAAE,wBAAwB,EAAuB,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"dialogue.js","sourceRoot":"","sources":["../src/dialogue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,wBAAwB,EAA6C,MAAM,0BAA0B,CAAC"}
package/dist/hit-mask.js CHANGED
@@ -18,8 +18,8 @@ var RenderedHitMask = class {
18
18
  if (!listener)
19
19
  this.#surface = void 0;
20
20
  }
21
- capture(canvas, timestamp) {
22
- if (!this.#listener || timestamp - this.#lastTime < 50)
21
+ capture(canvas, timestamp, force = false) {
22
+ if (!this.#listener || !force && timestamp - this.#lastTime < 50)
23
23
  return;
24
24
  this.#lastTime = timestamp;
25
25
  const rect = canvas.getBoundingClientRect();
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
+ export { resolveLocale, type StarLiteLocale } from "./locale.js";
1
2
  export { validateInochi2DWidgetConfig } from "./config.js";
3
+ export { QuickSettingsMenu, type QuickSettingsOptions, type QuickSettingItem } from "./quick-settings.js";
2
4
  export type { AmbientAnimationConfig, AnimationClip, AnimationInterpolation, AnimationKeyframe, AnimationLane, AnimationPlaybackMode, AnimationPlaybackOptions, AnimationPlaybackResult, DialogueConfig, DialogueSceneConfig, DialogueSceneName, EnterDialogueSceneConfig, IdleDialogueSceneConfig, Inochi2dWasmRuntime, ModelAnimationInfo, ParameterAxis, ParameterBinding, ParameterIds, ParameterTarget, ResolvedParameterBindings, ResolvedParameterTarget, ResolvedWidgetConfig, RuntimeFactory, WidgetConfig, WidgetController, WidgetStatus, } from "./types.js";
3
5
  /** Mount an Inochi2D widget and resolve once it is running or in fallback state. */
4
6
  export declare function mountInochi2DWidget(element: HTMLElement, config: import("./types.js").WidgetConfig, options?: import("@starcried/starlite-core").MountOptions): Promise<import("./types.js").WidgetController>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAC;AAE3D,YAAY,EACV,sBAAsB,EACtB,aAAa,EACb,sBAAsB,EACtB,iBAAiB,EACjB,aAAa,EACb,qBAAqB,EACrB,wBAAwB,EACxB,uBAAuB,EACvB,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,wBAAwB,EACxB,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,eAAe,EACf,yBAAyB,EACzB,uBAAuB,EACvB,oBAAoB,EACpB,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,YAAY,GACb,MAAM,YAAY,CAAC;AAEpB,oFAAoF;AACpF,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,OAAO,YAAY,EAAE,YAAY,EACzC,OAAO,GAAE,OAAO,0BAA0B,EAAE,YAAiB,GAC5D,OAAO,CAAC,OAAO,YAAY,EAAE,gBAAgB,CAAC,CAEhD;AAED,iFAAiF;AACjF,eAAO,MAAM,gBAAgB,4BAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAIjE,OAAO,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,KAAK,oBAAoB,EAAE,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE1G,YAAY,EACV,sBAAsB,EACtB,aAAa,EACb,sBAAsB,EACtB,iBAAiB,EACjB,aAAa,EACb,qBAAqB,EACrB,wBAAwB,EACxB,uBAAuB,EACvB,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,wBAAwB,EACxB,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,eAAe,EACf,yBAAyB,EACzB,uBAAuB,EACvB,oBAAoB,EACpB,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,YAAY,GACb,MAAM,YAAY,CAAC;AAEpB,oFAAoF;AACpF,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,OAAO,YAAY,EAAE,YAAY,EACzC,OAAO,GAAE,OAAO,0BAA0B,EAAE,YAAiB,GAC5D,OAAO,CAAC,OAAO,YAAY,EAAE,gBAAgB,CAAC,CAEhD;AAED,iFAAiF;AACjF,eAAO,MAAM,gBAAgB,4BAAsB,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,8 @@
1
+ export { resolveLocale } from "./locale.js";
1
2
  import { mountWithDependencies } from "./controller.js";
2
3
  import { createDefaultDependencies } from "./dependencies.js";
3
4
  export { validateInochi2DWidgetConfig } from "./config.js";
5
+ export { QuickSettingsMenu } from "./quick-settings.js";
4
6
  /** Mount an Inochi2D widget and resolve once it is running or in fallback state. */
5
7
  export async function mountInochi2DWidget(element, config, options = {}) {
6
8
  return mountWithDependencies(element, config, createDefaultDependencies(), options.signal);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,OAAO,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAC;AA+B3D,oFAAoF;AACpF,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,OAAoB,EACpB,MAAyC,EACzC,OAAO,GAAoD,EAAE;IAE7D,OAAO,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,yBAAyB,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;AAC7F,CAAC;AAED,iFAAiF;AACjF,MAAM,CAAC,MAAM,gBAAgB,GAAG,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAuB,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,OAAO,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAoD,MAAM,qBAAqB,CAAC;AA+B1G,oFAAoF;AACpF,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,OAAoB,EACpB,MAAyC,EACzC,OAAO,GAAoD,EAAE;IAE7D,OAAO,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,yBAAyB,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;AAC7F,CAAC;AAED,iFAAiF;AACjF,MAAM,CAAC,MAAM,gBAAgB,GAAG,mBAAmB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { resolveLocale, validateLocale, type StarLiteLocale } from "@starcried/starlite-core";
2
+ //# sourceMappingURL=locale.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locale.d.ts","sourceRoot":"","sources":["../src/locale.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,0BAA0B,CAAC"}
package/dist/locale.js ADDED
@@ -0,0 +1,16 @@
1
+ // ../core/dist/locale.js
2
+ function resolveLocale(language) {
3
+ const value = Array.isArray(language) ? language[0] : language;
4
+ if (typeof value !== "string" || !value.trim())
5
+ return "zh-CN";
6
+ return /^zh(?:[-_]|$)/i.test(value.trim()) ? "zh-CN" : "en";
7
+ }
8
+ function validateLocale(value) {
9
+ if (value !== void 0 && value !== "zh-CN" && value !== "en") {
10
+ throw new Error("locale must be zh-CN or en");
11
+ }
12
+ }
13
+ export {
14
+ resolveLocale,
15
+ validateLocale
16
+ };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locale.js","sourceRoot":"","sources":["../src/locale.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAuB,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { PerformanceOverlay, validatePerformanceConfig } from "@starcried/starlite-core";
2
+ //# sourceMappingURL=performance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"performance.d.ts","sourceRoot":"","sources":["../src/performance.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,114 @@
1
+ // ../core/dist/performance.js
2
+ function validatePerformanceConfig(value) {
3
+ if (value === void 0)
4
+ return;
5
+ if (!value || typeof value !== "object" || Array.isArray(value) || Object.keys(value).some((key) => key !== "show") || "show" in value && value.show !== void 0 && typeof value.show !== "boolean") {
6
+ throw new Error("performance must be an object with an optional boolean show");
7
+ }
8
+ }
9
+ var FrameSamples = class {
10
+ #values;
11
+ #next = 0;
12
+ #size = 0;
13
+ constructor(capacity = 240) {
14
+ if (!Number.isSafeInteger(capacity) || capacity < 1)
15
+ throw new Error("invalid sample capacity");
16
+ this.#values = new Float64Array(capacity);
17
+ }
18
+ add(value) {
19
+ if (!Number.isFinite(value) || value < 0)
20
+ return;
21
+ this.#values[this.#next] = value;
22
+ this.#next = (this.#next + 1) % this.#values.length;
23
+ this.#size = Math.min(this.#size + 1, this.#values.length);
24
+ }
25
+ reset() {
26
+ this.#next = 0;
27
+ this.#size = 0;
28
+ }
29
+ values() {
30
+ return Array.from({ length: this.#size }, (_, i) => this.#values[(this.#next - this.#size + i + this.#values.length) % this.#values.length]);
31
+ }
32
+ };
33
+ var PerformanceOverlay = class {
34
+ element;
35
+ #intervals = new FrameSamples();
36
+ #cpu = new FrameSamples();
37
+ #previous;
38
+ #lastPaint;
39
+ #status = "loading";
40
+ #destroyed = false;
41
+ constructor(host) {
42
+ this.element = document.createElement("output");
43
+ this.element.className = "model-widget__performance";
44
+ this.element.setAttribute("data-model-performance", "");
45
+ this.element.setAttribute("aria-label", "StarLite model performance");
46
+ this.element.setAttribute("aria-live", "off");
47
+ this.element.title = "Rendered FPS and frame-interval p95; CPU p95 is the wall time of model update and WebGL submission, including any driver waits, not measured GPU execution or CPU utilization. The latest 240 frames are sampled. Pausing resets measurements.";
48
+ Object.assign(this.element.style, {
49
+ position: "absolute",
50
+ left: "8px",
51
+ bottom: "8px",
52
+ zIndex: "2",
53
+ maxWidth: "calc(100% - 16px)",
54
+ boxSizing: "border-box",
55
+ padding: "6px 8px",
56
+ borderRadius: "6px",
57
+ background: "rgba(15, 23, 42, .86)",
58
+ color: "#f1f5f9",
59
+ font: "11px/1.5 ui-monospace, SFMono-Regular, Consolas, monospace",
60
+ whiteSpace: "pre-line",
61
+ overflowWrap: "anywhere",
62
+ pointerEvents: "none",
63
+ userSelect: "none",
64
+ textAlign: "left"
65
+ });
66
+ host.append(this.element);
67
+ this.#paintStatus();
68
+ }
69
+ setStatus(status) {
70
+ if (this.#destroyed || status === this.#status)
71
+ return;
72
+ this.#status = status;
73
+ this.#intervals.reset();
74
+ this.#cpu.reset();
75
+ this.#previous = void 0;
76
+ this.#lastPaint = void 0;
77
+ this.#paintStatus();
78
+ }
79
+ recordFrame(timestampMs, cpuMs, details = {}) {
80
+ if (this.#destroyed || this.#status !== "running" || !Number.isFinite(timestampMs))
81
+ return;
82
+ if (this.#previous !== void 0 && timestampMs > this.#previous)
83
+ this.#intervals.add(timestampMs - this.#previous);
84
+ this.#previous = timestampMs;
85
+ this.#cpu.add(cpuMs);
86
+ if (this.#lastPaint !== void 0 && timestampMs - this.#lastPaint < 500)
87
+ return;
88
+ this.#lastPaint = timestampMs;
89
+ const intervals = this.#intervals.values(), cpu = this.#cpu.values();
90
+ const sum = intervals.reduce((total, value) => total + value, 0);
91
+ const fps = sum > 0 ? `${(1e3 * intervals.length / sum).toFixed(1)} FPS` : "FPS warming up";
92
+ const p95 = (values) => values.length ? values.sort((a, b) => a - b)[Math.ceil(values.length * 0.95) - 1].toFixed(1) : "\u2014";
93
+ const lines = [fps, `Frame p95 ${p95(intervals)} ms`, `CPU p95 ${p95(cpu)} ms`];
94
+ if (Number.isFinite(details.calls) && Number.isFinite(details.triangles)) {
95
+ lines.push(`${details.calls} calls \xB7 ${details.triangles.toLocaleString("en-US")} tris`);
96
+ }
97
+ this.element.textContent = lines.join("\n");
98
+ this.element.dataset.modelPerformanceStatus = this.#status;
99
+ }
100
+ destroy() {
101
+ if (this.#destroyed)
102
+ return;
103
+ this.#destroyed = true;
104
+ this.element.remove();
105
+ }
106
+ #paintStatus() {
107
+ this.element.textContent = `StarLite \xB7 ${this.#status}`;
108
+ this.element.dataset.modelPerformanceStatus = this.#status;
109
+ }
110
+ };
111
+ export {
112
+ PerformanceOverlay,
113
+ validatePerformanceConfig
114
+ };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"performance.js","sourceRoot":"","sources":["../src/performance.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,OAAO,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { QuickSettingsMenu, type QuickSettingsOptions, type QuickSettingItem } from "@starcried/starlite-core";
2
+ //# sourceMappingURL=quick-settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quick-settings.d.ts","sourceRoot":"","sources":["../src/quick-settings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,oBAAoB,EAAE,KAAK,gBAAgB,EAAE,MAAM,0BAA0B,CAAC"}