privateboard 0.1.38 → 0.1.41

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 (78) hide show
  1. package/dist/boot.js +327 -50
  2. package/dist/boot.js.map +1 -1
  3. package/dist/cli.js +327 -50
  4. package/dist/cli.js.map +1 -1
  5. package/dist/server.js +201 -40
  6. package/dist/server.js.map +1 -1
  7. package/dist/version.d.ts +1 -1
  8. package/dist/version.js +1 -1
  9. package/dist/version.js.map +1 -1
  10. package/package.json +1 -1
  11. package/public/__avatar3d_test.html +156 -0
  12. package/public/agent-overlay.css +14 -6
  13. package/public/agent-overlay.js +6 -6
  14. package/public/agent-profile.css +9 -12
  15. package/public/agent-profile.js +91 -38
  16. package/public/app.js +471 -528
  17. package/public/avatar-3d-snap.js +205 -0
  18. package/public/avatar-3d.js +836 -0
  19. package/public/avatar-customizer.html +274 -0
  20. package/public/avatar3d-editor.css +240 -0
  21. package/public/avatar3d-editor.js +484 -0
  22. package/public/avatars/3d/chair.png +0 -0
  23. package/public/avatars/3d/first-principles.png +0 -0
  24. package/public/avatars/3d/historian.png +0 -0
  25. package/public/avatars/3d/long-horizon.png +0 -0
  26. package/public/avatars/3d/phenomenologist.png +0 -0
  27. package/public/avatars/3d/socrates.png +0 -0
  28. package/public/avatars/3d/user-empathy.png +0 -0
  29. package/public/avatars/3d/value-investor.png +0 -0
  30. package/public/core-avatars.js +86 -0
  31. package/public/home-3d-loader.js +15 -4
  32. package/public/home-3d-mock.js +25 -14
  33. package/public/home.html +78 -16
  34. package/public/i18n.js +8 -4
  35. package/public/icons/avatar_1779855104027.glb +0 -0
  36. package/public/icons/logo.png +0 -0
  37. package/public/icons/new-style.glb +0 -0
  38. package/public/icons/new-style2.glb +0 -0
  39. package/public/icons/new-style3.glb +0 -0
  40. package/public/icons/new-style4.glb +0 -0
  41. package/public/icons/new-style5.glb +0 -0
  42. package/public/icons/new-style6.glb +0 -0
  43. package/public/icons/office.glb +0 -0
  44. package/public/icons/stuff.glb +0 -0
  45. package/public/index.html +169 -141
  46. package/public/magazine.html +1 -1
  47. package/public/new-agent.js +46 -20
  48. package/public/newspaper.html +1 -1
  49. package/public/office-viewer.html +340 -0
  50. package/public/ppt.html +1 -1
  51. package/public/stuff-viewer.html +330 -0
  52. package/public/thread.css +16 -15
  53. package/public/user-settings.css +7 -31
  54. package/public/user-settings.js +75 -89
  55. package/public/vendor/BufferGeometryUtils.js +1434 -0
  56. package/public/vendor/DRACOLoader.js +739 -0
  57. package/public/vendor/GLTFLoader.js +4860 -0
  58. package/public/vendor/RoomEnvironment.js +185 -0
  59. package/public/vendor/SkeletonUtils.js +496 -0
  60. package/public/vendor/draco/draco_decoder.js +34 -0
  61. package/public/vendor/draco/draco_decoder.wasm +0 -0
  62. package/public/vendor/draco/draco_encoder.js +33 -0
  63. package/public/vendor/draco/draco_wasm_wrapper.js +117 -0
  64. package/public/vendor/meshopt_decoder.module.js +196 -0
  65. package/public/voice-3d-banner.js +19 -7
  66. package/public/voice-3d.js +1407 -432
  67. package/public/voice-replay.js +21 -0
  68. package/public/avatar-skill.js +0 -629
  69. package/public/avatars/chair-blink.svg +0 -1
  70. package/public/avatars/chair.svg +0 -1
  71. package/public/avatars/first-principles.svg +0 -1
  72. package/public/avatars/historian.svg +0 -1
  73. package/public/avatars/long-horizon.svg +0 -1
  74. package/public/avatars/phenomenologist.svg +0 -1
  75. package/public/avatars/socrates.svg +0 -1
  76. package/public/avatars/user-empathy.svg +0 -1
  77. package/public/avatars/value-investor.svg +0 -1
  78. package/public/icons/folded-sidebar.png +0 -0
