@oxy.so/bloom 7.1.1 → 7.1.3
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
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { sha256 } from './sha256.mjs';
|
|
2
|
+
/** Internal adapter for the pinned, unmodified original Character WASM ABI.
|
|
3
|
+
* The public activity API binds its renderer permanently. This controller bit
|
|
4
|
+
* selects both render and input branches; it does not replace geometry or pose.
|
|
5
|
+
* Any upstream binary change requires re-disassembly and real-render validation.
|
|
6
|
+
*/
|
|
7
|
+
export const CONTROLLER_WASM_SHA256 =
|
|
8
|
+
'c15f3692305c1385a12524e877199ba279b8d53e6bd37a9e533d626f12fcb94b';
|
|
9
|
+
const OFFSET = Object.freeze({ mode: 3015, ready: 74640, type: 74772 });
|
|
10
|
+
const CHARACTER_TYPE = 4001288;
|
|
11
|
+
// Read-only, null-terminated identity literals in this exact WASM image.
|
|
12
|
+
// func1726 compares the requested and prepared identity strings, then stores
|
|
13
|
+
// only the numeric original signature profile in the reaction controller.
|
|
14
|
+
const SIGNATURE_IDENTITIES = Object.freeze({
|
|
15
|
+
blue_beret: 6968,
|
|
16
|
+
alfred: 34630,
|
|
17
|
+
purple_heart: 4922,
|
|
18
|
+
lime_frog: 22673,
|
|
19
|
+
coral_monocle: 28480,
|
|
20
|
+
gus: 8835,
|
|
21
|
+
blue_spectacles: 12573,
|
|
22
|
+
lime_headphones: 12137,
|
|
23
|
+
});
|
|
24
|
+
const IDENTITY_OFFSETS = [73396, 73792];
|
|
25
|
+
|
|
26
|
+
export function createControllerModeAdapter(wasmUrl) {
|
|
27
|
+
let memory;
|
|
28
|
+
let verified = false;
|
|
29
|
+
let rejectInstantiation;
|
|
30
|
+
const failure = new Promise((_, reject) => {
|
|
31
|
+
rejectInstantiation = reject;
|
|
32
|
+
});
|
|
33
|
+
// A mocked module factory need not invoke instantiateWasm.
|
|
34
|
+
failure.catch(() => {});
|
|
35
|
+
const characters = new WeakMap();
|
|
36
|
+
|
|
37
|
+
const instantiateWasm = (imports, receiveInstance) => {
|
|
38
|
+
void (async () => {
|
|
39
|
+
const response = await fetch(
|
|
40
|
+
typeof wasmUrl === 'function' ? wasmUrl() : wasmUrl,
|
|
41
|
+
);
|
|
42
|
+
if (!response.ok)
|
|
43
|
+
throw new Error(`Character WASM fetch failed: ${response.status}`);
|
|
44
|
+
const bytes = await response.arrayBuffer();
|
|
45
|
+
const digest = await sha256(bytes);
|
|
46
|
+
if (digest !== CONTROLLER_WASM_SHA256)
|
|
47
|
+
throw new Error(
|
|
48
|
+
'Character controller ABI: original WASM integrity mismatch',
|
|
49
|
+
);
|
|
50
|
+
const { instance } = await WebAssembly.instantiate(bytes, imports);
|
|
51
|
+
if (!(instance.exports.Vd instanceof WebAssembly.Memory))
|
|
52
|
+
throw new Error(
|
|
53
|
+
'Character controller ABI: missing original memory export',
|
|
54
|
+
);
|
|
55
|
+
memory = instance.exports.Vd;
|
|
56
|
+
verified = true;
|
|
57
|
+
receiveInstance(instance);
|
|
58
|
+
})().catch(rejectInstantiation);
|
|
59
|
+
return {};
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
function register(character, activities, source) {
|
|
63
|
+
characters.set(character, {
|
|
64
|
+
activities: activities === true,
|
|
65
|
+
bound: characters.get(source)?.bound === true,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
function unregister(character) {
|
|
69
|
+
characters.delete(character);
|
|
70
|
+
}
|
|
71
|
+
function layout(character) {
|
|
72
|
+
const record = characters.get(character);
|
|
73
|
+
if (!record?.activities || !verified || !memory || character.isDeleted?.())
|
|
74
|
+
throw new Error(
|
|
75
|
+
'Character controller ABI: unsupported or deleted character',
|
|
76
|
+
);
|
|
77
|
+
// Read a fresh view after every possible memory growth. Embind's outer
|
|
78
|
+
// handle owns one pointer to the native implementation, not the impl itself.
|
|
79
|
+
const view = new DataView(memory.buffer);
|
|
80
|
+
const handle = character.$$?.ptr;
|
|
81
|
+
if (
|
|
82
|
+
!Number.isInteger(handle) ||
|
|
83
|
+
handle <= 0 ||
|
|
84
|
+
handle % 4 ||
|
|
85
|
+
handle + 4 > view.byteLength
|
|
86
|
+
)
|
|
87
|
+
throw new Error('Character controller ABI: invalid Embind handle');
|
|
88
|
+
const impl = view.getUint32(handle, true);
|
|
89
|
+
if (
|
|
90
|
+
!impl ||
|
|
91
|
+
impl % 4 ||
|
|
92
|
+
impl + OFFSET.type + 4 > view.byteLength ||
|
|
93
|
+
view.getUint32(impl + OFFSET.type, true) !== CHARACTER_TYPE ||
|
|
94
|
+
view.getUint8(impl + OFFSET.ready) > 1 ||
|
|
95
|
+
view.getUint8(impl + OFFSET.mode) > 1
|
|
96
|
+
)
|
|
97
|
+
throw new Error('Character controller ABI: invalid pinned native layout');
|
|
98
|
+
return { record, view, address: impl + OFFSET.mode };
|
|
99
|
+
}
|
|
100
|
+
function markBound(character) {
|
|
101
|
+
const { record, view, address } = layout(character);
|
|
102
|
+
if (view.getUint8(address) === 1) record.bound = true;
|
|
103
|
+
}
|
|
104
|
+
function controllerMode(character, enabled) {
|
|
105
|
+
const { record, view, address } = layout(character);
|
|
106
|
+
if (!record.bound)
|
|
107
|
+
throw new Error(
|
|
108
|
+
'Character controller ABI: activity Restore must bind before selecting a controller',
|
|
109
|
+
);
|
|
110
|
+
if (enabled !== undefined) {
|
|
111
|
+
if (typeof enabled !== 'boolean')
|
|
112
|
+
throw new TypeError('Character controller mode must be boolean');
|
|
113
|
+
view.setUint8(address, enabled ? 1 : 0);
|
|
114
|
+
}
|
|
115
|
+
return view.getUint8(address) === 1;
|
|
116
|
+
}
|
|
117
|
+
function controllerState(character) {
|
|
118
|
+
const { record, view, address } = layout(character);
|
|
119
|
+
if (!record.bound)
|
|
120
|
+
throw new Error(
|
|
121
|
+
'Character controller ABI: activity Restore must bind before reading state',
|
|
122
|
+
);
|
|
123
|
+
const impl = address - OFFSET.mode;
|
|
124
|
+
const phase = view.getUint8(impl + 3008 + 35160);
|
|
125
|
+
const activity = view.getUint32(impl + 3008 + 35136, true);
|
|
126
|
+
const episodeId = view.getBigUint64(impl + 3008 + 35128, true);
|
|
127
|
+
if (phase > 3 || activity > 9)
|
|
128
|
+
throw new Error(
|
|
129
|
+
'Character controller ABI: invalid pinned activity state',
|
|
130
|
+
);
|
|
131
|
+
// Original func1124 starts Stop at phase3. Original func786 clears phase,
|
|
132
|
+
// current activity and episode only after its authored 3D outro finishes.
|
|
133
|
+
// copyActivityRestore reflects the requested state immediately, too early.
|
|
134
|
+
return {
|
|
135
|
+
phase,
|
|
136
|
+
activity,
|
|
137
|
+
episodeId,
|
|
138
|
+
settled: phase === 0 && activity === 0 && episodeId === 0n,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
function controllerWithSignature(character, identity, operation) {
|
|
142
|
+
const { record, view, address } = layout(character);
|
|
143
|
+
if (!record.bound)
|
|
144
|
+
throw new Error(
|
|
145
|
+
'Character controller ABI: activity Restore must bind before selecting a signature',
|
|
146
|
+
);
|
|
147
|
+
const pointer = SIGNATURE_IDENTITIES[identity];
|
|
148
|
+
if (!Object.hasOwn(SIGNATURE_IDENTITIES, identity))
|
|
149
|
+
throw new TypeError(
|
|
150
|
+
'Character controller signature must name an original body',
|
|
151
|
+
);
|
|
152
|
+
if (typeof operation !== 'function')
|
|
153
|
+
throw new TypeError(
|
|
154
|
+
'Character controller signature operation must be synchronous',
|
|
155
|
+
);
|
|
156
|
+
const literal = new TextEncoder().encode(`${identity}\0`);
|
|
157
|
+
if (
|
|
158
|
+
pointer + literal.length > view.byteLength ||
|
|
159
|
+
!literal.every((byte, i) => view.getUint8(pointer + i) === byte)
|
|
160
|
+
)
|
|
161
|
+
throw new Error(
|
|
162
|
+
'Character controller ABI: invalid pinned signature literal',
|
|
163
|
+
);
|
|
164
|
+
const impl = address - OFFSET.mode;
|
|
165
|
+
const saved = IDENTITY_OFFSETS.map((offset) =>
|
|
166
|
+
new Uint8Array(memory.buffer, impl + offset, 12).slice(),
|
|
167
|
+
);
|
|
168
|
+
// Borrow immutable native strings only for the synchronous native call.
|
|
169
|
+
// Restore the complete libc++ string objects (including any owning heap
|
|
170
|
+
// pointers) before rendering, state serialization, or destruction can run.
|
|
171
|
+
// Keeping HERE in the appearance would also override transplanted materials.
|
|
172
|
+
try {
|
|
173
|
+
for (const offset of IDENTITY_OFFSETS) {
|
|
174
|
+
const at = impl + offset;
|
|
175
|
+
view.setUint32(at, pointer, true);
|
|
176
|
+
view.setUint32(at + 4, identity.length, true);
|
|
177
|
+
view.setUint32(at + 8, 0x80000000 | (identity.length + 1), true);
|
|
178
|
+
}
|
|
179
|
+
const result = operation();
|
|
180
|
+
if (result && typeof result.then === 'function')
|
|
181
|
+
throw new TypeError(
|
|
182
|
+
'Character controller signature operation must be synchronous',
|
|
183
|
+
);
|
|
184
|
+
return result;
|
|
185
|
+
} finally {
|
|
186
|
+
// Native calls may grow memory, invalidating the earlier DataView.
|
|
187
|
+
IDENTITY_OFFSETS.forEach((offset, i) =>
|
|
188
|
+
new Uint8Array(memory.buffer, impl + offset, 12).set(saved[i]),
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function controllerSignature(character, identity) {
|
|
193
|
+
return controllerWithSignature(character, identity, () =>
|
|
194
|
+
character.playReaction(2),
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
return {
|
|
198
|
+
instantiateWasm,
|
|
199
|
+
failure,
|
|
200
|
+
register,
|
|
201
|
+
unregister,
|
|
202
|
+
markBound,
|
|
203
|
+
controllerMode,
|
|
204
|
+
controllerState,
|
|
205
|
+
controllerSignature,
|
|
206
|
+
controllerWithSignature,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import {
|
|
2
|
+
authoredAssemblyRecords,
|
|
3
|
+
authoredEyeRecords,
|
|
4
|
+
hasAuthoredLabel,
|
|
5
|
+
transformAuthoredRecord,
|
|
6
|
+
assembleAuthoredRecords,
|
|
7
|
+
} from './authored-parts.mjs';
|
|
8
|
+
import { sha256 } from './sha256.mjs';
|
|
9
|
+
|
|
10
|
+
const encoder = new TextEncoder();
|
|
11
|
+
const center = (bounds) => bounds.min.map((v, k) => (v + bounds.max[k]) / 2);
|
|
12
|
+
const span = (bounds, axis) => bounds.max[axis] - bounds.min[axis];
|
|
13
|
+
const fail = (message) => {
|
|
14
|
+
throw new Error(`Single eye: ${message}`);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/** Single-eye placement is body-relative, never a collapsed left/right pair.
|
|
18
|
+
* The upper-middle face keeps the eye on Todd's head rather than between its
|
|
19
|
+
* raised eye stalks; the narrow clip uses its original upper face instead.
|
|
20
|
+
*/
|
|
21
|
+
export function cyclopsPlacement(body, eyes, clippo = false) {
|
|
22
|
+
if (
|
|
23
|
+
(clippo && !eyes.length) ||
|
|
24
|
+
[...body.min, ...body.max].some((v) => !Number.isFinite(v))
|
|
25
|
+
)
|
|
26
|
+
fail('missing finite face bounds');
|
|
27
|
+
const radius = Math.max(
|
|
28
|
+
0.2,
|
|
29
|
+
Math.min(0.6, span(body, 0) * (clippo ? 0.32 : 0.27)),
|
|
30
|
+
);
|
|
31
|
+
const location = center(body);
|
|
32
|
+
location[1] = clippo
|
|
33
|
+
? eyes.reduce((sum, part) => sum + center(part.bounds)[1], 0) / eyes.length
|
|
34
|
+
: body.min[1] + span(body, 1) * 0.62;
|
|
35
|
+
location[2] = clippo ? 0.13 : body.max[2] - radius * 0.18;
|
|
36
|
+
return { radius, center: location };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function eyeRecord(bytes, part, origin, scale, destination, role, color) {
|
|
40
|
+
const record = await transformAuthoredRecord(bytes, part, {
|
|
41
|
+
scale,
|
|
42
|
+
origin,
|
|
43
|
+
translate: destination.map((v, k) => v - origin[k]),
|
|
44
|
+
});
|
|
45
|
+
const view = new DataView(record.bytes.buffer);
|
|
46
|
+
if (color) {
|
|
47
|
+
// Native fixed-pupil black bypasses material RGB. Disable only that flag,
|
|
48
|
+
// retaining the original eye shader and its blink/look deformation data.
|
|
49
|
+
record.bytes[88] = 0;
|
|
50
|
+
for (const offset of [28, 60])
|
|
51
|
+
color.forEach((v, k) => view.setFloat32(offset + k * 4, v, true));
|
|
52
|
+
}
|
|
53
|
+
if (role === 'iris') {
|
|
54
|
+
// Radial iris striations use surface normals rather than a new texture or
|
|
55
|
+
// dozens of draw calls. The three native normal bases receive the same
|
|
56
|
+
// perturbation, so native blink/morph interpolation remains continuous.
|
|
57
|
+
for (let i = 0; i < part.vertexCount; i++) {
|
|
58
|
+
const at = part.vertexOffset - part.start + i * 96;
|
|
59
|
+
const x = view.getFloat32(at, true) - destination[0];
|
|
60
|
+
const y = view.getFloat32(at + 4, true) - destination[1];
|
|
61
|
+
const angle = Math.atan2(y, x);
|
|
62
|
+
const groove = 0.2 * Math.sin(angle * 53) + 0.09 * Math.sin(angle * 91);
|
|
63
|
+
for (const offset of [12, 36, 60, 84]) {
|
|
64
|
+
const nx =
|
|
65
|
+
view.getFloat32(at + offset, true) + Math.cos(angle) * groove;
|
|
66
|
+
const ny =
|
|
67
|
+
view.getFloat32(at + offset + 4, true) + Math.sin(angle) * groove;
|
|
68
|
+
const nz = view.getFloat32(at + offset + 8, true);
|
|
69
|
+
const length = Math.hypot(nx, ny, nz);
|
|
70
|
+
if (length > 1e-8)
|
|
71
|
+
[nx, ny, nz].forEach((v, k) =>
|
|
72
|
+
view.setFloat32(at + offset + k * 4, v / length, true),
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const key = await sha256(
|
|
78
|
+
encoder.encode(JSON.stringify(['cyclops-v1', record.name, role, color])),
|
|
79
|
+
);
|
|
80
|
+
record.bytes.set(encoder.encode(key), part.nameOffset - part.start);
|
|
81
|
+
record.name = key + record.name.slice(64);
|
|
82
|
+
return record;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** One original native eyeball, an iris, pupil and glint. Preserves the same
|
|
86
|
+
* character controller, native eye motion and opaque work/activity payload.
|
|
87
|
+
*/
|
|
88
|
+
export async function composeCyclopsAssembly(module, bytes, request) {
|
|
89
|
+
if (request.authoredParts?.eyes !== 'cyclops') return bytes;
|
|
90
|
+
const target = authoredAssemblyRecords(bytes);
|
|
91
|
+
const previousEyes = authoredEyeRecords(target);
|
|
92
|
+
const prepared = module.orbitPrepareAssembly(
|
|
93
|
+
module.presetAppearance('lime_frog'),
|
|
94
|
+
request.quality,
|
|
95
|
+
`${request.key}:single-eye-source`,
|
|
96
|
+
false,
|
|
97
|
+
);
|
|
98
|
+
if (!prepared.bytes || prepared.error)
|
|
99
|
+
fail(prepared.error || 'eye source unavailable');
|
|
100
|
+
const sourceBytes = prepared.bytes.slice();
|
|
101
|
+
const source = authoredAssemblyRecords(sourceBytes);
|
|
102
|
+
const [outer, pupil] = source.records.slice(1, 3);
|
|
103
|
+
if (
|
|
104
|
+
!outer ||
|
|
105
|
+
!pupil ||
|
|
106
|
+
![outer, pupil].every((p) =>
|
|
107
|
+
hasAuthoredLabel(sourceBytes, p, 'source_integrated_eye'),
|
|
108
|
+
)
|
|
109
|
+
)
|
|
110
|
+
fail('original eye layout changed');
|
|
111
|
+
const layout = request.faceLayout;
|
|
112
|
+
const placement = layout
|
|
113
|
+
? {
|
|
114
|
+
radius: layout.radius * 2,
|
|
115
|
+
center: [0, 1]
|
|
116
|
+
.map((k) => (layout.centers[0][k] + layout.centers[1][k]) / 2)
|
|
117
|
+
.concat(
|
|
118
|
+
Math.max(...layout.centers.map((c) => c[2])) + layout.radius * 0.5,
|
|
119
|
+
),
|
|
120
|
+
}
|
|
121
|
+
: cyclopsPlacement(
|
|
122
|
+
target.body.bounds,
|
|
123
|
+
previousEyes,
|
|
124
|
+
hasAuthoredLabel(bytes, target.body, 'metal'),
|
|
125
|
+
);
|
|
126
|
+
const origin = center(outer.bounds);
|
|
127
|
+
const scale = (placement.radius * 2) / span(outer.bounds, 0);
|
|
128
|
+
const white = await eyeRecord(
|
|
129
|
+
sourceBytes,
|
|
130
|
+
outer,
|
|
131
|
+
origin,
|
|
132
|
+
scale,
|
|
133
|
+
placement.center,
|
|
134
|
+
'white',
|
|
135
|
+
);
|
|
136
|
+
const pupilOrigin = center(pupil.bounds);
|
|
137
|
+
const front = white.bounds.max[2];
|
|
138
|
+
const layers = [
|
|
139
|
+
['rim', 0.57, [0.012, 0.08, 0.075], 0, 0],
|
|
140
|
+
['iris', 0.53, [0.035, 0.48, 0.37], 0, 0],
|
|
141
|
+
['pupil', 0.275, [0.006, 0.012, 0.016], 0, 0],
|
|
142
|
+
['glint', 0.065, [1, 1, 1], -0.19, 0.23],
|
|
143
|
+
];
|
|
144
|
+
const records = [white];
|
|
145
|
+
let previousFront = front;
|
|
146
|
+
for (const [role, radius, color, x, y] of layers) {
|
|
147
|
+
const partScale = (placement.radius * radius * 2) / span(pupil.bounds, 0);
|
|
148
|
+
// Align visible fronts, not centers: iris and pupil have different depths.
|
|
149
|
+
// Equal center positions hide the smaller pupil behind the larger iris.
|
|
150
|
+
const destinationZ =
|
|
151
|
+
previousFront +
|
|
152
|
+
0.006 -
|
|
153
|
+
(pupil.bounds.max[2] - pupilOrigin[2]) * partScale;
|
|
154
|
+
const layer = await eyeRecord(
|
|
155
|
+
sourceBytes,
|
|
156
|
+
pupil,
|
|
157
|
+
pupilOrigin,
|
|
158
|
+
partScale,
|
|
159
|
+
[
|
|
160
|
+
placement.center[0] + x * placement.radius,
|
|
161
|
+
placement.center[1] + y * placement.radius,
|
|
162
|
+
destinationZ,
|
|
163
|
+
],
|
|
164
|
+
role,
|
|
165
|
+
color,
|
|
166
|
+
);
|
|
167
|
+
records.push(layer);
|
|
168
|
+
previousFront = layer.bounds.max[2];
|
|
169
|
+
}
|
|
170
|
+
const eyeIds = new Set(previousEyes.map((p) => p.part));
|
|
171
|
+
const retained = target.records
|
|
172
|
+
.filter((p) => !eyeIds.has(p.part) && !hasAuthoredLabel(bytes, p, 'brows'))
|
|
173
|
+
.map((p) => ({
|
|
174
|
+
bytes: bytes.slice(p.start, p.end),
|
|
175
|
+
name: p.name,
|
|
176
|
+
bounds: p.bounds,
|
|
177
|
+
}));
|
|
178
|
+
retained.splice(1, 0, ...records);
|
|
179
|
+
return assembleAuthoredRecords(target, retained);
|
|
180
|
+
}
|