@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.
Files changed (220) hide show
  1. package/assets/character-runtime/README.md +19 -114
  2. package/assets/character-runtime/legacy-engine.mjs +54 -406
  3. package/assets/character-runtime/legacy-geometry.mjs +85 -242
  4. package/assets/character-runtime/legacy-worker.mjs +23 -82
  5. package/assets/character-runtime/managed-avatar.mjs +18 -12
  6. package/assets/character-runtime/render-budget.mjs +11 -6
  7. package/assets/character-runtime/runtime.mjs +295 -744
  8. package/docs/agent-avatar.mdx +8 -45
  9. package/docs/agent-creator.mdx +3 -13
  10. package/lib/commonjs/agent-avatar/AgentAvatar.js +1 -1
  11. package/lib/commonjs/agent-avatar/AgentAvatar.js.map +1 -1
  12. package/lib/commonjs/agent-avatar/CharacterAvatar.js +1 -2
  13. package/lib/commonjs/agent-avatar/CharacterAvatar.js.map +1 -1
  14. package/lib/commonjs/agent-avatar/config-character.js +0 -4
  15. package/lib/commonjs/agent-avatar/config-character.js.map +1 -1
  16. package/lib/commonjs/agent-avatar/legacy-recipe.js +6 -19
  17. package/lib/commonjs/agent-avatar/legacy-recipe.js.map +1 -1
  18. package/lib/commonjs/agent-creator/AgentCreatorBase.js +107 -67
  19. package/lib/commonjs/agent-creator/AgentCreatorBase.js.map +1 -1
  20. package/lib/commonjs/agent-creator/CharacterControls.js +5 -23
  21. package/lib/commonjs/agent-creator/CharacterControls.js.map +1 -1
  22. package/lib/commonjs/agent-creator/EmotionPicker.js +1 -8
  23. package/lib/commonjs/agent-creator/EmotionPicker.js.map +1 -1
  24. package/lib/commonjs/agent-creator/ShapeSilhouette.js +1 -8
  25. package/lib/commonjs/agent-creator/ShapeSilhouette.js.map +1 -1
  26. package/lib/commonjs/agent-creator/constants.js +17 -16
  27. package/lib/commonjs/agent-creator/constants.js.map +1 -1
  28. package/lib/commonjs/agent-creator/messages.js +1 -1
  29. package/lib/commonjs/agent-creator/messages.js.map +1 -1
  30. package/lib/commonjs/locale/translations/ar.js +1 -1
  31. package/lib/commonjs/locale/translations/ar.js.map +1 -1
  32. package/lib/commonjs/locale/translations/bn.js +1 -1
  33. package/lib/commonjs/locale/translations/bn.js.map +1 -1
  34. package/lib/commonjs/locale/translations/ca.js +1 -1
  35. package/lib/commonjs/locale/translations/ca.js.map +1 -1
  36. package/lib/commonjs/locale/translations/de.js +1 -1
  37. package/lib/commonjs/locale/translations/de.js.map +1 -1
  38. package/lib/commonjs/locale/translations/es.js +1 -1
  39. package/lib/commonjs/locale/translations/es.js.map +1 -1
  40. package/lib/commonjs/locale/translations/fr.js +1 -1
  41. package/lib/commonjs/locale/translations/fr.js.map +1 -1
  42. package/lib/commonjs/locale/translations/hi.js +1 -1
  43. package/lib/commonjs/locale/translations/hi.js.map +1 -1
  44. package/lib/commonjs/locale/translations/id.js +1 -1
  45. package/lib/commonjs/locale/translations/id.js.map +1 -1
  46. package/lib/commonjs/locale/translations/it.js +1 -1
  47. package/lib/commonjs/locale/translations/it.js.map +1 -1
  48. package/lib/commonjs/locale/translations/ja.js +1 -1
  49. package/lib/commonjs/locale/translations/ja.js.map +1 -1
  50. package/lib/commonjs/locale/translations/pt.js +1 -1
  51. package/lib/commonjs/locale/translations/pt.js.map +1 -1
  52. package/lib/commonjs/locale/translations/ru.js +1 -1
  53. package/lib/commonjs/locale/translations/ru.js.map +1 -1
  54. package/lib/commonjs/locale/translations/tr.js +1 -1
  55. package/lib/commonjs/locale/translations/tr.js.map +1 -1
  56. package/lib/commonjs/locale/translations/zh.js +1 -1
  57. package/lib/commonjs/locale/translations/zh.js.map +1 -1
  58. package/lib/module/agent-avatar/AgentAvatar.js +1 -1
  59. package/lib/module/agent-avatar/AgentAvatar.js.map +1 -1
  60. package/lib/module/agent-avatar/CharacterAvatar.js +1 -2
  61. package/lib/module/agent-avatar/CharacterAvatar.js.map +1 -1
  62. package/lib/module/agent-avatar/config-character.js +0 -4
  63. package/lib/module/agent-avatar/config-character.js.map +1 -1
  64. package/lib/module/agent-avatar/legacy-recipe.js +6 -19
  65. package/lib/module/agent-avatar/legacy-recipe.js.map +1 -1
  66. package/lib/module/agent-creator/AgentCreatorBase.js +109 -69
  67. package/lib/module/agent-creator/AgentCreatorBase.js.map +1 -1
  68. package/lib/module/agent-creator/CharacterControls.js +6 -24
  69. package/lib/module/agent-creator/CharacterControls.js.map +1 -1
  70. package/lib/module/agent-creator/EmotionPicker.js +1 -8
  71. package/lib/module/agent-creator/EmotionPicker.js.map +1 -1
  72. package/lib/module/agent-creator/ShapeSilhouette.js +1 -8
  73. package/lib/module/agent-creator/ShapeSilhouette.js.map +1 -1
  74. package/lib/module/agent-creator/constants.js +16 -8
  75. package/lib/module/agent-creator/constants.js.map +1 -1
  76. package/lib/module/agent-creator/messages.js +1 -1
  77. package/lib/module/agent-creator/messages.js.map +1 -1
  78. package/lib/module/locale/translations/ar.js +1 -1
  79. package/lib/module/locale/translations/ar.js.map +1 -1
  80. package/lib/module/locale/translations/bn.js +1 -1
  81. package/lib/module/locale/translations/bn.js.map +1 -1
  82. package/lib/module/locale/translations/ca.js +1 -1
  83. package/lib/module/locale/translations/ca.js.map +1 -1
  84. package/lib/module/locale/translations/de.js +1 -1
  85. package/lib/module/locale/translations/de.js.map +1 -1
  86. package/lib/module/locale/translations/es.js +1 -1
  87. package/lib/module/locale/translations/es.js.map +1 -1
  88. package/lib/module/locale/translations/fr.js +1 -1
  89. package/lib/module/locale/translations/fr.js.map +1 -1
  90. package/lib/module/locale/translations/hi.js +1 -1
  91. package/lib/module/locale/translations/hi.js.map +1 -1
  92. package/lib/module/locale/translations/id.js +1 -1
  93. package/lib/module/locale/translations/id.js.map +1 -1
  94. package/lib/module/locale/translations/it.js +1 -1
  95. package/lib/module/locale/translations/it.js.map +1 -1
  96. package/lib/module/locale/translations/ja.js +1 -1
  97. package/lib/module/locale/translations/ja.js.map +1 -1
  98. package/lib/module/locale/translations/pt.js +1 -1
  99. package/lib/module/locale/translations/pt.js.map +1 -1
  100. package/lib/module/locale/translations/ru.js +1 -1
  101. package/lib/module/locale/translations/ru.js.map +1 -1
  102. package/lib/module/locale/translations/tr.js +1 -1
  103. package/lib/module/locale/translations/tr.js.map +1 -1
  104. package/lib/module/locale/translations/zh.js +1 -1
  105. package/lib/module/locale/translations/zh.js.map +1 -1
  106. package/lib/typescript/commonjs/agent-avatar/CharacterAvatar.d.ts.map +1 -1
  107. package/lib/typescript/commonjs/agent-avatar/config-character.d.ts +0 -4
  108. package/lib/typescript/commonjs/agent-avatar/config-character.d.ts.map +1 -1
  109. package/lib/typescript/commonjs/agent-avatar/legacy-recipe.d.ts +10 -2
  110. package/lib/typescript/commonjs/agent-avatar/legacy-recipe.d.ts.map +1 -1
  111. package/lib/typescript/commonjs/agent-creator/AgentCreatorBase.d.ts.map +1 -1
  112. package/lib/typescript/commonjs/agent-creator/CharacterControls.d.ts +1 -2
  113. package/lib/typescript/commonjs/agent-creator/CharacterControls.d.ts.map +1 -1
  114. package/lib/typescript/commonjs/agent-creator/EmotionPicker.d.ts +0 -1
  115. package/lib/typescript/commonjs/agent-creator/EmotionPicker.d.ts.map +1 -1
  116. package/lib/typescript/commonjs/agent-creator/ShapeSilhouette.d.ts.map +1 -1
  117. package/lib/typescript/commonjs/agent-creator/constants.d.ts +15 -7
  118. package/lib/typescript/commonjs/agent-creator/constants.d.ts.map +1 -1
  119. package/lib/typescript/commonjs/agent-creator/messages.d.ts.map +1 -1
  120. package/lib/typescript/module/agent-avatar/CharacterAvatar.d.ts.map +1 -1
  121. package/lib/typescript/module/agent-avatar/config-character.d.ts +0 -4
  122. package/lib/typescript/module/agent-avatar/config-character.d.ts.map +1 -1
  123. package/lib/typescript/module/agent-avatar/legacy-recipe.d.ts +10 -2
  124. package/lib/typescript/module/agent-avatar/legacy-recipe.d.ts.map +1 -1
  125. package/lib/typescript/module/agent-creator/AgentCreatorBase.d.ts.map +1 -1
  126. package/lib/typescript/module/agent-creator/CharacterControls.d.ts +1 -2
  127. package/lib/typescript/module/agent-creator/CharacterControls.d.ts.map +1 -1
  128. package/lib/typescript/module/agent-creator/EmotionPicker.d.ts +0 -1
  129. package/lib/typescript/module/agent-creator/EmotionPicker.d.ts.map +1 -1
  130. package/lib/typescript/module/agent-creator/ShapeSilhouette.d.ts.map +1 -1
  131. package/lib/typescript/module/agent-creator/constants.d.ts +15 -7
  132. package/lib/typescript/module/agent-creator/constants.d.ts.map +1 -1
  133. package/lib/typescript/module/agent-creator/messages.d.ts.map +1 -1
  134. package/package.json +1 -1
  135. package/src/agent-avatar/AgentAvatar.tsx +1 -1
  136. package/src/agent-avatar/CharacterAvatar.tsx +1 -4
  137. package/src/agent-avatar/config-character.ts +6 -39
  138. package/src/agent-avatar/legacy-recipe.ts +6 -34
  139. package/src/agent-creator/AgentCreatorBase.tsx +152 -121
  140. package/src/agent-creator/CharacterControls.tsx +14 -39
  141. package/src/agent-creator/EmotionPicker.tsx +16 -55
  142. package/src/agent-creator/ShapeSilhouette.tsx +1 -16
  143. package/src/agent-creator/constants.ts +14 -47
  144. package/src/agent-creator/messages.ts +1 -2
  145. package/src/locale/translations/ar.ts +1 -1
  146. package/src/locale/translations/bn.ts +1 -1
  147. package/src/locale/translations/ca.ts +1 -1
  148. package/src/locale/translations/de.ts +1 -1
  149. package/src/locale/translations/es.ts +1 -1
  150. package/src/locale/translations/fr.ts +1 -1
  151. package/src/locale/translations/hi.ts +1 -1
  152. package/src/locale/translations/id.ts +1 -1
  153. package/src/locale/translations/it.ts +1 -1
  154. package/src/locale/translations/ja.ts +1 -1
  155. package/src/locale/translations/pt.ts +1 -1
  156. package/src/locale/translations/ru.ts +1 -1
  157. package/src/locale/translations/tr.ts +1 -1
  158. package/src/locale/translations/zh.ts +1 -1
  159. package/assets/character-runtime/authored-parts.mjs +0 -754
  160. package/assets/character-runtime/catalog-parts.mjs +0 -362
  161. package/assets/character-runtime/character-recipe.mjs +0 -247
  162. package/assets/character-runtime/clippo-geometry.mjs +0 -679
  163. package/assets/character-runtime/controller-mode.mjs +0 -208
  164. package/assets/character-runtime/cyclops-geometry.mjs +0 -180
  165. package/assets/character-runtime/migrated-contours.mjs +0 -2067
  166. package/assets/character-runtime/migrated-faces.mjs +0 -59
  167. package/assets/character-runtime/pose-transition.mjs +0 -523
  168. package/assets/character-runtime/preparation-cache.mjs +0 -60
  169. package/assets/character-runtime/render-errors.mjs +0 -180
  170. package/assets/character-runtime/resolution.mjs +0 -10
  171. package/assets/character-runtime/sha256.mjs +0 -44
  172. package/assets/character-runtime/shared-programs.mjs +0 -534
  173. package/assets/character-runtime/shared-surface.mjs +0 -490
  174. package/assets/character-runtime/shared-textures.mjs +0 -420
  175. package/assets/character-runtime/thumbnails/eyes/todd.png +0 -0
  176. package/lib/commonjs/agent-avatar/character-colors.js +0 -19
  177. package/lib/commonjs/agent-avatar/character-colors.js.map +0 -1
  178. package/lib/commonjs/agent-avatar/character-shapes.js +0 -106
  179. package/lib/commonjs/agent-avatar/character-shapes.js.map +0 -1
  180. package/lib/commonjs/agent-creator/ClippoArtwork.js +0 -63
  181. package/lib/commonjs/agent-creator/ClippoArtwork.js.map +0 -1
  182. package/lib/commonjs/agent-creator/CyclopsArtwork.js +0 -45
  183. package/lib/commonjs/agent-creator/CyclopsArtwork.js.map +0 -1
  184. package/lib/commonjs/agent-creator/ToddArtwork.js +0 -29
  185. package/lib/commonjs/agent-creator/ToddArtwork.js.map +0 -1
  186. package/lib/module/agent-avatar/character-colors.js +0 -15
  187. package/lib/module/agent-avatar/character-colors.js.map +0 -1
  188. package/lib/module/agent-avatar/character-shapes.js +0 -97
  189. package/lib/module/agent-avatar/character-shapes.js.map +0 -1
  190. package/lib/module/agent-creator/ClippoArtwork.js +0 -59
  191. package/lib/module/agent-creator/ClippoArtwork.js.map +0 -1
  192. package/lib/module/agent-creator/CyclopsArtwork.js +0 -41
  193. package/lib/module/agent-creator/CyclopsArtwork.js.map +0 -1
  194. package/lib/module/agent-creator/ToddArtwork.js +0 -25
  195. package/lib/module/agent-creator/ToddArtwork.js.map +0 -1
  196. package/lib/typescript/commonjs/agent-avatar/character-colors.d.ts +0 -13
  197. package/lib/typescript/commonjs/agent-avatar/character-colors.d.ts.map +0 -1
  198. package/lib/typescript/commonjs/agent-avatar/character-shapes.d.ts +0 -19
  199. package/lib/typescript/commonjs/agent-avatar/character-shapes.d.ts.map +0 -1
  200. package/lib/typescript/commonjs/agent-creator/ClippoArtwork.d.ts +0 -6
  201. package/lib/typescript/commonjs/agent-creator/ClippoArtwork.d.ts.map +0 -1
  202. package/lib/typescript/commonjs/agent-creator/CyclopsArtwork.d.ts +0 -5
  203. package/lib/typescript/commonjs/agent-creator/CyclopsArtwork.d.ts.map +0 -1
  204. package/lib/typescript/commonjs/agent-creator/ToddArtwork.d.ts +0 -6
  205. package/lib/typescript/commonjs/agent-creator/ToddArtwork.d.ts.map +0 -1
  206. package/lib/typescript/module/agent-avatar/character-colors.d.ts +0 -13
  207. package/lib/typescript/module/agent-avatar/character-colors.d.ts.map +0 -1
  208. package/lib/typescript/module/agent-avatar/character-shapes.d.ts +0 -19
  209. package/lib/typescript/module/agent-avatar/character-shapes.d.ts.map +0 -1
  210. package/lib/typescript/module/agent-creator/ClippoArtwork.d.ts +0 -6
  211. package/lib/typescript/module/agent-creator/ClippoArtwork.d.ts.map +0 -1
  212. package/lib/typescript/module/agent-creator/CyclopsArtwork.d.ts +0 -5
  213. package/lib/typescript/module/agent-creator/CyclopsArtwork.d.ts.map +0 -1
  214. package/lib/typescript/module/agent-creator/ToddArtwork.d.ts +0 -6
  215. package/lib/typescript/module/agent-creator/ToddArtwork.d.ts.map +0 -1
  216. package/src/agent-avatar/character-colors.ts +0 -12
  217. package/src/agent-avatar/character-shapes.ts +0 -122
  218. package/src/agent-creator/ClippoArtwork.tsx +0 -49
  219. package/src/agent-creator/CyclopsArtwork.tsx +0 -27
  220. package/src/agent-creator/ToddArtwork.tsx +0 -24
