@oxy.so/bloom 7.1.1 → 7.1.4
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/assets/character-runtime/README.md +114 -19
- package/assets/character-runtime/authored-parts.mjs +754 -0
- package/assets/character-runtime/catalog-parts.mjs +362 -0
- package/assets/character-runtime/character-recipe.mjs +247 -0
- package/assets/character-runtime/clippo-geometry.mjs +679 -0
- package/assets/character-runtime/controller-mode.mjs +208 -0
- package/assets/character-runtime/cyclops-geometry.mjs +180 -0
- package/assets/character-runtime/legacy-engine.mjs +406 -54
- package/assets/character-runtime/legacy-geometry.mjs +242 -85
- package/assets/character-runtime/legacy-worker.mjs +82 -23
- package/assets/character-runtime/managed-avatar.mjs +12 -17
- package/assets/character-runtime/migrated-contours.mjs +2067 -0
- package/assets/character-runtime/migrated-faces.mjs +59 -0
- package/assets/character-runtime/pose-transition.mjs +523 -0
- package/assets/character-runtime/preparation-cache.mjs +60 -0
- package/assets/character-runtime/render-budget.mjs +5 -3
- package/assets/character-runtime/render-errors.mjs +180 -0
- package/assets/character-runtime/resolution.mjs +10 -0
- package/assets/character-runtime/runtime.mjs +744 -295
- package/assets/character-runtime/sha256.mjs +44 -0
- package/assets/character-runtime/shared-programs.mjs +534 -0
- package/assets/character-runtime/shared-surface.mjs +490 -0
- package/assets/character-runtime/shared-textures.mjs +420 -0
- package/assets/character-runtime/thumbnails/eyes/todd.png +0 -0
- package/docs/adoption-matrix.mdx +2 -2
- package/docs/agent-avatar.mdx +45 -8
- package/docs/agent-creator.mdx +13 -3
- package/docs/bottom-sheet.mdx +1 -1
- package/lib/commonjs/agent-avatar/AgentAvatar.js +1 -1
- package/lib/commonjs/agent-avatar/AgentAvatar.js.map +1 -1
- package/lib/commonjs/agent-avatar/CharacterAvatar.js +2 -1
- package/lib/commonjs/agent-avatar/CharacterAvatar.js.map +1 -1
- package/lib/commonjs/agent-avatar/character-colors.js +19 -0
- package/lib/commonjs/agent-avatar/character-colors.js.map +1 -0
- package/lib/commonjs/agent-avatar/character-shapes.js +106 -0
- package/lib/commonjs/agent-avatar/character-shapes.js.map +1 -0
- package/lib/commonjs/agent-avatar/config-character.js +4 -0
- package/lib/commonjs/agent-avatar/config-character.js.map +1 -1
- package/lib/commonjs/agent-avatar/legacy-recipe.js +19 -6
- package/lib/commonjs/agent-avatar/legacy-recipe.js.map +1 -1
- package/lib/commonjs/agent-creator/AgentCreatorBase.js +67 -107
- package/lib/commonjs/agent-creator/AgentCreatorBase.js.map +1 -1
- package/lib/commonjs/agent-creator/CharacterControls.js +23 -5
- package/lib/commonjs/agent-creator/CharacterControls.js.map +1 -1
- package/lib/commonjs/agent-creator/ClippoArtwork.js +63 -0
- package/lib/commonjs/agent-creator/ClippoArtwork.js.map +1 -0
- package/lib/commonjs/agent-creator/CyclopsArtwork.js +45 -0
- package/lib/commonjs/agent-creator/CyclopsArtwork.js.map +1 -0
- package/lib/commonjs/agent-creator/EmotionPicker.js +8 -1
- package/lib/commonjs/agent-creator/EmotionPicker.js.map +1 -1
- package/lib/commonjs/agent-creator/ShapeSilhouette.js +8 -1
- package/lib/commonjs/agent-creator/ShapeSilhouette.js.map +1 -1
- package/lib/commonjs/agent-creator/ToddArtwork.js +29 -0
- package/lib/commonjs/agent-creator/ToddArtwork.js.map +1 -0
- package/lib/commonjs/agent-creator/constants.js +16 -17
- package/lib/commonjs/agent-creator/constants.js.map +1 -1
- package/lib/commonjs/agent-creator/messages.js +1 -1
- package/lib/commonjs/agent-creator/messages.js.map +1 -1
- package/lib/commonjs/bottom-sheet/BottomSheetBase.js +33 -49
- package/lib/commonjs/bottom-sheet/BottomSheetBase.js.map +1 -1
- package/lib/commonjs/dialog/DialogBottomSheet.js +1 -1
- package/lib/commonjs/dialog/DialogBottomSheet.js.map +1 -1
- package/lib/commonjs/locale/translations/ar.js +1 -1
- package/lib/commonjs/locale/translations/ar.js.map +1 -1
- package/lib/commonjs/locale/translations/bn.js +1 -1
- package/lib/commonjs/locale/translations/bn.js.map +1 -1
- package/lib/commonjs/locale/translations/ca.js +1 -1
- package/lib/commonjs/locale/translations/ca.js.map +1 -1
- package/lib/commonjs/locale/translations/de.js +1 -1
- package/lib/commonjs/locale/translations/de.js.map +1 -1
- package/lib/commonjs/locale/translations/es.js +1 -1
- package/lib/commonjs/locale/translations/es.js.map +1 -1
- package/lib/commonjs/locale/translations/fr.js +1 -1
- package/lib/commonjs/locale/translations/fr.js.map +1 -1
- package/lib/commonjs/locale/translations/hi.js +1 -1
- package/lib/commonjs/locale/translations/hi.js.map +1 -1
- package/lib/commonjs/locale/translations/id.js +1 -1
- package/lib/commonjs/locale/translations/id.js.map +1 -1
- package/lib/commonjs/locale/translations/it.js +1 -1
- package/lib/commonjs/locale/translations/it.js.map +1 -1
- package/lib/commonjs/locale/translations/ja.js +1 -1
- package/lib/commonjs/locale/translations/ja.js.map +1 -1
- package/lib/commonjs/locale/translations/pt.js +1 -1
- package/lib/commonjs/locale/translations/pt.js.map +1 -1
- package/lib/commonjs/locale/translations/ru.js +1 -1
- package/lib/commonjs/locale/translations/ru.js.map +1 -1
- package/lib/commonjs/locale/translations/tr.js +1 -1
- package/lib/commonjs/locale/translations/tr.js.map +1 -1
- package/lib/commonjs/locale/translations/zh.js +1 -1
- package/lib/commonjs/locale/translations/zh.js.map +1 -1
- package/lib/commonjs/surface/SurfacePaint.js +17 -4
- package/lib/commonjs/surface/SurfacePaint.js.map +1 -1
- package/lib/module/agent-avatar/AgentAvatar.js +1 -1
- package/lib/module/agent-avatar/AgentAvatar.js.map +1 -1
- package/lib/module/agent-avatar/CharacterAvatar.js +2 -1
- package/lib/module/agent-avatar/CharacterAvatar.js.map +1 -1
- package/lib/module/agent-avatar/character-colors.js +15 -0
- package/lib/module/agent-avatar/character-colors.js.map +1 -0
- package/lib/module/agent-avatar/character-shapes.js +97 -0
- package/lib/module/agent-avatar/character-shapes.js.map +1 -0
- package/lib/module/agent-avatar/config-character.js +4 -0
- package/lib/module/agent-avatar/config-character.js.map +1 -1
- package/lib/module/agent-avatar/legacy-recipe.js +19 -6
- package/lib/module/agent-avatar/legacy-recipe.js.map +1 -1
- package/lib/module/agent-creator/AgentCreatorBase.js +69 -109
- package/lib/module/agent-creator/AgentCreatorBase.js.map +1 -1
- package/lib/module/agent-creator/CharacterControls.js +24 -6
- package/lib/module/agent-creator/CharacterControls.js.map +1 -1
- package/lib/module/agent-creator/ClippoArtwork.js +59 -0
- package/lib/module/agent-creator/ClippoArtwork.js.map +1 -0
- package/lib/module/agent-creator/CyclopsArtwork.js +41 -0
- package/lib/module/agent-creator/CyclopsArtwork.js.map +1 -0
- package/lib/module/agent-creator/EmotionPicker.js +8 -1
- package/lib/module/agent-creator/EmotionPicker.js.map +1 -1
- package/lib/module/agent-creator/ShapeSilhouette.js +8 -1
- package/lib/module/agent-creator/ShapeSilhouette.js.map +1 -1
- package/lib/module/agent-creator/ToddArtwork.js +25 -0
- package/lib/module/agent-creator/ToddArtwork.js.map +1 -0
- package/lib/module/agent-creator/constants.js +8 -16
- package/lib/module/agent-creator/constants.js.map +1 -1
- package/lib/module/agent-creator/messages.js +1 -1
- package/lib/module/agent-creator/messages.js.map +1 -1
- package/lib/module/bottom-sheet/BottomSheetBase.js +33 -49
- package/lib/module/bottom-sheet/BottomSheetBase.js.map +1 -1
- package/lib/module/dialog/DialogBottomSheet.js +1 -1
- package/lib/module/dialog/DialogBottomSheet.js.map +1 -1
- package/lib/module/locale/translations/ar.js +1 -1
- package/lib/module/locale/translations/ar.js.map +1 -1
- package/lib/module/locale/translations/bn.js +1 -1
- package/lib/module/locale/translations/bn.js.map +1 -1
- package/lib/module/locale/translations/ca.js +1 -1
- package/lib/module/locale/translations/ca.js.map +1 -1
- package/lib/module/locale/translations/de.js +1 -1
- package/lib/module/locale/translations/de.js.map +1 -1
- package/lib/module/locale/translations/es.js +1 -1
- package/lib/module/locale/translations/es.js.map +1 -1
- package/lib/module/locale/translations/fr.js +1 -1
- package/lib/module/locale/translations/fr.js.map +1 -1
- package/lib/module/locale/translations/hi.js +1 -1
- package/lib/module/locale/translations/hi.js.map +1 -1
- package/lib/module/locale/translations/id.js +1 -1
- package/lib/module/locale/translations/id.js.map +1 -1
- package/lib/module/locale/translations/it.js +1 -1
- package/lib/module/locale/translations/it.js.map +1 -1
- package/lib/module/locale/translations/ja.js +1 -1
- package/lib/module/locale/translations/ja.js.map +1 -1
- package/lib/module/locale/translations/pt.js +1 -1
- package/lib/module/locale/translations/pt.js.map +1 -1
- package/lib/module/locale/translations/ru.js +1 -1
- package/lib/module/locale/translations/ru.js.map +1 -1
- package/lib/module/locale/translations/tr.js +1 -1
- package/lib/module/locale/translations/tr.js.map +1 -1
- package/lib/module/locale/translations/zh.js +1 -1
- package/lib/module/locale/translations/zh.js.map +1 -1
- package/lib/module/surface/SurfacePaint.js +18 -5
- package/lib/module/surface/SurfacePaint.js.map +1 -1
- package/lib/typescript/commonjs/agent-avatar/CharacterAvatar.d.ts.map +1 -1
- package/lib/typescript/commonjs/agent-avatar/character-colors.d.ts +13 -0
- package/lib/typescript/commonjs/agent-avatar/character-colors.d.ts.map +1 -0
- package/lib/typescript/commonjs/agent-avatar/character-shapes.d.ts +19 -0
- package/lib/typescript/commonjs/agent-avatar/character-shapes.d.ts.map +1 -0
- package/lib/typescript/commonjs/agent-avatar/config-character.d.ts +4 -0
- package/lib/typescript/commonjs/agent-avatar/config-character.d.ts.map +1 -1
- package/lib/typescript/commonjs/agent-avatar/legacy-recipe.d.ts +2 -10
- package/lib/typescript/commonjs/agent-avatar/legacy-recipe.d.ts.map +1 -1
- package/lib/typescript/commonjs/agent-creator/AgentCreatorBase.d.ts.map +1 -1
- package/lib/typescript/commonjs/agent-creator/CharacterControls.d.ts +2 -1
- package/lib/typescript/commonjs/agent-creator/CharacterControls.d.ts.map +1 -1
- package/lib/typescript/commonjs/agent-creator/ClippoArtwork.d.ts +6 -0
- package/lib/typescript/commonjs/agent-creator/ClippoArtwork.d.ts.map +1 -0
- package/lib/typescript/commonjs/agent-creator/CyclopsArtwork.d.ts +5 -0
- package/lib/typescript/commonjs/agent-creator/CyclopsArtwork.d.ts.map +1 -0
- package/lib/typescript/commonjs/agent-creator/EmotionPicker.d.ts +1 -0
- package/lib/typescript/commonjs/agent-creator/EmotionPicker.d.ts.map +1 -1
- package/lib/typescript/commonjs/agent-creator/ShapeSilhouette.d.ts.map +1 -1
- package/lib/typescript/commonjs/agent-creator/ToddArtwork.d.ts +6 -0
- package/lib/typescript/commonjs/agent-creator/ToddArtwork.d.ts.map +1 -0
- package/lib/typescript/commonjs/agent-creator/constants.d.ts +7 -15
- package/lib/typescript/commonjs/agent-creator/constants.d.ts.map +1 -1
- package/lib/typescript/commonjs/agent-creator/messages.d.ts.map +1 -1
- package/lib/typescript/commonjs/bottom-sheet/BottomSheetBase.d.ts.map +1 -1
- package/lib/typescript/commonjs/bottom-sheet/types.d.ts +1 -0
- package/lib/typescript/commonjs/bottom-sheet/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/surface/SurfacePaint.d.ts.map +1 -1
- package/lib/typescript/module/agent-avatar/CharacterAvatar.d.ts.map +1 -1
- package/lib/typescript/module/agent-avatar/character-colors.d.ts +13 -0
- package/lib/typescript/module/agent-avatar/character-colors.d.ts.map +1 -0
- package/lib/typescript/module/agent-avatar/character-shapes.d.ts +19 -0
- package/lib/typescript/module/agent-avatar/character-shapes.d.ts.map +1 -0
- package/lib/typescript/module/agent-avatar/config-character.d.ts +4 -0
- package/lib/typescript/module/agent-avatar/config-character.d.ts.map +1 -1
- package/lib/typescript/module/agent-avatar/legacy-recipe.d.ts +2 -10
- package/lib/typescript/module/agent-avatar/legacy-recipe.d.ts.map +1 -1
- package/lib/typescript/module/agent-creator/AgentCreatorBase.d.ts.map +1 -1
- package/lib/typescript/module/agent-creator/CharacterControls.d.ts +2 -1
- package/lib/typescript/module/agent-creator/CharacterControls.d.ts.map +1 -1
- package/lib/typescript/module/agent-creator/ClippoArtwork.d.ts +6 -0
- package/lib/typescript/module/agent-creator/ClippoArtwork.d.ts.map +1 -0
- package/lib/typescript/module/agent-creator/CyclopsArtwork.d.ts +5 -0
- package/lib/typescript/module/agent-creator/CyclopsArtwork.d.ts.map +1 -0
- package/lib/typescript/module/agent-creator/EmotionPicker.d.ts +1 -0
- package/lib/typescript/module/agent-creator/EmotionPicker.d.ts.map +1 -1
- package/lib/typescript/module/agent-creator/ShapeSilhouette.d.ts.map +1 -1
- package/lib/typescript/module/agent-creator/ToddArtwork.d.ts +6 -0
- package/lib/typescript/module/agent-creator/ToddArtwork.d.ts.map +1 -0
- package/lib/typescript/module/agent-creator/constants.d.ts +7 -15
- package/lib/typescript/module/agent-creator/constants.d.ts.map +1 -1
- package/lib/typescript/module/agent-creator/messages.d.ts.map +1 -1
- package/lib/typescript/module/bottom-sheet/BottomSheetBase.d.ts.map +1 -1
- package/lib/typescript/module/bottom-sheet/types.d.ts +1 -0
- package/lib/typescript/module/bottom-sheet/types.d.ts.map +1 -1
- package/lib/typescript/module/surface/SurfacePaint.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/agent-avatar/AgentAvatar.tsx +1 -1
- package/src/agent-avatar/CharacterAvatar.tsx +4 -1
- package/src/agent-avatar/character-colors.ts +12 -0
- package/src/agent-avatar/character-shapes.ts +122 -0
- package/src/agent-avatar/config-character.ts +39 -6
- package/src/agent-avatar/legacy-recipe.ts +34 -6
- package/src/agent-creator/AgentCreatorBase.tsx +121 -152
- package/src/agent-creator/CharacterControls.tsx +39 -14
- package/src/agent-creator/ClippoArtwork.tsx +49 -0
- package/src/agent-creator/CyclopsArtwork.tsx +27 -0
- package/src/agent-creator/EmotionPicker.tsx +55 -16
- package/src/agent-creator/ShapeSilhouette.tsx +16 -1
- package/src/agent-creator/ToddArtwork.tsx +24 -0
- package/src/agent-creator/constants.ts +47 -14
- package/src/agent-creator/messages.ts +2 -1
- package/src/bottom-sheet/BottomSheetBase.tsx +24 -34
- package/src/bottom-sheet/types.ts +1 -0
- package/src/dialog/DialogBottomSheet.tsx +1 -1
- package/src/locale/translations/ar.ts +1 -1
- package/src/locale/translations/bn.ts +1 -1
- package/src/locale/translations/ca.ts +1 -1
- package/src/locale/translations/de.ts +1 -1
- package/src/locale/translations/es.ts +1 -1
- package/src/locale/translations/fr.ts +1 -1
- package/src/locale/translations/hi.ts +1 -1
- package/src/locale/translations/id.ts +1 -1
- package/src/locale/translations/it.ts +1 -1
- package/src/locale/translations/ja.ts +1 -1
- package/src/locale/translations/pt.ts +1 -1
- package/src/locale/translations/ru.ts +1 -1
- package/src/locale/translations/tr.ts +1 -1
- package/src/locale/translations/zh.ts +1 -1
- package/src/surface/SurfacePaint.tsx +14 -4
|
@@ -1,76 +1,429 @@
|
|
|
1
|
+
import {
|
|
2
|
+
NATIVE_PARTS,
|
|
3
|
+
ORIGINAL_PRESETS,
|
|
4
|
+
MIGRATED_SHAPE_IDS,
|
|
5
|
+
} from './character-recipe.mjs';
|
|
1
6
|
import createModule from './orbit-characters.mjs';
|
|
7
|
+
import { createControllerModeAdapter } from './controller-mode.mjs';
|
|
8
|
+
import {
|
|
9
|
+
createPreparationCache,
|
|
10
|
+
preparationKey,
|
|
11
|
+
} from './preparation-cache.mjs';
|
|
12
|
+
import { waitForSharedRender } from './shared-surface.mjs';
|
|
2
13
|
|
|
14
|
+
let controller;
|
|
3
15
|
const pool = new Map();
|
|
16
|
+
const authoredFacades = new Map();
|
|
4
17
|
const pending = new Map();
|
|
5
|
-
|
|
18
|
+
const prepared = createPreparationCache();
|
|
19
|
+
const originalScope = Object.freeze({ points: undefined });
|
|
20
|
+
let modulePromise,
|
|
21
|
+
originalFacade,
|
|
22
|
+
currentScope,
|
|
23
|
+
worker,
|
|
6
24
|
idleTimer,
|
|
25
|
+
characters = 0,
|
|
7
26
|
sequence = 0;
|
|
27
|
+
|
|
28
|
+
const dispatchTimers = new Map();
|
|
29
|
+
const preparationQueue = [];
|
|
30
|
+
let activePreparation;
|
|
31
|
+
|
|
32
|
+
function pumpPreparationQueue() {
|
|
33
|
+
if (pending.size || dispatchTimers.size) return;
|
|
34
|
+
if (activePreparation && !activePreparation.released) return;
|
|
35
|
+
activePreparation = undefined;
|
|
36
|
+
const next = preparationQueue.shift();
|
|
37
|
+
if (!next) return;
|
|
38
|
+
next.signal?.removeEventListener('abort', next.abort);
|
|
39
|
+
const lease = { released: false };
|
|
40
|
+
activePreparation = lease;
|
|
41
|
+
next.resolve(() => {
|
|
42
|
+
if (lease.released) return;
|
|
43
|
+
lease.released = true;
|
|
44
|
+
pumpPreparationQueue();
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function scoped(scope, operation) {
|
|
49
|
+
const previous = currentScope;
|
|
50
|
+
const schedule = globalThis.setTimeout;
|
|
51
|
+
const cancel = globalThis.clearTimeout;
|
|
52
|
+
currentScope = scope;
|
|
53
|
+
// Emscripten dispatches preparation asynchronously. Keep the owning scope
|
|
54
|
+
// through its timer, but preserve the engine's timing and callback ordering.
|
|
55
|
+
// The preparation lease prevents other characters from joining that global
|
|
56
|
+
// native queue until this owner's preparation has settled.
|
|
57
|
+
globalThis.setTimeout = function (callback, delay, ...args) {
|
|
58
|
+
const nativeDispatcher =
|
|
59
|
+
typeof callback === 'function' &&
|
|
60
|
+
Number(delay) === 0 &&
|
|
61
|
+
Function.prototype.toString
|
|
62
|
+
.call(callback)
|
|
63
|
+
.includes(
|
|
64
|
+
'safeSetTimeout.mapping[id]=undefined;callUserCallback(func)',
|
|
65
|
+
);
|
|
66
|
+
let handle;
|
|
67
|
+
handle = schedule.call(
|
|
68
|
+
globalThis,
|
|
69
|
+
typeof callback === 'function'
|
|
70
|
+
? (...values) => {
|
|
71
|
+
if (nativeDispatcher) dispatchTimers.delete(handle);
|
|
72
|
+
try {
|
|
73
|
+
return scoped(scope, () => callback(...values));
|
|
74
|
+
} finally {
|
|
75
|
+
pumpPreparationQueue();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
: callback,
|
|
79
|
+
delay,
|
|
80
|
+
...args,
|
|
81
|
+
);
|
|
82
|
+
if (nativeDispatcher) dispatchTimers.set(handle, scope);
|
|
83
|
+
return handle;
|
|
84
|
+
};
|
|
85
|
+
globalThis.clearTimeout = function (handle) {
|
|
86
|
+
dispatchTimers.delete(handle);
|
|
87
|
+
return cancel.call(globalThis, handle);
|
|
88
|
+
};
|
|
89
|
+
try {
|
|
90
|
+
return operation();
|
|
91
|
+
} finally {
|
|
92
|
+
globalThis.setTimeout = schedule;
|
|
93
|
+
globalThis.clearTimeout = cancel;
|
|
94
|
+
currentScope = previous;
|
|
95
|
+
pumpPreparationQueue();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Fair, cancelable setup lease for the native engine's global prepare queue.
|
|
100
|
+
* Acquire before constructing or changing a Character's geometry. Release
|
|
101
|
+
* after preparation/paint, or dispose/error. A released owner with a pending
|
|
102
|
+
* native callback retains its turn until that callback has completed.
|
|
103
|
+
*/
|
|
104
|
+
export function acquireCharacterPreparation(signal) {
|
|
105
|
+
return new Promise((resolve, reject) => {
|
|
106
|
+
const abort = () => {
|
|
107
|
+
const index = preparationQueue.indexOf(entry);
|
|
108
|
+
if (index >= 0) preparationQueue.splice(index, 1);
|
|
109
|
+
reject(new DOMException('Character preparation aborted', 'AbortError'));
|
|
110
|
+
pumpPreparationQueue();
|
|
111
|
+
};
|
|
112
|
+
const entry = { resolve, reject, signal, abort };
|
|
113
|
+
if (signal?.aborted) {
|
|
114
|
+
abort();
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
signal?.addEventListener('abort', abort, { once: true });
|
|
118
|
+
preparationQueue.push(entry);
|
|
119
|
+
pumpPreparationQueue();
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function stopIdleWorker() {
|
|
124
|
+
clearTimeout(idleTimer);
|
|
125
|
+
if (characters || pool.size || pending.size || dispatchTimers.size) return;
|
|
126
|
+
idleTimer = setTimeout(() => {
|
|
127
|
+
if (!characters && !pool.size && !pending.size && !dispatchTimers.size) {
|
|
128
|
+
worker?.terminate();
|
|
129
|
+
worker = undefined;
|
|
130
|
+
}
|
|
131
|
+
}, 0);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function finishRequest(id, result, reused = false) {
|
|
135
|
+
const entry = pending.get(id);
|
|
136
|
+
if (!entry || entry.delivering) return;
|
|
137
|
+
entry.delivering = true;
|
|
138
|
+
try {
|
|
139
|
+
await entry.complete(result, reused);
|
|
140
|
+
} finally {
|
|
141
|
+
// Keep the owner's turn while the GPU boundary and native completion are
|
|
142
|
+
// still waiting, even if that owner has already been canceled or deleted.
|
|
143
|
+
pending.delete(id);
|
|
144
|
+
pumpPreparationQueue();
|
|
145
|
+
stopIdleWorker();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
8
149
|
function preparationWorker() {
|
|
150
|
+
clearTimeout(idleTimer);
|
|
9
151
|
if (worker) return worker;
|
|
10
152
|
worker = new Worker(new URL('./legacy-worker.mjs', import.meta.url), {
|
|
11
153
|
type: 'module',
|
|
12
154
|
});
|
|
13
155
|
worker.onmessage = ({ data }) => {
|
|
14
|
-
|
|
15
|
-
if (!entry) return;
|
|
16
|
-
pending.delete(data.id);
|
|
17
|
-
entry.complete(data);
|
|
156
|
+
void finishRequest(data.id, data);
|
|
18
157
|
};
|
|
19
158
|
worker.onerror = () => {
|
|
20
|
-
const failed = [...pending.
|
|
21
|
-
pending.clear();
|
|
159
|
+
const failed = [...pending.keys()];
|
|
22
160
|
worker?.terminate();
|
|
23
161
|
worker = undefined;
|
|
24
|
-
for (const
|
|
25
|
-
|
|
26
|
-
error: '
|
|
162
|
+
for (const id of failed)
|
|
163
|
+
void finishRequest(id, {
|
|
164
|
+
error: 'Character preparation failed',
|
|
27
165
|
milliseconds: 0,
|
|
28
166
|
});
|
|
29
167
|
};
|
|
30
168
|
return worker;
|
|
31
169
|
}
|
|
32
170
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
171
|
+
function sharedModule() {
|
|
172
|
+
if (!modulePromise) {
|
|
173
|
+
controller = createControllerModeAdapter(
|
|
174
|
+
() => new URL('./orbit-characters.wasm', import.meta.url),
|
|
175
|
+
);
|
|
176
|
+
modulePromise = Promise.race([
|
|
177
|
+
createModule({
|
|
178
|
+
locateFile: (file) => new URL(file, import.meta.url).href,
|
|
179
|
+
instantiateWasm: controller.instantiateWasm,
|
|
180
|
+
}),
|
|
181
|
+
controller.failure,
|
|
182
|
+
])
|
|
183
|
+
.then((module) => {
|
|
184
|
+
module.orbitPrepare = (
|
|
185
|
+
id,
|
|
186
|
+
appearance,
|
|
187
|
+
quality,
|
|
188
|
+
cacheKey,
|
|
189
|
+
activities,
|
|
190
|
+
) => {
|
|
191
|
+
const scope = currentScope;
|
|
192
|
+
if (!scope) {
|
|
50
193
|
module.orbitCompletePreparation(
|
|
51
194
|
id,
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
195
|
+
null,
|
|
196
|
+
'Character preparation requires a scoped call',
|
|
197
|
+
0,
|
|
55
198
|
);
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
id: request,
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
const request = ++sequence;
|
|
202
|
+
const cacheKeyExact = preparationKey({
|
|
61
203
|
appearance,
|
|
62
204
|
quality,
|
|
63
205
|
key: cacheKey,
|
|
64
206
|
activities,
|
|
65
|
-
points,
|
|
207
|
+
points: scope.points,
|
|
208
|
+
authoredParts: scope.authoredParts,
|
|
209
|
+
eyeSpacing: scope.authoredParts?.eyeSpacing,
|
|
210
|
+
});
|
|
211
|
+
const complete = async (result, reused = false) => {
|
|
212
|
+
await waitForSharedRender();
|
|
213
|
+
return scoped(scope, () => {
|
|
214
|
+
if (result.bytes && !result.error && !reused)
|
|
215
|
+
prepared.set(cacheKeyExact, result.bytes);
|
|
216
|
+
module.orbitCompletePreparation(
|
|
217
|
+
id,
|
|
218
|
+
result.bytes ?? null,
|
|
219
|
+
result.error || '',
|
|
220
|
+
result.milliseconds || 0,
|
|
221
|
+
);
|
|
222
|
+
});
|
|
223
|
+
};
|
|
224
|
+
pending.set(request, { complete });
|
|
225
|
+
const cached = prepared.get(cacheKeyExact);
|
|
226
|
+
if (cached) {
|
|
227
|
+
// Preserve asynchronous completion and the owner's preparation
|
|
228
|
+
// turn. Completing inside orbitPrepare would re-enter native
|
|
229
|
+
// dispatch while its job is still being registered.
|
|
230
|
+
queueMicrotask(() => {
|
|
231
|
+
void finishRequest(
|
|
232
|
+
request,
|
|
233
|
+
{ bytes: cached, milliseconds: 0 },
|
|
234
|
+
true,
|
|
235
|
+
);
|
|
236
|
+
});
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
try {
|
|
240
|
+
preparationWorker().postMessage({
|
|
241
|
+
id: request,
|
|
242
|
+
appearance,
|
|
243
|
+
quality,
|
|
244
|
+
key: cacheKey,
|
|
245
|
+
activities,
|
|
246
|
+
points: scope.points,
|
|
247
|
+
authoredParts: scope.authoredParts,
|
|
248
|
+
eyeSpacing: scope.authoredParts?.eyeSpacing,
|
|
249
|
+
});
|
|
250
|
+
} catch (error) {
|
|
251
|
+
void finishRequest(request, {
|
|
252
|
+
error: String(error),
|
|
253
|
+
milliseconds: 0,
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
return module;
|
|
258
|
+
})
|
|
259
|
+
.catch((error) => {
|
|
260
|
+
modulePromise = undefined;
|
|
261
|
+
throw error;
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
return modulePromise;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function facade(module, scope) {
|
|
268
|
+
const result = Object.create(module);
|
|
269
|
+
const handles = new WeakMap();
|
|
270
|
+
function wrap(target, activities = false, source) {
|
|
271
|
+
controller.register(target, activities, source);
|
|
272
|
+
const methods = new Map();
|
|
273
|
+
let deleted = false;
|
|
274
|
+
characters++;
|
|
275
|
+
const proxy = new Proxy(target, {
|
|
276
|
+
get(instance, key) {
|
|
277
|
+
const value = Reflect.get(instance, key, instance);
|
|
278
|
+
if (typeof value !== 'function' || key === 'constructor') return value;
|
|
279
|
+
if (!methods.has(key))
|
|
280
|
+
methods.set(key, (...args) => {
|
|
281
|
+
const returned = scoped(scope, () => value.apply(instance, args));
|
|
282
|
+
if (key === 'applyActivity' && returned === 0 && activities)
|
|
283
|
+
controller.markBound(instance);
|
|
284
|
+
if (key === 'delete' && !deleted) {
|
|
285
|
+
controller.unregister(instance);
|
|
286
|
+
deleted = true;
|
|
287
|
+
characters--;
|
|
288
|
+
stopIdleWorker();
|
|
289
|
+
}
|
|
290
|
+
// Embind handle clones retain the same native character and scope.
|
|
291
|
+
if (returned !== instance && returned instanceof module.Character)
|
|
292
|
+
return wrap(returned, activities, instance);
|
|
293
|
+
return returned;
|
|
66
294
|
});
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
module.orbitCompletePreparation(id, null, String(error), 0);
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
return module;
|
|
295
|
+
return methods.get(key);
|
|
296
|
+
},
|
|
73
297
|
});
|
|
298
|
+
handles.set(proxy, target);
|
|
299
|
+
return proxy;
|
|
300
|
+
}
|
|
301
|
+
result.controllerMode = (character, enabled) => {
|
|
302
|
+
const instance = handles.get(character);
|
|
303
|
+
if (!instance)
|
|
304
|
+
throw new Error(
|
|
305
|
+
'Character controller belongs to a different engine scope',
|
|
306
|
+
);
|
|
307
|
+
return scoped(scope, () => controller.controllerMode(instance, enabled));
|
|
308
|
+
};
|
|
309
|
+
result.controllerState = (character) => {
|
|
310
|
+
const instance = handles.get(character);
|
|
311
|
+
if (!instance)
|
|
312
|
+
throw new Error(
|
|
313
|
+
'Character controller belongs to a different engine scope',
|
|
314
|
+
);
|
|
315
|
+
return scoped(scope, () => controller.controllerState(instance));
|
|
316
|
+
};
|
|
317
|
+
result.controllerSignature = (character, preset) => {
|
|
318
|
+
const instance = handles.get(character);
|
|
319
|
+
if (!instance)
|
|
320
|
+
throw new Error(
|
|
321
|
+
'Character controller belongs to a different engine scope',
|
|
322
|
+
);
|
|
323
|
+
return scoped(scope, () =>
|
|
324
|
+
controller.controllerSignature(instance, preset),
|
|
325
|
+
);
|
|
326
|
+
};
|
|
327
|
+
result.controllerWithSignature = (character, preset, operation) => {
|
|
328
|
+
const instance = handles.get(character);
|
|
329
|
+
if (!instance)
|
|
330
|
+
throw new Error(
|
|
331
|
+
'Character controller belongs to a different engine scope',
|
|
332
|
+
);
|
|
333
|
+
return scoped(scope, () =>
|
|
334
|
+
controller.controllerWithSignature(instance, preset, operation),
|
|
335
|
+
);
|
|
336
|
+
};
|
|
337
|
+
result.Character = function Character(...args) {
|
|
338
|
+
clearTimeout(idleTimer);
|
|
339
|
+
return wrap(
|
|
340
|
+
scoped(scope, () => new module.Character(...args)),
|
|
341
|
+
args[3]?.activities,
|
|
342
|
+
);
|
|
343
|
+
};
|
|
344
|
+
result.Character.prototype = module.Character.prototype;
|
|
345
|
+
return result;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/** Original and custom bodies share one WASM instance and preparation worker.
|
|
349
|
+
* Prepared mesh identities distinguish contours inside the shared GPU cache.
|
|
350
|
+
*/
|
|
351
|
+
function normalizeAuthoredParts(value) {
|
|
352
|
+
if (!value || !Object.keys(value).length) return undefined;
|
|
353
|
+
const keys = [
|
|
354
|
+
'bodyPreset',
|
|
355
|
+
'paintBody',
|
|
356
|
+
'shape',
|
|
357
|
+
'eyes',
|
|
358
|
+
'eyewear',
|
|
359
|
+
'accessory',
|
|
360
|
+
'eyeSpacing',
|
|
361
|
+
'faceShape',
|
|
362
|
+
];
|
|
363
|
+
if (
|
|
364
|
+
Object.keys(value).some((key) => !keys.includes(key)) ||
|
|
365
|
+
(value.bodyPreset !== undefined &&
|
|
366
|
+
!ORIGINAL_PRESETS.includes(value.bodyPreset)) ||
|
|
367
|
+
(value.paintBody !== undefined && typeof value.paintBody !== 'boolean') ||
|
|
368
|
+
(value.shape !== undefined && value.shape !== 'clippo') ||
|
|
369
|
+
(value.faceShape !== undefined &&
|
|
370
|
+
![...MIGRATED_SHAPE_IDS, ...NATIVE_PARTS.shape].includes(
|
|
371
|
+
value.faceShape,
|
|
372
|
+
)) ||
|
|
373
|
+
(value.eyes !== undefined &&
|
|
374
|
+
![...NATIVE_PARTS.eyes, 'todd', 'clippo', 'cyclops'].includes(
|
|
375
|
+
value.eyes,
|
|
376
|
+
)) ||
|
|
377
|
+
(value.eyewear !== undefined &&
|
|
378
|
+
!NATIVE_PARTS.eyewear.includes(value.eyewear)) ||
|
|
379
|
+
(value.accessory !== undefined &&
|
|
380
|
+
![...NATIVE_PARTS.accessory, 'felipe_beret'].includes(value.accessory))
|
|
381
|
+
)
|
|
382
|
+
throw new Error('Unsupported authored character part');
|
|
383
|
+
return Object.freeze(
|
|
384
|
+
Object.fromEntries(
|
|
385
|
+
keys
|
|
386
|
+
.filter((key) => value[key] !== undefined && key !== 'eyeSpacing')
|
|
387
|
+
.map((key) => [key, value[key]]),
|
|
388
|
+
),
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
export async function getCharacterEngine(parts) {
|
|
392
|
+
const authoredParts = normalizeAuthoredParts(parts);
|
|
393
|
+
const module = await sharedModule();
|
|
394
|
+
if (!authoredParts) {
|
|
395
|
+
originalFacade ??= facade(module, originalScope);
|
|
396
|
+
return originalFacade;
|
|
397
|
+
}
|
|
398
|
+
// Retain a bounded set of recipe facades; live Characters own their scopes.
|
|
399
|
+
const key = JSON.stringify(authoredParts);
|
|
400
|
+
if (!authoredFacades.has(key))
|
|
401
|
+
authoredFacades.set(
|
|
402
|
+
key,
|
|
403
|
+
facade(module, { points: undefined, authoredParts }),
|
|
404
|
+
);
|
|
405
|
+
const result = authoredFacades.get(key);
|
|
406
|
+
authoredFacades.delete(key);
|
|
407
|
+
authoredFacades.set(key, result);
|
|
408
|
+
if (authoredFacades.size > 64)
|
|
409
|
+
authoredFacades.delete(authoredFacades.keys().next().value);
|
|
410
|
+
return result;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
export async function acquireLegacyEngine(points, parts) {
|
|
414
|
+
clearTimeout(idleTimer);
|
|
415
|
+
const authoredParts = normalizeAuthoredParts(parts);
|
|
416
|
+
const key = JSON.stringify([points, authoredParts]);
|
|
417
|
+
let entry = pool.get(key);
|
|
418
|
+
if (!entry) {
|
|
419
|
+
const scope = {
|
|
420
|
+
points: points.map((point) => point.slice()),
|
|
421
|
+
authoredParts,
|
|
422
|
+
};
|
|
423
|
+
entry = {
|
|
424
|
+
references: 0,
|
|
425
|
+
facade: sharedModule().then((module) => facade(module, scope)),
|
|
426
|
+
};
|
|
74
427
|
pool.set(key, entry);
|
|
75
428
|
}
|
|
76
429
|
entry.references++;
|
|
@@ -78,20 +431,11 @@ export async function acquireLegacyEngine(points) {
|
|
|
78
431
|
const release = () => {
|
|
79
432
|
if (released) return;
|
|
80
433
|
released = true;
|
|
81
|
-
if (--entry.references
|
|
82
|
-
|
|
83
|
-
for (const [id, request] of pending)
|
|
84
|
-
if (request.owner === entry) pending.delete(id);
|
|
85
|
-
if (!pool.size)
|
|
86
|
-
idleTimer = setTimeout(() => {
|
|
87
|
-
if (!pool.size) {
|
|
88
|
-
worker?.terminate();
|
|
89
|
-
worker = undefined;
|
|
90
|
-
}
|
|
91
|
-
}, 0);
|
|
434
|
+
if (--entry.references === 0) pool.delete(key);
|
|
435
|
+
stopIdleWorker();
|
|
92
436
|
};
|
|
93
437
|
try {
|
|
94
|
-
return { module: await entry.
|
|
438
|
+
return { module: await entry.facade, release };
|
|
95
439
|
} catch (error) {
|
|
96
440
|
release();
|
|
97
441
|
throw error;
|
|
@@ -99,7 +443,15 @@ export async function acquireLegacyEngine(points) {
|
|
|
99
443
|
}
|
|
100
444
|
|
|
101
445
|
export const legacyEngineStats = () => ({
|
|
446
|
+
// Historical field counts leased contour entries; sharedModules is the
|
|
447
|
+
// actual WASM count, including the instance used by original characters.
|
|
102
448
|
modules: pool.size,
|
|
449
|
+
sharedModules: modulePromise ? 1 : 0,
|
|
450
|
+
characters,
|
|
451
|
+
preparationWaiters: preparationQueue.length,
|
|
452
|
+
preparationActive: !!activePreparation,
|
|
453
|
+
dispatchTimers: dispatchTimers.size,
|
|
103
454
|
pending: pending.size,
|
|
104
455
|
worker: !!worker,
|
|
456
|
+
preparationCache: prepared.stats(),
|
|
105
457
|
});
|