@oxy.so/bloom 7.1.4 → 7.1.5
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 +19 -114
- package/assets/character-runtime/legacy-engine.mjs +54 -406
- package/assets/character-runtime/legacy-geometry.mjs +85 -242
- package/assets/character-runtime/legacy-worker.mjs +23 -82
- package/assets/character-runtime/managed-avatar.mjs +18 -12
- package/assets/character-runtime/render-budget.mjs +11 -6
- package/assets/character-runtime/runtime.mjs +295 -744
- package/docs/agent-avatar.mdx +8 -45
- package/docs/agent-creator.mdx +3 -13
- 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 +1 -2
- package/lib/commonjs/agent-avatar/CharacterAvatar.js.map +1 -1
- package/lib/commonjs/agent-avatar/config-character.js +0 -4
- package/lib/commonjs/agent-avatar/config-character.js.map +1 -1
- package/lib/commonjs/agent-avatar/legacy-recipe.js +6 -19
- package/lib/commonjs/agent-avatar/legacy-recipe.js.map +1 -1
- package/lib/commonjs/agent-creator/AgentCreatorBase.js +107 -67
- package/lib/commonjs/agent-creator/AgentCreatorBase.js.map +1 -1
- package/lib/commonjs/agent-creator/CharacterControls.js +5 -23
- package/lib/commonjs/agent-creator/CharacterControls.js.map +1 -1
- package/lib/commonjs/agent-creator/EmotionPicker.js +1 -8
- package/lib/commonjs/agent-creator/EmotionPicker.js.map +1 -1
- package/lib/commonjs/agent-creator/ShapeSilhouette.js +1 -8
- package/lib/commonjs/agent-creator/ShapeSilhouette.js.map +1 -1
- package/lib/commonjs/agent-creator/constants.js +17 -16
- 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/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/module/agent-avatar/AgentAvatar.js +1 -1
- package/lib/module/agent-avatar/AgentAvatar.js.map +1 -1
- package/lib/module/agent-avatar/CharacterAvatar.js +1 -2
- package/lib/module/agent-avatar/CharacterAvatar.js.map +1 -1
- package/lib/module/agent-avatar/config-character.js +0 -4
- package/lib/module/agent-avatar/config-character.js.map +1 -1
- package/lib/module/agent-avatar/legacy-recipe.js +6 -19
- package/lib/module/agent-avatar/legacy-recipe.js.map +1 -1
- package/lib/module/agent-creator/AgentCreatorBase.js +109 -69
- package/lib/module/agent-creator/AgentCreatorBase.js.map +1 -1
- package/lib/module/agent-creator/CharacterControls.js +6 -24
- package/lib/module/agent-creator/CharacterControls.js.map +1 -1
- package/lib/module/agent-creator/EmotionPicker.js +1 -8
- package/lib/module/agent-creator/EmotionPicker.js.map +1 -1
- package/lib/module/agent-creator/ShapeSilhouette.js +1 -8
- package/lib/module/agent-creator/ShapeSilhouette.js.map +1 -1
- package/lib/module/agent-creator/constants.js +16 -8
- 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/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/typescript/commonjs/agent-avatar/CharacterAvatar.d.ts.map +1 -1
- package/lib/typescript/commonjs/agent-avatar/config-character.d.ts +0 -4
- package/lib/typescript/commonjs/agent-avatar/config-character.d.ts.map +1 -1
- package/lib/typescript/commonjs/agent-avatar/legacy-recipe.d.ts +10 -2
- 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 +1 -2
- package/lib/typescript/commonjs/agent-creator/CharacterControls.d.ts.map +1 -1
- package/lib/typescript/commonjs/agent-creator/EmotionPicker.d.ts +0 -1
- 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/constants.d.ts +15 -7
- 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/module/agent-avatar/CharacterAvatar.d.ts.map +1 -1
- package/lib/typescript/module/agent-avatar/config-character.d.ts +0 -4
- package/lib/typescript/module/agent-avatar/config-character.d.ts.map +1 -1
- package/lib/typescript/module/agent-avatar/legacy-recipe.d.ts +10 -2
- 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 +1 -2
- package/lib/typescript/module/agent-creator/CharacterControls.d.ts.map +1 -1
- package/lib/typescript/module/agent-creator/EmotionPicker.d.ts +0 -1
- 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/constants.d.ts +15 -7
- 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/package.json +1 -1
- package/src/agent-avatar/AgentAvatar.tsx +1 -1
- package/src/agent-avatar/CharacterAvatar.tsx +1 -4
- package/src/agent-avatar/config-character.ts +6 -39
- package/src/agent-avatar/legacy-recipe.ts +6 -34
- package/src/agent-creator/AgentCreatorBase.tsx +152 -121
- package/src/agent-creator/CharacterControls.tsx +14 -39
- package/src/agent-creator/EmotionPicker.tsx +16 -55
- package/src/agent-creator/ShapeSilhouette.tsx +1 -16
- package/src/agent-creator/constants.ts +14 -47
- package/src/agent-creator/messages.ts +1 -2
- 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/assets/character-runtime/authored-parts.mjs +0 -754
- package/assets/character-runtime/catalog-parts.mjs +0 -362
- package/assets/character-runtime/character-recipe.mjs +0 -247
- package/assets/character-runtime/clippo-geometry.mjs +0 -679
- package/assets/character-runtime/controller-mode.mjs +0 -208
- package/assets/character-runtime/cyclops-geometry.mjs +0 -180
- package/assets/character-runtime/migrated-contours.mjs +0 -2067
- package/assets/character-runtime/migrated-faces.mjs +0 -59
- package/assets/character-runtime/pose-transition.mjs +0 -523
- package/assets/character-runtime/preparation-cache.mjs +0 -60
- package/assets/character-runtime/render-errors.mjs +0 -180
- package/assets/character-runtime/resolution.mjs +0 -10
- package/assets/character-runtime/sha256.mjs +0 -44
- package/assets/character-runtime/shared-programs.mjs +0 -534
- package/assets/character-runtime/shared-surface.mjs +0 -490
- package/assets/character-runtime/shared-textures.mjs +0 -420
- package/assets/character-runtime/thumbnails/eyes/todd.png +0 -0
- package/lib/commonjs/agent-avatar/character-colors.js +0 -19
- package/lib/commonjs/agent-avatar/character-colors.js.map +0 -1
- package/lib/commonjs/agent-avatar/character-shapes.js +0 -106
- package/lib/commonjs/agent-avatar/character-shapes.js.map +0 -1
- package/lib/commonjs/agent-creator/ClippoArtwork.js +0 -63
- package/lib/commonjs/agent-creator/ClippoArtwork.js.map +0 -1
- package/lib/commonjs/agent-creator/CyclopsArtwork.js +0 -45
- package/lib/commonjs/agent-creator/CyclopsArtwork.js.map +0 -1
- package/lib/commonjs/agent-creator/ToddArtwork.js +0 -29
- package/lib/commonjs/agent-creator/ToddArtwork.js.map +0 -1
- package/lib/module/agent-avatar/character-colors.js +0 -15
- package/lib/module/agent-avatar/character-colors.js.map +0 -1
- package/lib/module/agent-avatar/character-shapes.js +0 -97
- package/lib/module/agent-avatar/character-shapes.js.map +0 -1
- package/lib/module/agent-creator/ClippoArtwork.js +0 -59
- package/lib/module/agent-creator/ClippoArtwork.js.map +0 -1
- package/lib/module/agent-creator/CyclopsArtwork.js +0 -41
- package/lib/module/agent-creator/CyclopsArtwork.js.map +0 -1
- package/lib/module/agent-creator/ToddArtwork.js +0 -25
- package/lib/module/agent-creator/ToddArtwork.js.map +0 -1
- package/lib/typescript/commonjs/agent-avatar/character-colors.d.ts +0 -13
- package/lib/typescript/commonjs/agent-avatar/character-colors.d.ts.map +0 -1
- package/lib/typescript/commonjs/agent-avatar/character-shapes.d.ts +0 -19
- package/lib/typescript/commonjs/agent-avatar/character-shapes.d.ts.map +0 -1
- package/lib/typescript/commonjs/agent-creator/ClippoArtwork.d.ts +0 -6
- package/lib/typescript/commonjs/agent-creator/ClippoArtwork.d.ts.map +0 -1
- package/lib/typescript/commonjs/agent-creator/CyclopsArtwork.d.ts +0 -5
- package/lib/typescript/commonjs/agent-creator/CyclopsArtwork.d.ts.map +0 -1
- package/lib/typescript/commonjs/agent-creator/ToddArtwork.d.ts +0 -6
- package/lib/typescript/commonjs/agent-creator/ToddArtwork.d.ts.map +0 -1
- package/lib/typescript/module/agent-avatar/character-colors.d.ts +0 -13
- package/lib/typescript/module/agent-avatar/character-colors.d.ts.map +0 -1
- package/lib/typescript/module/agent-avatar/character-shapes.d.ts +0 -19
- package/lib/typescript/module/agent-avatar/character-shapes.d.ts.map +0 -1
- package/lib/typescript/module/agent-creator/ClippoArtwork.d.ts +0 -6
- package/lib/typescript/module/agent-creator/ClippoArtwork.d.ts.map +0 -1
- package/lib/typescript/module/agent-creator/CyclopsArtwork.d.ts +0 -5
- package/lib/typescript/module/agent-creator/CyclopsArtwork.d.ts.map +0 -1
- package/lib/typescript/module/agent-creator/ToddArtwork.d.ts +0 -6
- package/lib/typescript/module/agent-creator/ToddArtwork.d.ts.map +0 -1
- package/src/agent-avatar/character-colors.ts +0 -12
- package/src/agent-avatar/character-shapes.ts +0 -122
- package/src/agent-creator/ClippoArtwork.tsx +0 -49
- package/src/agent-creator/CyclopsArtwork.tsx +0 -27
- package/src/agent-creator/ToddArtwork.tsx +0 -24
|
@@ -1,28 +1,19 @@
|
|
|
1
1
|
// Adapter for the recovered renderer's prepared vertex layout. Packaged meshes,
|
|
2
2
|
// resource manifests, the WASM binary, and the appearance record stay untouched.
|
|
3
|
-
const decoder = new TextDecoder(),
|
|
4
|
-
|
|
5
|
-
const BODY = ":body:no-shadow:studio-fur-v6:";
|
|
3
|
+
const decoder = new TextDecoder(), encoder = new TextEncoder();
|
|
4
|
+
const BODY = ':body:no-shadow:studio-fur-v6:';
|
|
6
5
|
// Highlights are separate non-shadow-casting meshes in the original renderer.
|
|
7
|
-
const SURFACES = [
|
|
6
|
+
const SURFACES = [':surface:shadow', ':surface:no-shadow'];
|
|
8
7
|
const SURFACE_KEY = /^[a-f0-9]{64}:surface:(?:shadow|no-shadow)$/;
|
|
9
8
|
const FUR_SURFACE_KEY = /^[a-f0-9]{64}:surface:shadow:studio-fur-v6:/;
|
|
10
|
-
const STRIDE = 96,
|
|
11
|
-
|
|
12
|
-
function invalid(
|
|
13
|
-
throw new Error(`Unsupported prepared avatar geometry: ${message}`);
|
|
14
|
-
}
|
|
15
|
-
function finite(value) {
|
|
16
|
-
if (!Number.isFinite(value)) invalid("non-finite coordinate");
|
|
17
|
-
return value;
|
|
18
|
-
}
|
|
9
|
+
const STRIDE = 96, TAU = Math.PI * 2;
|
|
10
|
+
function invalid(message) { throw new Error(`Unsupported prepared avatar geometry: ${message}`); }
|
|
11
|
+
function finite(value) { if (!Number.isFinite(value)) invalid('non-finite coordinate'); return value; }
|
|
19
12
|
function findAll(bytes, text) {
|
|
20
|
-
const needle = encoder.encode(text),
|
|
21
|
-
result = [];
|
|
13
|
+
const needle = encoder.encode(text), result = [];
|
|
22
14
|
outer: for (let i = 0; i <= bytes.length - needle.length; i++) {
|
|
23
15
|
if (bytes[i] !== needle[0]) continue;
|
|
24
|
-
for (let j = 1; j < needle.length; j++)
|
|
25
|
-
if (bytes[i + j] !== needle[j]) continue outer;
|
|
16
|
+
for (let j = 1; j < needle.length; j++) if (bytes[i + j] !== needle[j]) continue outer;
|
|
26
17
|
result.push(i);
|
|
27
18
|
}
|
|
28
19
|
return result;
|
|
@@ -30,187 +21,82 @@ function findAll(bytes, text) {
|
|
|
30
21
|
|
|
31
22
|
/** Inspect the bounded, length-prefixed mesh records; reject unknown layouts. */
|
|
32
23
|
export function inspectLegacyAssembly(bytes) {
|
|
33
|
-
if (!(bytes instanceof Uint8Array) || bytes.length < 400)
|
|
34
|
-
invalid("truncated assembly");
|
|
24
|
+
if (!(bytes instanceof Uint8Array) || bytes.length < 400) invalid('truncated assembly');
|
|
35
25
|
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
36
|
-
const uint = (at)
|
|
37
|
-
if (at < 0 || at + 4 > bytes.length) invalid("truncated count");
|
|
38
|
-
return view.getUint32(at, true);
|
|
39
|
-
};
|
|
26
|
+
const uint = at => { if (at < 0 || at + 4 > bytes.length) invalid('truncated count'); return view.getUint32(at, true); };
|
|
40
27
|
const bodies = findAll(bytes, BODY);
|
|
41
|
-
if (bodies.length !== 1) invalid(
|
|
28
|
+
if (bodies.length !== 1) invalid('expected one furry body');
|
|
42
29
|
const bodyStart = bodies[0] - 64;
|
|
43
|
-
const starts = [
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const name = decoder.decode(bytes.subarray(i, i + length));
|
|
54
|
-
return SURFACE_KEY.test(name) || FUR_SURFACE_KEY.test(name);
|
|
55
|
-
}),
|
|
56
|
-
).sort((a, b) => a - b),
|
|
57
|
-
];
|
|
30
|
+
const starts = [bodyStart, ...SURFACES.flatMap(kind => findAll(bytes, kind)
|
|
31
|
+
.map(i => i - 64)
|
|
32
|
+
.filter(i => {
|
|
33
|
+
if (i <= bodyStart || i < 4) return false;
|
|
34
|
+
const length = uint(i - 4);
|
|
35
|
+
if (length < 79 || length > 8192 || i + length > bytes.length) return false;
|
|
36
|
+
const name = decoder.decode(bytes.subarray(i, i + length));
|
|
37
|
+
return SURFACE_KEY.test(name) || FUR_SURFACE_KEY.test(name);
|
|
38
|
+
}))
|
|
39
|
+
.sort((a, b) => a - b)];
|
|
58
40
|
const meshCount = uint(0);
|
|
59
|
-
if (meshCount !== starts.length || meshCount > 40)
|
|
60
|
-
invalid("mesh count/key mismatch");
|
|
41
|
+
if (meshCount !== starts.length || meshCount > 40) invalid('mesh count/key mismatch');
|
|
61
42
|
const parts = starts.map((nameOffset, part) => {
|
|
62
|
-
const nameLength = uint(nameOffset - 4),
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (
|
|
67
|
-
nameLength < 79 ||
|
|
68
|
-
nameLength > 8192 ||
|
|
69
|
-
nameOffset + nameLength > bytes.length ||
|
|
70
|
-
!/^[a-f0-9]{64}:/.test(name)
|
|
71
|
-
)
|
|
72
|
-
invalid("mesh identity");
|
|
73
|
-
if (
|
|
74
|
-
part === 0
|
|
75
|
-
? !name.includes(BODY)
|
|
76
|
-
: !SURFACE_KEY.test(name) && !FUR_SURFACE_KEY.test(name)
|
|
77
|
-
)
|
|
78
|
-
invalid("mesh kind");
|
|
79
|
-
const vertexCount = uint(nameOffset + nameLength),
|
|
80
|
-
vertexOffset = nameOffset + nameLength + 4;
|
|
81
|
-
if (vertexCount < 3 || vertexCount > 1000000) invalid("vertex count");
|
|
43
|
+
const nameLength = uint(nameOffset - 4), name = decoder.decode(bytes.subarray(nameOffset, nameOffset + nameLength));
|
|
44
|
+
if (nameLength < 79 || nameLength > 8192 || nameOffset + nameLength > bytes.length || !/^[a-f0-9]{64}:/.test(name)) invalid('mesh identity');
|
|
45
|
+
if (part === 0 ? !name.includes(BODY) : !SURFACE_KEY.test(name) && !FUR_SURFACE_KEY.test(name)) invalid('mesh kind');
|
|
46
|
+
const vertexCount = uint(nameOffset + nameLength), vertexOffset = nameOffset + nameLength + 4;
|
|
47
|
+
if (vertexCount < 3 || vertexCount > 1000000) invalid('vertex count');
|
|
82
48
|
let at = vertexOffset + vertexCount * STRIDE;
|
|
83
|
-
const count32 = uint(at);
|
|
84
|
-
at
|
|
85
|
-
|
|
86
|
-
invalid("32-bit indices");
|
|
87
|
-
for (let i = 0; i < count32; i++)
|
|
88
|
-
if (uint(at + i * 4) >= vertexCount) invalid("index outside mesh");
|
|
49
|
+
const count32 = uint(at); at += 4;
|
|
50
|
+
if (count32 > 6000000 || at + count32 * 4 > bytes.length) invalid('32-bit indices');
|
|
51
|
+
for (let i = 0; i < count32; i++) if (uint(at + i * 4) >= vertexCount) invalid('index outside mesh');
|
|
89
52
|
at += count32 * 4;
|
|
90
|
-
const count16 = uint(at);
|
|
91
|
-
at
|
|
92
|
-
|
|
93
|
-
invalid("16-bit indices");
|
|
94
|
-
for (let i = 0; i < count16; i++)
|
|
95
|
-
if (view.getUint16(at + i * 2, true) >= vertexCount)
|
|
96
|
-
invalid("index outside mesh");
|
|
53
|
+
const count16 = uint(at); at += 4;
|
|
54
|
+
if (count16 > 6000000 || at + count16 * 2 > bytes.length) invalid('16-bit indices');
|
|
55
|
+
for (let i = 0; i < count16; i++) if (view.getUint16(at + i * 2, true) >= vertexCount) invalid('index outside mesh');
|
|
97
56
|
at += count16 * 2;
|
|
98
57
|
// Empty supplemental vertex buffer followed by three boolean mesh flags.
|
|
99
|
-
if (
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
bytes[at + 5] > 1 ||
|
|
104
|
-
bytes[at + 6] > 1
|
|
105
|
-
)
|
|
106
|
-
invalid("mesh flags");
|
|
107
|
-
const hasFur = bytes[at + 6] === 1;
|
|
108
|
-
at += 7;
|
|
109
|
-
const furCount = hasFur ? uint(at) : 0,
|
|
110
|
-
furOffset = hasFur ? at + 4 : 0;
|
|
111
|
-
if (
|
|
112
|
-
furCount > 1000000 ||
|
|
113
|
-
(hasFur && furOffset + furCount * 64 > bytes.length)
|
|
114
|
-
)
|
|
115
|
-
invalid("fur records");
|
|
58
|
+
if (at + 7 > bytes.length || uint(at) !== 0 || bytes[at + 4] > 1 || bytes[at + 5] > 1 || bytes[at + 6] > 1) invalid('mesh flags');
|
|
59
|
+
const hasFur = bytes[at + 6] === 1; at += 7;
|
|
60
|
+
const furCount = hasFur ? uint(at) : 0, furOffset = hasFur ? at + 4 : 0;
|
|
61
|
+
if (furCount > 1000000 || hasFur && furOffset + furCount * 64 > bytes.length) invalid('fur records');
|
|
116
62
|
const geometryEnd = hasFur ? furOffset + furCount * 64 : at;
|
|
117
|
-
if (
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
max = [-Infinity, -Infinity, -Infinity];
|
|
127
|
-
for (let i = 0; i < vertexCount; i++)
|
|
128
|
-
for (let k = 0; k < 24; k++) {
|
|
129
|
-
const value = finite(
|
|
130
|
-
view.getFloat32(vertexOffset + i * STRIDE + k * 4, true),
|
|
131
|
-
);
|
|
132
|
-
if (k < 3) {
|
|
133
|
-
min[k] = Math.min(min[k], value);
|
|
134
|
-
max[k] = Math.max(max[k], value);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
return {
|
|
138
|
-
part,
|
|
139
|
-
name,
|
|
140
|
-
nameOffset,
|
|
141
|
-
nameLength,
|
|
142
|
-
vertexCount,
|
|
143
|
-
vertexOffset,
|
|
144
|
-
furCount,
|
|
145
|
-
furOffset,
|
|
146
|
-
geometryEnd,
|
|
147
|
-
bounds: { min, max },
|
|
148
|
-
};
|
|
63
|
+
if (geometryEnd > (starts[part + 1] === undefined ? bytes.length : starts[part + 1] - 4)) invalid('overlapping meshes');
|
|
64
|
+
if (part === 0 && !hasFur) invalid('body lacks fur layout');
|
|
65
|
+
if (FUR_SURFACE_KEY.test(name) && !hasFur) invalid('accessory lacks fur layout');
|
|
66
|
+
const min = [Infinity, Infinity, Infinity], max = [-Infinity, -Infinity, -Infinity];
|
|
67
|
+
for (let i = 0; i < vertexCount; i++) for (let k = 0; k < 24; k++) {
|
|
68
|
+
const value = finite(view.getFloat32(vertexOffset + i * STRIDE + k * 4, true));
|
|
69
|
+
if (k < 3) { min[k] = Math.min(min[k], value); max[k] = Math.max(max[k], value); }
|
|
70
|
+
}
|
|
71
|
+
return { part, name, nameOffset, nameLength, vertexCount, vertexOffset, furCount, furOffset, bounds: { min, max } };
|
|
149
72
|
});
|
|
150
73
|
return { body: parts[0], parts };
|
|
151
74
|
}
|
|
152
75
|
|
|
153
76
|
function mapper({ points, radii, depthScale = 1 }) {
|
|
154
|
-
if (!Number.isFinite(depthScale) || depthScale <= 0 || depthScale > 4)
|
|
155
|
-
|
|
156
|
-
if ((points && radii) || (!points && !radii))
|
|
157
|
-
invalid("provide points or radii");
|
|
77
|
+
if (!Number.isFinite(depthScale) || depthScale <= 0 || depthScale > 4) invalid('depth scale');
|
|
78
|
+
if (points && radii || !points && !radii) invalid('provide points or radii');
|
|
158
79
|
const count = (points || radii).length;
|
|
159
|
-
if (count < 16 || count > 65536) invalid(
|
|
160
|
-
if (points)
|
|
161
|
-
|
|
162
|
-
if (p.length !== 2) invalid("contour point");
|
|
163
|
-
p.forEach(finite);
|
|
164
|
-
}
|
|
165
|
-
else
|
|
166
|
-
for (const radius of radii)
|
|
167
|
-
if (!(finite(radius) > 0)) invalid("contour radius");
|
|
80
|
+
if (count < 16 || count > 65536) invalid('contour resolution');
|
|
81
|
+
if (points) for (const p of points) { if (p.length !== 2) invalid('contour point'); p.forEach(finite); }
|
|
82
|
+
else for (const radius of radii) if (!(finite(radius) > 0)) invalid('contour radius');
|
|
168
83
|
return (x, y, z) => {
|
|
169
|
-
const radius = Math.hypot(x, y),
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
index = Math.floor(slot),
|
|
173
|
-
t = slot - index,
|
|
174
|
-
next = (index + 1) % count;
|
|
175
|
-
if (points)
|
|
176
|
-
return [
|
|
177
|
-
radius * (points[index][0] * (1 - t) + points[next][0] * t),
|
|
178
|
-
radius * (points[index][1] * (1 - t) + points[next][1] * t),
|
|
179
|
-
z * depthScale,
|
|
180
|
-
];
|
|
84
|
+
const radius = Math.hypot(x, y), angle = (Math.atan2(y, x) + TAU) % TAU;
|
|
85
|
+
const slot = angle / TAU * count, index = Math.floor(slot), t = slot - index, next = (index + 1) % count;
|
|
86
|
+
if (points) return [radius * (points[index][0] * (1 - t) + points[next][0] * t), radius * (points[index][1] * (1 - t) + points[next][1] * t), z * depthScale];
|
|
181
87
|
const scale = radii[index] * (1 - t) + radii[next] * t;
|
|
182
88
|
return [x * scale, y * scale, z * depthScale];
|
|
183
89
|
};
|
|
184
90
|
}
|
|
185
91
|
function derivative(map, p) {
|
|
186
|
-
const epsilon =
|
|
187
|
-
|
|
188
|
-
const columns = [0, 1, 2].map((k) => {
|
|
189
|
-
const q = [...p];
|
|
190
|
-
q[k] += epsilon;
|
|
191
|
-
return map(...q).map((v, i) => (v - base[i]) / epsilon);
|
|
192
|
-
});
|
|
92
|
+
const epsilon = .00005, base = map(...p);
|
|
93
|
+
const columns = [0, 1, 2].map(k => { const q = [...p]; q[k] += epsilon; return map(...q).map((v, i) => (v - base[i]) / epsilon); });
|
|
193
94
|
const [a, b, c] = columns;
|
|
194
|
-
const cross = (u, v) => [
|
|
195
|
-
u[1] * v[2] - u[2] * v[1],
|
|
196
|
-
u[2] * v[0] - u[0] * v[2],
|
|
197
|
-
u[0] * v[1] - u[1] * v[0],
|
|
198
|
-
];
|
|
95
|
+
const cross = (u, v) => [u[1] * v[2] - u[2] * v[1], u[2] * v[0] - u[0] * v[2], u[0] * v[1] - u[1] * v[0]];
|
|
199
96
|
const inverse = [cross(b, c), cross(c, a), cross(a, b)];
|
|
200
97
|
const determinant = a.reduce((sum, v, i) => sum + v * inverse[0][i], 0);
|
|
201
|
-
if (Math.abs(determinant) <
|
|
202
|
-
return {
|
|
203
|
-
base,
|
|
204
|
-
vector: (v) =>
|
|
205
|
-
[0, 1, 2].map((i) =>
|
|
206
|
-
columns.reduce((sum, col, j) => sum + col[i] * v[j], 0),
|
|
207
|
-
),
|
|
208
|
-
normal: (v) =>
|
|
209
|
-
[0, 1, 2].map(
|
|
210
|
-
(i) =>
|
|
211
|
-
inverse.reduce((sum, col, j) => sum + col[i] * v[j], 0) / determinant,
|
|
212
|
-
),
|
|
213
|
-
};
|
|
98
|
+
if (Math.abs(determinant) < .000001) invalid('singular contour');
|
|
99
|
+
return { base, vector: v => [0, 1, 2].map(i => columns.reduce((sum, col, j) => sum + col[i] * v[j], 0)), normal: v => [0, 1, 2].map(i => inverse.reduce((sum, col, j) => sum + col[i] * v[j], 0) / determinant) };
|
|
214
100
|
}
|
|
215
101
|
|
|
216
102
|
/** Rigid attachment anchors on the source circle, in the engine's XY units.
|
|
@@ -219,10 +105,9 @@ function derivative(map, p) {
|
|
|
219
105
|
*/
|
|
220
106
|
export function legacyAttachmentOffset(points, accessory) {
|
|
221
107
|
let anchor;
|
|
222
|
-
if (accessory ===
|
|
223
|
-
else if (accessory ===
|
|
224
|
-
else if ([
|
|
225
|
-
anchor = [0, 1, 0];
|
|
108
|
+
if (accessory === 'bow') anchor = [0, -1, 0];
|
|
109
|
+
else if (accessory === 'three_lobe') anchor = [-.5, Math.sqrt(.75), 0];
|
|
110
|
+
else if (['beanie', 'hat', 'beret', 'orb', 'crown'].includes(accessory)) anchor = [0, 1, 0];
|
|
226
111
|
else return undefined;
|
|
227
112
|
return mapper({ points })(...anchor).map((value, i) => value - anchor[i]);
|
|
228
113
|
}
|
|
@@ -235,89 +120,47 @@ export function legacyAttachmentOffset(points, accessory) {
|
|
|
235
120
|
* Attachments may explicitly transform a numbered part around an origin.
|
|
236
121
|
*/
|
|
237
122
|
export function deformLegacyAssembly(bytes, options) {
|
|
238
|
-
const info = inspectLegacyAssembly(bytes),
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
const read = (at) => [0, 1, 2].map((i) => view.getFloat32(at + i * 4, true));
|
|
245
|
-
const write = (at, values) =>
|
|
246
|
-
values.forEach((v, i) => view.setFloat32(at + i * 4, finite(v), true));
|
|
247
|
-
const unit = (v) => {
|
|
248
|
-
const n = Math.hypot(...v);
|
|
249
|
-
return n > 1e-9 ? v.map((x) => x / n) : v;
|
|
250
|
-
};
|
|
123
|
+
const info = inspectLegacyAssembly(bytes), result = bytes.slice();
|
|
124
|
+
if (!/^[a-f0-9]{64}$/.test(options.geometryKey || '')) invalid('missing geometry cache key');
|
|
125
|
+
const view = new DataView(result.buffer), map = mapper(options);
|
|
126
|
+
const read = at => [0, 1, 2].map(i => view.getFloat32(at + i * 4, true));
|
|
127
|
+
const write = (at, values) => values.forEach((v, i) => view.setFloat32(at + i * 4, finite(v), true));
|
|
128
|
+
const unit = v => { const n = Math.hypot(...v); return n > 1e-9 ? v.map(x => x / n) : v; };
|
|
251
129
|
function transform(part, mapping) {
|
|
252
130
|
for (let i = 0; i < part.vertexCount; i++) {
|
|
253
|
-
const at = part.vertexOffset + i * STRIDE,
|
|
254
|
-
p = read(at),
|
|
255
|
-
d = derivative(mapping, p);
|
|
131
|
+
const at = part.vertexOffset + i * STRIDE, p = read(at), d = derivative(mapping, p);
|
|
256
132
|
// The two pose positions are DELTAS: preserve zero as zero and deform the
|
|
257
133
|
// target position before subtracting the newly transformed base.
|
|
258
|
-
for (const offset of [24, 48]) {
|
|
259
|
-
|
|
260
|
-
target = mapping(...p.map((v, k) => v + delta[k]));
|
|
261
|
-
write(
|
|
262
|
-
at + offset,
|
|
263
|
-
target.map((v, k) => v - d.base[k]),
|
|
264
|
-
);
|
|
265
|
-
}
|
|
266
|
-
for (const offset of [12, 36, 60, 84])
|
|
267
|
-
write(at + offset, unit(d.normal(read(at + offset))));
|
|
134
|
+
for (const offset of [24, 48]) { const delta = read(at + offset), target = mapping(...p.map((v, k) => v + delta[k])); write(at + offset, target.map((v, k) => v - d.base[k])); }
|
|
135
|
+
for (const offset of [12, 36, 60, 84]) write(at + offset, unit(d.normal(read(at + offset))));
|
|
268
136
|
write(at, d.base);
|
|
269
137
|
}
|
|
270
138
|
for (let i = 0; i < part.furCount; i++) {
|
|
271
|
-
const at = part.furOffset + i * 64,
|
|
272
|
-
|
|
273
|
-
write(at, d.base);
|
|
274
|
-
write(at + 12, unit(d.normal(read(at + 12))));
|
|
275
|
-
write(at + 24, unit(d.vector(read(at + 24))));
|
|
139
|
+
const at = part.furOffset + i * 64, d = derivative(mapping, read(at));
|
|
140
|
+
write(at, d.base); write(at + 12, unit(d.normal(read(at + 12)))); write(at + 24, unit(d.vector(read(at + 24))));
|
|
276
141
|
}
|
|
277
142
|
result.set(encoder.encode(options.geometryKey), part.nameOffset);
|
|
278
143
|
}
|
|
279
144
|
transform(info.body, map);
|
|
280
145
|
for (const attachment of options.attachments || []) {
|
|
281
146
|
const part = info.parts[attachment.part];
|
|
282
|
-
if (!part || part.part === 0) invalid(
|
|
283
|
-
const scale = attachment.scale || [1, 1, 1],
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
if (
|
|
287
|
-
[scale, origin, translate].some(
|
|
288
|
-
(v) => v.length !== 3 || v.some((x) => !Number.isFinite(x)),
|
|
289
|
-
) ||
|
|
290
|
-
scale.some((x) => x <= 0)
|
|
291
|
-
)
|
|
292
|
-
invalid("attachment transform");
|
|
293
|
-
transform(part, (...p) =>
|
|
294
|
-
p.map((v, k) => (v - origin[k]) * scale[k] + origin[k] + translate[k]),
|
|
295
|
-
);
|
|
147
|
+
if (!part || part.part === 0) invalid('attachment index');
|
|
148
|
+
const scale = attachment.scale || [1, 1, 1], origin = attachment.origin || [0, 0, 0], translate = attachment.translate || [0, 0, 0];
|
|
149
|
+
if ([scale, origin, translate].some(v => v.length !== 3 || v.some(x => !Number.isFinite(x))) || scale.some(x => x <= 0)) invalid('attachment transform');
|
|
150
|
+
transform(part, (...p) => p.map((v, k) => (v - origin[k]) * scale[k] + origin[k] + translate[k]));
|
|
296
151
|
// Independent transformed parts must not alias the body's cache identity.
|
|
297
152
|
const key = options.attachmentKeys?.[attachment.part];
|
|
298
|
-
if (!/^[a-f0-9]{64}$/.test(key ||
|
|
153
|
+
if (!/^[a-f0-9]{64}$/.test(key || '')) invalid('attachment cache key');
|
|
299
154
|
result.set(encoder.encode(key), part.nameOffset);
|
|
300
155
|
}
|
|
301
156
|
// Keep original extents while admitting moved accessories and the new body.
|
|
302
|
-
const transformed = [
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
const p = read(part.vertexOffset + i * STRIDE);
|
|
309
|
-
for (let k = 0; k < 3; k++) {
|
|
310
|
-
view.setFloat32(
|
|
311
|
-
4 + k * 4,
|
|
312
|
-
Math.min(view.getFloat32(4 + k * 4, true), p[k]),
|
|
313
|
-
true,
|
|
314
|
-
);
|
|
315
|
-
view.setFloat32(
|
|
316
|
-
16 + k * 4,
|
|
317
|
-
Math.max(view.getFloat32(16 + k * 4, true), p[k]),
|
|
318
|
-
true,
|
|
319
|
-
);
|
|
320
|
-
}
|
|
157
|
+
const transformed = [info.body, ...(options.attachments || []).map(a => info.parts[a.part])];
|
|
158
|
+
for (const part of transformed) for (let i = 0; i < part.vertexCount; i++) {
|
|
159
|
+
const p = read(part.vertexOffset + i * STRIDE);
|
|
160
|
+
for (let k = 0; k < 3; k++) {
|
|
161
|
+
view.setFloat32(4 + k * 4, Math.min(view.getFloat32(4 + k * 4, true), p[k]), true);
|
|
162
|
+
view.setFloat32(16 + k * 4, Math.max(view.getFloat32(16 + k * 4, true), p[k]), true);
|
|
321
163
|
}
|
|
164
|
+
}
|
|
322
165
|
return result;
|
|
323
166
|
}
|
|
@@ -2,14 +2,6 @@
|
|
|
2
2
|
// the recovered engine, packaged meshes and native manifests remain intact.
|
|
3
3
|
import createModule from './orbit-characters.mjs';
|
|
4
4
|
import { decodeAppearance, encodeAppearance } from './appearance-codec.mjs';
|
|
5
|
-
import { composePresetBody, composeCatalogParts } from './catalog-parts.mjs';
|
|
6
|
-
import {
|
|
7
|
-
fitAuthoredEyeSpacing,
|
|
8
|
-
fitAuthoredHeadwear,
|
|
9
|
-
shapeFaceLayout,
|
|
10
|
-
authoredAssemblyRecords,
|
|
11
|
-
} from './authored-parts.mjs';
|
|
12
|
-
import { sha256 } from './sha256.mjs';
|
|
13
5
|
import {
|
|
14
6
|
deformLegacyAssembly,
|
|
15
7
|
inspectLegacyAssembly,
|
|
@@ -18,8 +10,13 @@ import {
|
|
|
18
10
|
const engine = createModule({
|
|
19
11
|
locateFile: (file) => new URL(file, import.meta.url).href,
|
|
20
12
|
});
|
|
21
|
-
const digest = (value) =>
|
|
22
|
-
|
|
13
|
+
const digest = async (value) =>
|
|
14
|
+
Array.from(
|
|
15
|
+
new Uint8Array(
|
|
16
|
+
await crypto.subtle.digest('SHA-256', typeof value === 'string' ? new TextEncoder().encode(value) : value),
|
|
17
|
+
),
|
|
18
|
+
(byte) => byte.toString(16).padStart(2, '0'),
|
|
19
|
+
).join('');
|
|
23
20
|
// Cache only identities, never the large prepared buffers. The same face with
|
|
24
21
|
// no accessories tells us exactly which meshes belong to eyes and eyewear.
|
|
25
22
|
const faceIdentities = new Map();
|
|
@@ -28,12 +25,8 @@ async function accessoryTransforms(module, data, source) {
|
|
|
28
25
|
// The editor selects one accessory. Preserve any unknown multi-accessory
|
|
29
26
|
// state rather than guessing which of its pieces should move together.
|
|
30
27
|
if (appearance.accessories.length !== 1) return {};
|
|
31
|
-
const translate = legacyAttachmentOffset(
|
|
32
|
-
|
|
33
|
-
appearance.accessories[0],
|
|
34
|
-
);
|
|
35
|
-
if (!translate || translate.every((value) => Math.abs(value) < 1e-6))
|
|
36
|
-
return {};
|
|
28
|
+
const translate = legacyAttachmentOffset(data.points, appearance.accessories[0]);
|
|
29
|
+
if (!translate || translate.every(value => Math.abs(value) < 1e-6)) return {};
|
|
37
30
|
appearance.accessories = [];
|
|
38
31
|
appearance.accessoryColors = {};
|
|
39
32
|
if (appearance.model) appearance.model.accessories = {};
|
|
@@ -41,35 +34,22 @@ async function accessoryTransforms(module, data, source) {
|
|
|
41
34
|
const key = `${await digest(bytes)}:${data.quality}:${data.activities}`;
|
|
42
35
|
let names = faceIdentities.get(key);
|
|
43
36
|
if (!names) {
|
|
44
|
-
const base = module.orbitPrepareAssembly(
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
`${data.key}:attachment-base`,
|
|
48
|
-
data.activities,
|
|
49
|
-
);
|
|
50
|
-
if (!base.bytes)
|
|
51
|
-
throw new Error(base.error || 'Accessory reference preparation failed');
|
|
52
|
-
names = new Set(
|
|
53
|
-
inspectLegacyAssembly(base.bytes)
|
|
54
|
-
.parts.slice(1)
|
|
55
|
-
.map((part) => part.name),
|
|
56
|
-
);
|
|
37
|
+
const base = module.orbitPrepareAssembly(bytes, data.quality, `${data.key}:attachment-base`, data.activities);
|
|
38
|
+
if (!base.bytes) throw new Error(base.error || 'Accessory reference preparation failed');
|
|
39
|
+
names = new Set(inspectLegacyAssembly(base.bytes).parts.slice(1).map(part => part.name));
|
|
57
40
|
faceIdentities.set(key, names);
|
|
58
|
-
if (faceIdentities.size > 32)
|
|
59
|
-
faceIdentities.delete(faceIdentities.keys().next().value);
|
|
41
|
+
if (faceIdentities.size > 32) faceIdentities.delete(faceIdentities.keys().next().value);
|
|
60
42
|
}
|
|
61
43
|
// Do not move anything unless every original face mesh survives unchanged.
|
|
62
|
-
const current = new Set(source.parts.slice(1).map(
|
|
63
|
-
if ([...names].some(
|
|
64
|
-
const attachments = source.parts
|
|
65
|
-
.
|
|
66
|
-
.
|
|
67
|
-
.map((part) => ({ part: part.part, translate }));
|
|
44
|
+
const current = new Set(source.parts.slice(1).map(part => part.name));
|
|
45
|
+
if ([...names].some(name => !current.has(name))) return {};
|
|
46
|
+
const attachments = source.parts.slice(1)
|
|
47
|
+
.filter(part => !names.has(part.name))
|
|
48
|
+
.map(part => ({ part: part.part, translate }));
|
|
68
49
|
const attachmentKeys = {};
|
|
69
|
-
for (const attachment of attachments)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
);
|
|
50
|
+
for (const attachment of attachments) attachmentKeys[attachment.part] = await digest(
|
|
51
|
+
JSON.stringify([source.parts[attachment.part].name, translate]),
|
|
52
|
+
);
|
|
73
53
|
return { attachments, attachmentKeys };
|
|
74
54
|
}
|
|
75
55
|
let queue = Promise.resolve();
|
|
@@ -83,12 +63,7 @@ self.onmessage = ({ data }) => {
|
|
|
83
63
|
data.key,
|
|
84
64
|
data.activities,
|
|
85
65
|
);
|
|
86
|
-
|
|
87
|
-
// face/donor reference calls must never overwrite the target scene.
|
|
88
|
-
if (result.bytes) result.bytes = result.bytes.slice();
|
|
89
|
-
if (result.bytes && data.authoredParts?.bodyPreset)
|
|
90
|
-
result.bytes = await composePresetBody(module, result.bytes, data);
|
|
91
|
-
if (result.bytes && data.points) {
|
|
66
|
+
if (result.bytes) {
|
|
92
67
|
const source = inspectLegacyAssembly(result.bytes);
|
|
93
68
|
const geometryKey = await digest(
|
|
94
69
|
JSON.stringify([source.body.name, data.points]),
|
|
@@ -96,43 +71,9 @@ self.onmessage = ({ data }) => {
|
|
|
96
71
|
result.bytes = deformLegacyAssembly(result.bytes, {
|
|
97
72
|
points: data.points,
|
|
98
73
|
geometryKey,
|
|
99
|
-
...
|
|
74
|
+
...await accessoryTransforms(module, data, source),
|
|
100
75
|
});
|
|
101
76
|
}
|
|
102
|
-
if (result.bytes && data.authoredParts)
|
|
103
|
-
data.faceLayout = shapeFaceLayout(
|
|
104
|
-
authoredAssemblyRecords(result.bytes),
|
|
105
|
-
data,
|
|
106
|
-
module,
|
|
107
|
-
);
|
|
108
|
-
if (
|
|
109
|
-
result.bytes &&
|
|
110
|
-
(data.authoredParts?.shape === 'clippo' ||
|
|
111
|
-
data.authoredParts?.eyes === 'clippo')
|
|
112
|
-
) {
|
|
113
|
-
const { composeClippoAssembly } = await import('./clippo-geometry.mjs');
|
|
114
|
-
result.bytes = await composeClippoAssembly(module, result.bytes, data);
|
|
115
|
-
}
|
|
116
|
-
if (result.bytes && data.authoredParts) {
|
|
117
|
-
result.bytes = await composeCatalogParts(module, result.bytes, data, [
|
|
118
|
-
'eyes',
|
|
119
|
-
'accessory',
|
|
120
|
-
]);
|
|
121
|
-
if (data.authoredParts.eyes === 'cyclops') {
|
|
122
|
-
const { composeCyclopsAssembly } =
|
|
123
|
-
await import('./cyclops-geometry.mjs');
|
|
124
|
-
result.bytes = await composeCyclopsAssembly(
|
|
125
|
-
module,
|
|
126
|
-
result.bytes,
|
|
127
|
-
data,
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
result.bytes = await composeCatalogParts(module, result.bytes, data, [
|
|
131
|
-
'eyewear',
|
|
132
|
-
]);
|
|
133
|
-
result.bytes = await fitAuthoredEyeSpacing(result.bytes, data);
|
|
134
|
-
result.bytes = await fitAuthoredHeadwear(result.bytes, data);
|
|
135
|
-
}
|
|
136
77
|
self.postMessage(
|
|
137
78
|
{ id: data.id, ...result },
|
|
138
79
|
result.bytes ? [result.bytes.buffer] : [],
|
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
import { renderBudget } from './render-budget.mjs';
|
|
2
|
-
import { characterPixels } from './resolution.mjs';
|
|
3
2
|
|
|
4
3
|
const snapshots = new Map();
|
|
5
4
|
const waiting = new Map();
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
const pixelsFor = (canvas) =>
|
|
6
|
+
Math.max(
|
|
7
|
+
64,
|
|
8
|
+
Math.min(
|
|
9
|
+
512,
|
|
10
|
+
Math.round(
|
|
11
|
+
Math.min(canvas.clientWidth, canvas.clientHeight) *
|
|
12
|
+
Math.min(devicePixelRatio || 1, 2),
|
|
13
|
+
),
|
|
14
|
+
),
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
// Presentation lifetime is independent of the GPU lease. Overflow avatars keep
|
|
18
|
+
// their real engine pixels and can reclaim a lease through pointer/command input.
|
|
8
19
|
export function createManagedAvatar(canvas, initial, callbacks, factory) {
|
|
9
20
|
let props = initial,
|
|
10
21
|
controller,
|
|
@@ -31,7 +42,7 @@ export function createManagedAvatar(canvas, initial, callbacks, factory) {
|
|
|
31
42
|
props.config.character,
|
|
32
43
|
props.legacy,
|
|
33
44
|
props.config.lookAt,
|
|
34
|
-
|
|
45
|
+
pixelsFor(canvas),
|
|
35
46
|
]);
|
|
36
47
|
const priority = () =>
|
|
37
48
|
pendingWork || pendingReaction || performance.now() < urgentUntil
|
|
@@ -46,6 +57,7 @@ export function createManagedAvatar(canvas, initial, callbacks, factory) {
|
|
|
46
57
|
visible: (visible || props.portrait) && !document.hidden,
|
|
47
58
|
still: still(),
|
|
48
59
|
priority: still() ? 0 : priority(),
|
|
60
|
+
interactive: !!props.interactive,
|
|
49
61
|
needsPaint: !ready,
|
|
50
62
|
});
|
|
51
63
|
function promote(duration = 5000) {
|
|
@@ -56,8 +68,7 @@ export function createManagedAvatar(canvas, initial, callbacks, factory) {
|
|
|
56
68
|
refresh();
|
|
57
69
|
}
|
|
58
70
|
function commands() {
|
|
59
|
-
|
|
60
|
-
if (disposed || still() || !ready || !state?.ready || state.pending) return;
|
|
71
|
+
if (!controller?.diagnostics?.()?.ready) return;
|
|
61
72
|
if (pendingWork)
|
|
62
73
|
promote(
|
|
63
74
|
2500 * Math.max(1, Math.min(10, props.workingCycles || 1)) + 1000,
|
|
@@ -108,13 +119,9 @@ export function createManagedAvatar(canvas, initial, callbacks, factory) {
|
|
|
108
119
|
for (const receive of waiting.get(cacheKey) ?? []) receive();
|
|
109
120
|
}
|
|
110
121
|
callbacks.onPaint?.();
|
|
111
|
-
// Scope replacements and in-place edits may settle without another
|
|
112
|
-
// onReady event. Deliver retained commands only after their paint.
|
|
113
|
-
if (pendingWork || pendingReaction) queueMicrotask(commands);
|
|
114
122
|
},
|
|
115
123
|
});
|
|
116
124
|
controller = created;
|
|
117
|
-
if (!disposed) callbacks.onPreparationStart?.();
|
|
118
125
|
created.update(props, true);
|
|
119
126
|
return created;
|
|
120
127
|
} finally {
|
|
@@ -172,8 +179,7 @@ export function createManagedAvatar(canvas, initial, callbacks, factory) {
|
|
|
172
179
|
pendingReaction = false;
|
|
173
180
|
}
|
|
174
181
|
appearance();
|
|
175
|
-
const
|
|
176
|
-
const queueCommands = !ready || !state?.ready || !!state.pending;
|
|
182
|
+
const queueCommands = !controller?.diagnostics?.()?.ready;
|
|
177
183
|
if (!still() && (work || reaction)) {
|
|
178
184
|
if (queueCommands) {
|
|
179
185
|
pendingWork ||= work;
|