@@ -1,490 +0,0 @@
1
- // Original Character renderers keep independent state and render targets, but
2
- // their browser contexts are views onto ONE physical WebGL canvas. Only the
3
- // default framebuffer is mapped into atlas regions; private FBOs stay local.
4
- import { createSharedProgramPool } from './shared-programs.mjs';
5
- import { createRenderErrorBoundary } from './render-errors.mjs';
6
- import { createSharedTexturePool } from './shared-textures.mjs';
7
- import { createPoseTransition } from './pose-transition.mjs';
8
-
9
- const atlasKey = Symbol.for('bloom.character.shared-surface.v1');
10
- let serial = 0;
11
- function createAtlas() {
12
- const canvas = document.createElement('canvas');
13
- canvas.setAttribute('aria-hidden', 'true');
14
- canvas.style.display = 'none';
15
- document.body.append(canvas);
16
- const physical = canvas.getContext('webgl2', {
17
- alpha: true,
18
- antialias: false,
19
- premultipliedAlpha: true,
20
- preserveDrawingBuffer: false,
21
- });
22
- if (!physical) {
23
- canvas.remove();
24
- throw new Error('Shared character WebGL2 context unavailable');
25
- }
26
- const renderErrors = createRenderErrorBoundary(physical);
27
- const programs = createSharedProgramPool(renderErrors.context);
28
- const textures = createSharedTexturePool(programs.context);
29
- const resources = Object.fromEntries(
30
- ['Buffer', 'Texture', 'Framebuffer', 'Renderbuffer', 'VertexArray'].map(
31
- (name) => [name, new Set()],
32
- ),
33
- );
34
- const resourceMethods = new Map();
35
- const gl = new Proxy(textures.context, {
36
- get(target, key) {
37
- if (resourceMethods.has(key)) return resourceMethods.get(key);
38
- const value = Reflect.get(target, key, target);
39
- if (typeof value !== 'function') return value;
40
- if (!resourceMethods.has(key)) {
41
- const operation =
42
- /^(create|delete)(Buffer|Texture|Framebuffer|Renderbuffer|VertexArray)$/.exec(
43
- String(key),
44
- );
45
- resourceMethods.set(
46
- key,
47
- operation
48
- ? (...args) => {
49
- const result = value(...args);
50
- const set = resources[operation[2]];
51
- if (operation[1] === 'create' && result) set.add(result);
52
- else if (operation[1] === 'delete') set.delete(args[0]);
53
- return result;
54
- }
55
- : value,
56
- );
57
- }
58
- return resourceMethods.get(key);
59
- },
60
- });
61
- const entries = new Set();
62
- const resolves = new Map();
63
- function resolveTarget(width, height) {
64
- const key = `${width}:${height}`;
65
- if (resolves.has(key)) return resolves.get(key);
66
- const texture = gl.createTexture(),
67
- framebuffer = gl.createFramebuffer();
68
- const previous = gl.getParameter(gl.TEXTURE_BINDING_2D);
69
- gl.bindTexture(gl.TEXTURE_2D, texture);
70
- gl.texImage2D(
71
- gl.TEXTURE_2D,
72
- 0,
73
- gl.RGBA8,
74
- width,
75
- height,
76
- 0,
77
- gl.RGBA,
78
- gl.UNSIGNED_BYTE,
79
- null,
80
- );
81
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
82
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
83
- gl.bindTexture(gl.TEXTURE_2D, previous);
84
- gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, framebuffer);
85
- gl.framebufferTexture2D(
86
- gl.DRAW_FRAMEBUFFER,
87
- gl.COLOR_ATTACHMENT0,
88
- gl.TEXTURE_2D,
89
- texture,
90
- 0,
91
- );
92
- gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, drawFramebuffer);
93
- if (resolves.size >= 8) {
94
- const [oldKey, old] = resolves.entries().next().value;
95
- gl.deleteFramebuffer(old.framebuffer);
96
- gl.deleteTexture(old.texture);
97
- resolves.delete(oldKey);
98
- }
99
- resolves.set(key, { framebuffer, texture });
100
- return resolves.get(key);
101
- }
102
- const maximum = gl.getParameter(gl.MAX_RENDERBUFFER_SIZE);
103
- let drawFramebuffer = null,
104
- readFramebuffer = null;
105
- let revision = 0;
106
- function layout() {
107
- const ordered = [...entries].sort(
108
- (a, b) => b.canvas.height - a.canvas.height,
109
- );
110
- const area = ordered.reduce(
111
- (sum, e) => sum + e.canvas.width * e.canvas.height,
112
- 0,
113
- );
114
- let width = Math.min(
115
- maximum,
116
- 2 **
117
- Math.ceil(
118
- Math.log2(
119
- Math.max(
120
- 64,
121
- Math.sqrt(area),
122
- ...ordered.map((e) => e.canvas.width),
123
- ),
124
- ),
125
- ),
126
- );
127
- let height;
128
- const placements = new Map();
129
- for (;;) {
130
- let x = 0,
131
- y = 0,
132
- row = 0;
133
- for (const e of ordered) {
134
- if (x + e.canvas.width > width) {
135
- x = 0;
136
- y += row;
137
- row = 0;
138
- }
139
- placements.set(e, [x, y]);
140
- x += e.canvas.width;
141
- row = Math.max(row, e.canvas.height);
142
- }
143
- height = Math.max(1, y + row);
144
- if (height <= maximum) break;
145
- if (width === maximum)
146
- throw new Error('Character atlas exceeds device texture size');
147
- width = Math.min(maximum, width * 2);
148
- }
149
- for (const [entry, [x, y]] of placements) {
150
- entry.x = x;
151
- entry.y = y;
152
- }
153
- if (canvas.width !== width) canvas.width = width;
154
- if (canvas.height !== height) canvas.height = height;
155
- revision++;
156
- }
157
- function acquire(parent) {
158
- renderErrors.assertAvailable();
159
- const node = document.createElement('canvas');
160
- node.id = `bloom-character-surface-${++serial}`;
161
- node.width = node.height = 128;
162
- node.style.display = 'none';
163
- node.setAttribute('aria-hidden', 'true');
164
- parent.append(node);
165
- const entry = { canvas: node, x: 0, y: 0 };
166
- entries.add(entry);
167
- try {
168
- layout();
169
- } catch (error) {
170
- entries.delete(entry);
171
- node.remove();
172
- if (!entries.size) {
173
- textures.dispose();
174
- programs.dispose();
175
- physical.getExtension('WEBGL_lose_context')?.loseContext();
176
- canvas.remove();
177
- delete globalThis[atlasKey];
178
- }
179
- throw error;
180
- }
181
- let released = false,
182
- scissorEnabled = false;
183
- let scissor = [0, 0, 128, 128],
184
- viewport = [0, 0, 128, 128];
185
- for (const dimension of ['width', 'height']) {
186
- const descriptor = Object.getOwnPropertyDescriptor(
187
- HTMLCanvasElement.prototype,
188
- dimension,
189
- );
190
- Object.defineProperty(node, dimension, {
191
- get() {
192
- return descriptor.get.call(node);
193
- },
194
- set(value) {
195
- renderErrors.assertAvailable();
196
- if (value === descriptor.get.call(node)) return;
197
- const previous = descriptor.get.call(node);
198
- descriptor.set.call(node, value);
199
- try {
200
- if (node[dimension] > maximum)
201
- throw new Error('Character surface exceeds device texture size');
202
- layout();
203
- } catch (error) {
204
- descriptor.set.call(node, previous);
205
- throw error;
206
- }
207
- },
208
- });
209
- }
210
- function clip() {
211
- if (drawFramebuffer === null) {
212
- gl.enable(gl.SCISSOR_TEST);
213
- const [sx, sy, sw, sh] = scissorEnabled
214
- ? scissor
215
- : [0, 0, node.width, node.height];
216
- const x = Math.max(0, sx),
217
- y = Math.max(0, sy);
218
- gl.scissor(
219
- entry.x + x,
220
- entry.y + y,
221
- Math.max(0, Math.min(node.width, sx + sw) - x),
222
- Math.max(0, Math.min(node.height, sy + sh) - y),
223
- );
224
- } else {
225
- if (scissorEnabled) gl.enable(gl.SCISSOR_TEST);
226
- else gl.disable(gl.SCISSOR_TEST);
227
- gl.scissor(...scissor);
228
- }
229
- }
230
- function setViewport() {
231
- const [x, y, w, h] = viewport;
232
- gl.viewport(
233
- x + (drawFramebuffer === null ? entry.x : 0),
234
- y + (drawFramebuffer === null ? entry.y : 0),
235
- w,
236
- h,
237
- );
238
- }
239
- const methods = new Map();
240
- function contextProperty(target, key) {
241
- if (key === 'canvas') return node;
242
- if (key === 'drawingBufferWidth') return node.width;
243
- if (key === 'drawingBufferHeight') return node.height;
244
- if (key === 'getExtension')
245
- return (name) =>
246
- name === 'WEBGL_lose_context'
247
- ? { loseContext() {}, restoreContext() {} }
248
- : gl.getExtension(name);
249
- if (key === 'getParameter')
250
- return (name) =>
251
- name === gl.VIEWPORT
252
- ? new Int32Array(viewport)
253
- : name === gl.SCISSOR_BOX
254
- ? new Int32Array(scissor)
255
- : gl.getParameter(name);
256
- if (key === 'isEnabled')
257
- return (name) =>
258
- name === gl.SCISSOR_TEST ? scissorEnabled : gl.isEnabled(name);
259
- if (key === 'bindFramebuffer')
260
- return (target, buffer) => {
261
- gl.bindFramebuffer(target, buffer);
262
- if (target === gl.FRAMEBUFFER || target === gl.DRAW_FRAMEBUFFER)
263
- drawFramebuffer = buffer;
264
- if (target === gl.FRAMEBUFFER || target === gl.READ_FRAMEBUFFER)
265
- readFramebuffer = buffer;
266
- clip();
267
- setViewport();
268
- };
269
- if (key === 'viewport')
270
- return (...value) => {
271
- viewport = value;
272
- setViewport();
273
- };
274
- if (key === 'scissor')
275
- return (...value) => {
276
- scissor = value;
277
- clip();
278
- };
279
- if (key === 'enable' || key === 'disable')
280
- return (value) => {
281
- if (value === gl.SCISSOR_TEST) {
282
- scissorEnabled = key === 'enable';
283
- clip();
284
- } else gl[key](value);
285
- };
286
- if (key === 'blitFramebuffer')
287
- return (...args) => {
288
- if (drawFramebuffer === null && readFramebuffer !== null) {
289
- // WebGL requires identical source/destination bounds for an MSAA
290
- // resolve. Resolve at local coordinates before translating into the
291
- // atlas; this scratch attachment is shared by equal-sized avatars.
292
- const target = resolveTarget(node.width, node.height);
293
- gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, target.framebuffer);
294
- gl.disable(gl.SCISSOR_TEST);
295
- gl.blitFramebuffer(...args);
296
- gl.bindFramebuffer(gl.READ_FRAMEBUFFER, target.framebuffer);
297
- gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
298
- clip();
299
- gl.blitFramebuffer(
300
- 0,
301
- 0,
302
- node.width,
303
- node.height,
304
- entry.x,
305
- entry.y,
306
- entry.x + node.width,
307
- entry.y + node.height,
308
- gl.COLOR_BUFFER_BIT,
309
- gl.NEAREST,
310
- );
311
- gl.bindFramebuffer(gl.READ_FRAMEBUFFER, readFramebuffer);
312
- return;
313
- }
314
- if (readFramebuffer === null) {
315
- args[0] += entry.x;
316
- args[2] += entry.x;
317
- args[1] += entry.y;
318
- args[3] += entry.y;
319
- }
320
- if (drawFramebuffer === null) {
321
- args[4] += entry.x;
322
- args[6] += entry.x;
323
- args[5] += entry.y;
324
- args[7] += entry.y;
325
- }
326
- gl.blitFramebuffer(...args);
327
- };
328
- if (key === 'readPixels')
329
- return (x, y, ...args) =>
330
- gl.readPixels(
331
- x + (readFramebuffer === null ? entry.x : 0),
332
- y + (readFramebuffer === null ? entry.y : 0),
333
- ...args,
334
- );
335
- const value = Reflect.get(target, key, target);
336
- if (typeof value !== 'function') return value;
337
- if (!methods.has(key)) methods.set(key, value.bind(target));
338
- return methods.get(key);
339
- }
340
- const context = new Proxy(gl, {
341
- get(target, key) {
342
- // Methods are stable per logical surface. Resolve them once instead of
343
- // walking every nested GL adapter and allocating closures on each draw.
344
- // Canvas size and other non-method properties must remain live.
345
- if (methods.has(key)) return methods.get(key);
346
- const value = contextProperty(target, key);
347
- if (typeof value === 'function') {
348
- const guarded = (...args) => {
349
- renderErrors.assertAvailable();
350
- return value(...args);
351
- };
352
- methods.set(key, guarded);
353
- return guarded;
354
- }
355
- return value;
356
- },
357
- });
358
- const pose = createPoseTransition(context, {
359
- assertAvailable: renderErrors.assertAvailable,
360
- });
361
- const original = node.getContext.bind(node);
362
- node.getContext = (type, ...args) =>
363
- type === 'webgl2' ? pose.context : original(type, ...args);
364
- return {
365
- canvas: node,
366
- render(operation, poseReady) {
367
- pose.beginFrame();
368
- try {
369
- return renderErrors.render(operation);
370
- } finally {
371
- pose.endFrame(poseReady?.() ?? true);
372
- }
373
- },
374
- beginTransition: pose.beginTransition,
375
- cancelTransition: pose.cancel,
376
- transitionStats: pose.stats,
377
- create(module, ...options) {
378
- return new module.Character('#' + node.id, ...options);
379
- },
380
- copy(
381
- output,
382
- sx = 0,
383
- sy = 0,
384
- sw = node.width,
385
- sh = node.height,
386
- dx = 0,
387
- dy = 0,
388
- dw = node.width,
389
- dh = node.height,
390
- ) {
391
- renderErrors.assertReadable();
392
- // A fit can extend beyond its character's surface. Clip to this tile,
393
- // preserving the destination transform, so neighbours never bleed in.
394
- const x = Math.max(0, sx),
395
- y = Math.max(0, sy);
396
- const w = Math.min(node.width, sx + sw) - x,
397
- h = Math.min(node.height, sy + sh) - y;
398
- if (w <= 0 || h <= 0 || sw <= 0 || sh <= 0) return;
399
- output.drawImage(
400
- canvas,
401
- entry.x + x,
402
- canvas.height - entry.y - node.height + y,
403
- w,
404
- h,
405
- dx + ((x - sx) * dw) / sw,
406
- dy + ((y - sy) * dh) / sh,
407
- (w * dw) / sw,
408
- (h * dh) / sh,
409
- );
410
- pose.presented();
411
- },
412
- get revision() {
413
- return revision;
414
- },
415
- release() {
416
- if (released) return;
417
- renderErrors.assertAvailable();
418
- released = true;
419
- pose.dispose();
420
- entries.delete(entry);
421
- node.remove();
422
- if (!entries.size) {
423
- textures.dispose();
424
- programs.dispose();
425
- gl.getExtension('WEBGL_lose_context')?.loseContext();
426
- canvas.remove();
427
- delete globalThis[atlasKey];
428
- }
429
- // Retain layout until another allocation/resize, so releasing a surface
430
- // cannot erase an already submitted neighbour before presentation.
431
- },
432
- };
433
- }
434
- return {
435
- acquire,
436
- render: renderErrors.render,
437
- renderDeferred: renderErrors.renderDeferred,
438
- wait: renderErrors.wait,
439
- get pending() {
440
- return renderErrors.pending;
441
- },
442
- stats: () => ({
443
- contexts: 1,
444
- surfaces: entries.size,
445
- width: canvas.width,
446
- height: canvas.height,
447
- colorBytes: canvas.width * canvas.height * 4,
448
- revision,
449
- programs: programs.stats(),
450
- textures: textures.stats(),
451
- resources: Object.fromEntries(
452
- Object.entries(resources).map(([name, values]) => [
453
- name,
454
- name === 'Texture' ? textures.stats().physicalTextures : values.size,
455
- ]),
456
- ),
457
- }),
458
- };
459
- }
460
- export function acquireSharedSurface(parent) {
461
- return (globalThis[atlasKey] ??= createAtlas()).acquire(parent);
462
- }
463
- export function renderSharedBatch(operation) {
464
- const atlas = globalThis[atlasKey];
465
- return atlas ? atlas.render(operation) : operation();
466
- }
467
- // Publication runs synchronously while the GPU transaction remains locked.
468
- // Creation, preparation delivery, resize and deletion must await settlement.
469
- export function renderSharedBatchDeferred(operation, publish) {
470
- const atlas = globalThis[atlasKey];
471
- if (atlas) return atlas.renderDeferred(operation, publish);
472
- return Promise.resolve().then(() => {
473
- const result = operation();
474
- publish?.(result);
475
- return result;
476
- });
477
- }
478
- export function waitForSharedRender() {
479
- return globalThis[atlasKey]?.wait() ?? Promise.resolve();
480
- }
481
- export const sharedRenderPending = () => globalThis[atlasKey]?.pending ?? false;
482
- export const sharedSurfaceStats = () =>
483
- globalThis[atlasKey]?.stats() ?? {
484
- contexts: 0,
485
- surfaces: 0,
486
- width: 0,
487
- height: 0,
488
- colorBytes: 0,
489
- revision: 0,
490
- };