@@ -0,0 +1,205 @@
1
+ /* ═══════════════════════════════════════════════════════════════════
2
+ avatar-3d-snap.js · shared 3D head-and-shoulders snapshot helper.
3
+
4
+ ── Why it exists ──────────────────────────────────────────────────
5
+ Replaces the retired AvatarSkill (8-bit SVG generator). Every
6
+ surface that used to call AvatarSkill.generateDataUrl / .generate /
7
+ .randomSeed now lives on this module. The portrait is the SAME
8
+ 3D voxel render the agent-profile capture / voice room / home
9
+ page / new-agent celebrity card all use — single source of
10
+ truth, no more 2D/3D split.
11
+
12
+ ── API surface ─────────────────────────────────────────────────────
13
+ window.Avatar3DSnap = {
14
+ randomSeed() → string · 8-char hex
15
+ generate(seed, opts?) → Promise<string> · dataURL PNG
16
+ hydrateImg(imgOrSpan, seed, opts?) → Promise<void> · async paint
17
+ cacheGet(seed) → string | null · sync hot read
18
+ }
19
+
20
+ `seed` is any string · same input always yields the same face
21
+ (deterministic via avatar-3d.js → deriveDefaultAvatarConfig).
22
+
23
+ Caches per-seed dataURLs in-memory · safe to call thousands of
24
+ times from re-render loops. Lazy-loads three.js + avatar-3d.js
25
+ on first generate() call; subsequent calls reuse the module.
26
+ Falls back to no-op (resolves with empty string) on no-WebGL —
27
+ callers should keep their initial-letter / placeholder fallback
28
+ in the DOM for those visitors.
29
+ ═══════════════════════════════════════════════════════════════════ */
30
+ (function (root) {
31
+ if (root.Avatar3DSnap) return;
32
+
33
+ const cache = new Map(); // Map<seed, dataUrl>
34
+ const inflight = new Map(); // Map<seed, Promise<dataUrl>>
35
+ let mods = null; // { THREE, av } once loaded
36
+ let modsPromise = null;
37
+
38
+ function hasWebGL() {
39
+ try {
40
+ const c = document.createElement("canvas");
41
+ return !!(c.getContext("webgl2") || c.getContext("webgl"));
42
+ } catch (_) { return false; }
43
+ }
44
+
45
+ function randomSeed() {
46
+ const r = (n) => Math.floor(Math.random() * n).toString(16);
47
+ return r(0xffff).padStart(4, "0") + r(0xffff).padStart(4, "0");
48
+ }
49
+
50
+ function cacheGet(seed) {
51
+ return cache.has(seed) ? cache.get(seed) : null;
52
+ }
53
+
54
+ async function loadDeps() {
55
+ if (mods) return mods;
56
+ if (modsPromise) return modsPromise;
57
+ modsPromise = (async () => {
58
+ try {
59
+ const [THREE, av] = await Promise.all([
60
+ import("/vendor/three.module.min.js"),
61
+ import("/avatar-3d.js"),
62
+ ]);
63
+ mods = { THREE, av };
64
+ return mods;
65
+ } catch (e) {
66
+ try { console.warn("[avatar-3d-snap] dep load failed", e); } catch (_) {}
67
+ modsPromise = null;
68
+ return null;
69
+ }
70
+ })();
71
+ return modsPromise;
72
+ }
73
+
74
+ /** Render a head-and-shoulders portrait for `seed` and cache the
75
+ * resulting dataURL. Concurrent calls for the same seed share the
76
+ * in-flight promise so the renderer never builds two figures with
77
+ * identical inputs. Returns "" when WebGL is unavailable. */
78
+ async function generate(seed, opts) {
79
+ if (!seed) return "";
80
+ if (cache.has(seed)) return cache.get(seed);
81
+ if (inflight.has(seed)) return inflight.get(seed);
82
+ if (!hasWebGL()) return "";
83
+ const p = (async () => {
84
+ const m = await loadDeps();
85
+ if (!m) return "";
86
+ const { THREE, av } = m;
87
+ // Preload required GLB models · cross-model swaps need source
88
+ // GLBs cached before buildAvatar3D walks skeletons.
89
+ const cfg = av.deriveDefaultAvatarConfig(seed);
90
+ const modelIds = new Set([cfg.model]);
91
+ if (cfg.hairStyle && cfg.hairStyle !== "none") modelIds.add(cfg.hairStyle);
92
+ if (cfg.outfitStyle) modelIds.add(cfg.outfitStyle);
93
+ try {
94
+ await Promise.all(Array.from(modelIds).map((id) => av.loadAvatar3D(id).catch(() => null)));
95
+ } catch (_) { /* */ }
96
+
97
+ // Per-call renderer · the work is small (one frame) and tearing
98
+ // down each time avoids leaking GPU buffers across many seeds.
99
+ const SIZE = (opts && opts.size) || 128;
100
+ const offCanvas = document.createElement("canvas");
101
+ offCanvas.width = SIZE * 2;
102
+ offCanvas.height = SIZE * 2;
103
+ let renderer;
104
+ try {
105
+ renderer = new THREE.WebGLRenderer({ canvas: offCanvas, antialias: true, alpha: true, preserveDrawingBuffer: true });
106
+ } catch (e) {
107
+ try { console.warn("[avatar-3d-snap] renderer init failed", e); } catch (_) {}
108
+ return "";
109
+ }
110
+ renderer.setSize(SIZE * 2, SIZE * 2, false);
111
+ renderer.setClearColor(0x000000, 0);
112
+ renderer.toneMapping = THREE.ACESFilmicToneMapping;
113
+ renderer.toneMappingExposure = 1.0;
114
+ renderer.outputColorSpace = THREE.SRGBColorSpace;
115
+
116
+ const scene = new THREE.Scene();
117
+ scene.add(new THREE.HemisphereLight(0xffffff, 0x2a3140, 0.5));
118
+ const key = new THREE.DirectionalLight(0xffffff, 1.2);
119
+ key.position.set(2, 3, 2.5);
120
+ scene.add(key);
121
+ const rim = new THREE.DirectionalLight(0xbfd4ff, 0.4);
122
+ rim.position.set(-2, 2, -2);
123
+ scene.add(rim);
124
+
125
+ // Camera FOV matches avatar3d-editor's capturePng so face-
126
+ // framing produces the same crop the agent-profile portrait
127
+ // ships with.
128
+ const camera = new THREE.PerspectiveCamera(35, 1, 0.05, 20);
129
+
130
+ let figure = null;
131
+ try {
132
+ figure = av.buildAvatar3D(seed, {
133
+ model: cfg.model,
134
+ hairStyle: cfg.hairStyle,
135
+ outfitStyle: cfg.outfitStyle,
136
+ accessory: cfg.accessory,
137
+ height: 1.7,
138
+ skin: cfg.skin, hair: cfg.hair, brow: cfg.brow, outfit: cfg.outfit,
139
+ browStyle: cfg.browStyle, tieStyle: cfg.tieStyle,
140
+ tie: cfg.tie, eye: cfg.eye,
141
+ });
142
+ } catch (e) {
143
+ try { console.warn("[avatar-3d-snap] buildAvatar3D failed for seed", seed, e); } catch (_) {}
144
+ figure = null;
145
+ }
146
+ if (!figure) {
147
+ try { renderer.dispose(); } catch (_) {}
148
+ return "";
149
+ }
150
+ figure.rotation.y = -0.18;
151
+ scene.add(figure);
152
+ try {
153
+ if (typeof av.applyFaceFraming === "function") av.applyFaceFraming(camera, figure);
154
+ } catch (_) { /* */ }
155
+ renderer.render(scene, camera);
156
+ const dataUrl = renderer.domElement.toDataURL("image/png");
157
+ figure.traverse((n) => {
158
+ if (n.material) {
159
+ const ms = Array.isArray(n.material) ? n.material : [n.material];
160
+ for (const mat of ms) { try { mat.dispose(); } catch (_) {} }
161
+ }
162
+ if (n.geometry) { try { n.geometry.dispose(); } catch (_) {} }
163
+ });
164
+ try { renderer.dispose(); } catch (_) {}
165
+ cache.set(seed, dataUrl);
166
+ return dataUrl;
167
+ })().finally(() => { inflight.delete(seed); });
168
+ inflight.set(seed, p);
169
+ return p;
170
+ }
171
+
172
+ /** Async paint a portrait into an existing `<img>` or fallback
173
+ * `<span>` node. The first attempt uses the cache (synchronous);
174
+ * if no cache, an async render kicks off and updates the node
175
+ * when it lands. Use when the call site can't await — it pulls
176
+ * the placeholder out of the DOM and replaces it with an `<img>`
177
+ * carrying the rendered portrait. */
178
+ async function hydrateImg(target, seed, opts) {
179
+ if (!target || !seed) return;
180
+ const cached = cacheGet(seed);
181
+ if (cached) {
182
+ paint(target, cached);
183
+ return;
184
+ }
185
+ const dataUrl = await generate(seed, opts);
186
+ if (dataUrl) paint(target, dataUrl);
187
+ }
188
+
189
+ function paint(target, dataUrl) {
190
+ if (!target) return;
191
+ if (target.tagName === "IMG") {
192
+ target.src = dataUrl;
193
+ return;
194
+ }
195
+ const img = document.createElement("img");
196
+ img.src = dataUrl;
197
+ img.alt = "";
198
+ // Preserve any classes the placeholder carried so existing CSS
199
+ // sizing rules continue to apply.
200
+ if (target.className) img.className = target.className;
201
+ if (target.parentNode) target.parentNode.replaceChild(img, target);
202
+ }
203
+
204
+ root.Avatar3DSnap = { randomSeed, generate, hydrateImg, cacheGet };
205
+ })(typeof window !== "undefined" ? window : globalThis);