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.
- package/dist/boot.js +327 -50
- package/dist/boot.js.map +1 -1
- package/dist/cli.js +327 -50
- package/dist/cli.js.map +1 -1
- package/dist/server.js +201 -40
- package/dist/server.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +1 -1
- package/public/__avatar3d_test.html +156 -0
- package/public/agent-overlay.css +14 -6
- package/public/agent-overlay.js +6 -6
- package/public/agent-profile.css +9 -12
- package/public/agent-profile.js +91 -38
- package/public/app.js +471 -528
- package/public/avatar-3d-snap.js +205 -0
- package/public/avatar-3d.js +836 -0
- package/public/avatar-customizer.html +274 -0
- package/public/avatar3d-editor.css +240 -0
- package/public/avatar3d-editor.js +484 -0
- package/public/avatars/3d/chair.png +0 -0
- package/public/avatars/3d/first-principles.png +0 -0
- package/public/avatars/3d/historian.png +0 -0
- package/public/avatars/3d/long-horizon.png +0 -0
- package/public/avatars/3d/phenomenologist.png +0 -0
- package/public/avatars/3d/socrates.png +0 -0
- package/public/avatars/3d/user-empathy.png +0 -0
- package/public/avatars/3d/value-investor.png +0 -0
- package/public/core-avatars.js +86 -0
- package/public/home-3d-loader.js +15 -4
- package/public/home-3d-mock.js +25 -14
- package/public/home.html +78 -16
- package/public/i18n.js +8 -4
- package/public/icons/avatar_1779855104027.glb +0 -0
- package/public/icons/logo.png +0 -0
- package/public/icons/new-style.glb +0 -0
- package/public/icons/new-style2.glb +0 -0
- package/public/icons/new-style3.glb +0 -0
- package/public/icons/new-style4.glb +0 -0
- package/public/icons/new-style5.glb +0 -0
- package/public/icons/new-style6.glb +0 -0
- package/public/icons/office.glb +0 -0
- package/public/icons/stuff.glb +0 -0
- package/public/index.html +169 -141
- package/public/magazine.html +1 -1
- package/public/new-agent.js +46 -20
- package/public/newspaper.html +1 -1
- package/public/office-viewer.html +340 -0
- package/public/ppt.html +1 -1
- package/public/stuff-viewer.html +330 -0
- package/public/thread.css +16 -15
- package/public/user-settings.css +7 -31
- package/public/user-settings.js +75 -89
- package/public/vendor/BufferGeometryUtils.js +1434 -0
- package/public/vendor/DRACOLoader.js +739 -0
- package/public/vendor/GLTFLoader.js +4860 -0
- package/public/vendor/RoomEnvironment.js +185 -0
- package/public/vendor/SkeletonUtils.js +496 -0
- package/public/vendor/draco/draco_decoder.js +34 -0
- package/public/vendor/draco/draco_decoder.wasm +0 -0
- package/public/vendor/draco/draco_encoder.js +33 -0
- package/public/vendor/draco/draco_wasm_wrapper.js +117 -0
- package/public/vendor/meshopt_decoder.module.js +196 -0
- package/public/voice-3d-banner.js +19 -7
- package/public/voice-3d.js +1407 -432
- package/public/voice-replay.js +21 -0
- package/public/avatar-skill.js +0 -629
- package/public/avatars/chair-blink.svg +0 -1
- package/public/avatars/chair.svg +0 -1
- package/public/avatars/first-principles.svg +0 -1
- package/public/avatars/historian.svg +0 -1
- package/public/avatars/long-horizon.svg +0 -1
- package/public/avatars/phenomenologist.svg +0 -1
- package/public/avatars/socrates.svg +0 -1
- package/public/avatars/user-empathy.svg +0 -1
- package/public/avatars/value-investor.svg +0 -1
- 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);
|