privateboard 0.1.37 → 0.1.40
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 +1415 -91
- package/dist/boot.js.map +1 -1
- package/dist/cli.js +1415 -91
- package/dist/cli.js.map +1 -1
- package/dist/server.js +1271 -81
- 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/adjourn-overlay.css +2 -2
- package/public/agent-overlay.css +27 -15
- package/public/agent-overlay.js +3 -1
- package/public/agent-profile.css +331 -41
- package/public/agent-profile.js +499 -75
- package/public/app-updater.css +1 -1
- package/public/app.js +2090 -547
- package/public/avatar-3d-snap.js +205 -0
- package/public/avatar-3d.js +792 -0
- package/public/avatar-customizer.html +274 -0
- package/public/avatar3d-editor.css +240 -0
- package/public/avatar3d-editor.js +481 -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 +18 -7
- package/public/home.html +80 -18
- package/public/i18n.js +279 -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/office.glb +0 -0
- package/public/icons/stuff.glb +0 -0
- package/public/index.html +203 -182
- package/public/mention-picker.js +1 -1
- package/public/new-agent.css +7 -7
- package/public/new-agent.js +46 -20
- package/public/office-viewer.html +340 -0
- package/public/onboarding.css +5 -5
- package/public/quote-cta.css +5 -4
- package/public/quote-cta.js +50 -5
- package/public/room-settings.css +24 -9
- package/public/stuff-viewer.html +330 -0
- package/public/thread.css +1211 -0
- package/public/user-settings.css +16 -19
- package/public/user-settings.js +86 -78
- 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 +12 -0
- package/public/voice-3d.js +1407 -432
- package/public/voice-clone.css +875 -0
- package/public/voice-clone.js +1351 -0
- package/public/voice-replay.css +3 -3
- package/public/voice-replay.js +21 -0
- package/public/avatar-skill.js +0 -629
- package/public/icons/folded-sidebar.png +0 -0
package/public/user-settings.css
CHANGED
|
@@ -452,27 +452,24 @@
|
|
|
452
452
|
gap: 12px;
|
|
453
453
|
}
|
|
454
454
|
.us-avatar-frame {
|
|
455
|
-
width:
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
padding: 3px;
|
|
455
|
+
width: 64px; height: 64px;
|
|
456
|
+
padding: 0; /* avatar fills the container edge-to-edge */
|
|
457
|
+
overflow: hidden;
|
|
459
458
|
position: relative;
|
|
460
459
|
}
|
|
461
|
-
.us-avatar-frame::before, .us-avatar-frame::after {
|
|
462
|
-
content: "";
|
|
463
|
-
position: absolute;
|
|
464
|
-
width: 5px; height: 5px;
|
|
465
|
-
border: 0.5px solid var(--lime);
|
|
466
|
-
pointer-events: none;
|
|
467
|
-
}
|
|
468
|
-
.us-avatar-frame::before { top: -1px; left: -1px; border-right: none; border-bottom: none; }
|
|
469
|
-
.us-avatar-frame::after { bottom: -1px; right: -1px; border-left: none; border-top: none; }
|
|
470
460
|
.us-avatar-frame svg {
|
|
471
461
|
width: 100%; height: 100%;
|
|
472
462
|
image-rendering: pixelated;
|
|
473
463
|
image-rendering: -moz-crisp-edges;
|
|
474
464
|
display: block;
|
|
475
465
|
}
|
|
466
|
+
/* 3D portrait PNG · the capture is already framed head-and-shoulders
|
|
467
|
+
(face-anchored, identical to the agent profile avatar), so just cover-fit. */
|
|
468
|
+
.us-avatar-frame img {
|
|
469
|
+
width: 100%; height: 100%;
|
|
470
|
+
object-fit: cover;
|
|
471
|
+
display: block;
|
|
472
|
+
}
|
|
476
473
|
|
|
477
474
|
/* Buttons */
|
|
478
475
|
.us-mini-btn {
|
|
@@ -537,7 +534,7 @@
|
|
|
537
534
|
content: ">";
|
|
538
535
|
color: var(--lime);
|
|
539
536
|
font-weight: 700;
|
|
540
|
-
font-size:
|
|
537
|
+
font-size: 14px;
|
|
541
538
|
font-family: var(--mono);
|
|
542
539
|
padding: 9px 0 0 11px;
|
|
543
540
|
align-self: flex-start;
|
|
@@ -547,7 +544,7 @@
|
|
|
547
544
|
border: none;
|
|
548
545
|
background: transparent;
|
|
549
546
|
font-family: var(--font-human);
|
|
550
|
-
font-size:
|
|
547
|
+
font-size: 14px;
|
|
551
548
|
line-height: 1.5;
|
|
552
549
|
color: var(--text);
|
|
553
550
|
outline: none;
|
|
@@ -857,7 +854,7 @@
|
|
|
857
854
|
}
|
|
858
855
|
.us-signout-text {
|
|
859
856
|
font-family: var(--font-human);
|
|
860
|
-
font-size:
|
|
857
|
+
font-size: 14px;
|
|
861
858
|
color: var(--text-soft);
|
|
862
859
|
line-height: 1.6;
|
|
863
860
|
}
|
|
@@ -1021,7 +1018,7 @@
|
|
|
1021
1018
|
font-weight: 600;
|
|
1022
1019
|
}
|
|
1023
1020
|
.us-chart-meta-value {
|
|
1024
|
-
font-size:
|
|
1021
|
+
font-size: 14px;
|
|
1025
1022
|
color: var(--text);
|
|
1026
1023
|
font-weight: 700;
|
|
1027
1024
|
font-variant-numeric: tabular-nums;
|
|
@@ -1293,7 +1290,7 @@
|
|
|
1293
1290
|
font-family: var(--mono, "Inter", system-ui, sans-serif);
|
|
1294
1291
|
}
|
|
1295
1292
|
.us-model-tokens {
|
|
1296
|
-
font-size:
|
|
1293
|
+
font-size: 14px;
|
|
1297
1294
|
color: var(--text);
|
|
1298
1295
|
font-weight: 700;
|
|
1299
1296
|
font-variant-numeric: tabular-nums;
|
|
@@ -2101,7 +2098,7 @@
|
|
|
2101
2098
|
.us-llm-pick-single { min-height: 64px; }
|
|
2102
2099
|
.us-llm-pick-label {
|
|
2103
2100
|
font-family: var(--mono);
|
|
2104
|
-
font-size:
|
|
2101
|
+
font-size: 14px;
|
|
2105
2102
|
font-weight: 700;
|
|
2106
2103
|
color: var(--text);
|
|
2107
2104
|
}
|
package/public/user-settings.js
CHANGED
|
@@ -166,6 +166,8 @@
|
|
|
166
166
|
name: typeof data.name === "string" ? data.name : "You",
|
|
167
167
|
intro: typeof data.intro === "string" ? data.intro : "",
|
|
168
168
|
avatarSeed: data.avatarSeed ?? null,
|
|
169
|
+
avatar3d: data.avatar3d ?? null,
|
|
170
|
+
avatarUrl: data.avatarUrl ?? null,
|
|
169
171
|
webSearchProvider: data.webSearchProvider === "tavily" ? "tavily" : "brave",
|
|
170
172
|
minimaxRegion: data.minimaxRegion === "intl" ? "intl" : "cn",
|
|
171
173
|
};
|
|
@@ -187,11 +189,22 @@
|
|
|
187
189
|
body: JSON.stringify({
|
|
188
190
|
name: u.name,
|
|
189
191
|
intro: u.intro,
|
|
190
|
-
avatarSeed: u.avatarSeed
|
|
192
|
+
avatarSeed: u.avatarSeed,
|
|
193
|
+
...("avatarUrl" in u ? { avatarUrl: u.avatarUrl } : {}),
|
|
194
|
+
...("avatar3d" in u ? { avatar3d: u.avatar3d } : {}),
|
|
191
195
|
})
|
|
192
196
|
}).catch(() => { /* offline → cache stays, retry on next edit */ });
|
|
193
197
|
}
|
|
194
198
|
|
|
199
|
+
// The 3D-avatar editor (avatar3d-editor.js) saves the user's portrait via
|
|
200
|
+
// PUT /api/prefs and fires this event. Sync our cache + repaint the frame so
|
|
201
|
+
// the settings avatar updates without reopening the pane.
|
|
202
|
+
window.addEventListener("pb:user-avatar-updated", (e) => {
|
|
203
|
+
const url = e && e.detail && e.detail.avatarUrl;
|
|
204
|
+
_prefsCache = { ...(_prefsCache || {}), avatarUrl: url || null };
|
|
205
|
+
try { paintUserAvatar(); } catch (_) {}
|
|
206
|
+
});
|
|
207
|
+
|
|
195
208
|
// Provider keys · canonical state lives in keys-store.js (loaded as a
|
|
196
209
|
// module script before this file). All reads/writes go through that store;
|
|
197
210
|
// _keysMeta is a live accessor so the rest of this file needs no changes.
|
|
@@ -325,6 +338,10 @@
|
|
|
325
338
|
<div class="us-row-label">${tr("us_avatar")}</div>
|
|
326
339
|
<div class="us-row-field us-avatar-row">
|
|
327
340
|
<div class="us-avatar-frame" data-us-avatar></div>
|
|
341
|
+
<button type="button" class="us-mini-btn" data-us-avatar3d>
|
|
342
|
+
<span class="us-mini-btn-mark">◈</span>
|
|
343
|
+
<span>${tr("us_avatar3d")}</span>
|
|
344
|
+
</button>
|
|
328
345
|
<button type="button" class="us-mini-btn" data-us-regen-avatar>
|
|
329
346
|
<span class="us-mini-btn-mark">◆</span>
|
|
330
347
|
<span>${tr("us_regen_avatar")}</span>
|
|
@@ -367,30 +384,13 @@
|
|
|
367
384
|
}).join("");
|
|
368
385
|
}
|
|
369
386
|
|
|
370
|
-
/*
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
catch (_) { return true; }
|
|
378
|
-
}
|
|
379
|
-
function setStage3d(on) {
|
|
380
|
-
try { localStorage.setItem(STAGE3D_KEY, on ? "on" : "off"); } catch (_) {}
|
|
381
|
-
}
|
|
382
|
-
function stageStyleSegmentsHTML() {
|
|
383
|
-
const cur = getStage3d() ? "3d" : "2d";
|
|
384
|
-
const items = [
|
|
385
|
-
{ key: "3d", labelKey: "us_stage_3d" },
|
|
386
|
-
{ key: "2d", labelKey: "us_stage_2d" },
|
|
387
|
-
];
|
|
388
|
-
return items.map(({ key, labelKey }) => {
|
|
389
|
-
const label = tr(labelKey);
|
|
390
|
-
const cls = "us-seg-btn" + (key === cur ? " active" : "");
|
|
391
|
-
return `<button type="button" class="${cls}" data-stage="${key}" role="radio" aria-checked="${key === cur ? "true" : "false"}">${escape(label)}</button>`;
|
|
392
|
-
}).join("");
|
|
393
|
-
}
|
|
387
|
+
/* The 2D / 3D stage toggle was retired (2026-05) · the voice room
|
|
388
|
+
is 3D-only now. `STAGE3D_KEY` / `getStage3d` / `setStage3d` /
|
|
389
|
+
`stageStyleSegmentsHTML` used to live here and have been removed
|
|
390
|
+
along with their row in `otherSettingsSectionHTML` and the click
|
|
391
|
+
handler below. The localStorage key the toggle persisted to
|
|
392
|
+
(`boardroom.stage3d`) is also no longer consulted anywhere; old
|
|
393
|
+
values are inert. */
|
|
394
394
|
|
|
395
395
|
function otherSettingsSectionHTML() {
|
|
396
396
|
return `
|
|
@@ -410,16 +410,6 @@
|
|
|
410
410
|
</div>
|
|
411
411
|
</div>
|
|
412
412
|
|
|
413
|
-
<div class="us-row">
|
|
414
|
-
<div class="us-row-label">${tr("us_stage_label")}</div>
|
|
415
|
-
<div class="us-row-field">
|
|
416
|
-
<div class="us-seg" role="radiogroup" aria-label="${escape(tr("us_stage_label"))}" data-us-stage>
|
|
417
|
-
${stageStyleSegmentsHTML()}
|
|
418
|
-
</div>
|
|
419
|
-
<p class="us-locale-deck">${escape(tr("us_stage_deck"))}</p>
|
|
420
|
-
</div>
|
|
421
|
-
</div>
|
|
422
|
-
|
|
423
413
|
<div class="us-row">
|
|
424
414
|
<div class="us-row-label">${tr("us_locale_label")}</div>
|
|
425
415
|
<div class="us-row-field">
|
|
@@ -493,25 +483,8 @@
|
|
|
493
483
|
// the app to re-render the current round-table so the swap is
|
|
494
484
|
// visible immediately for anyone currently sitting in a voice
|
|
495
485
|
// room (instead of "have to leave + re-enter to see it").
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
stGroup.addEventListener("click", (e) => {
|
|
499
|
-
const btn = e.target.closest(".us-seg-btn[data-stage]");
|
|
500
|
-
if (!btn) return;
|
|
501
|
-
const next = btn.dataset.stage; // "3d" | "2d"
|
|
502
|
-
setStage3d(next === "3d");
|
|
503
|
-
stGroup.querySelectorAll(".us-seg-btn").forEach((el) => {
|
|
504
|
-
const on = el.dataset.stage === next;
|
|
505
|
-
el.classList.toggle("active", on);
|
|
506
|
-
el.setAttribute("aria-checked", on ? "true" : "false");
|
|
507
|
-
});
|
|
508
|
-
try {
|
|
509
|
-
if (window.app && typeof window.app.renderRoundTable === "function") {
|
|
510
|
-
window.app.renderRoundTable();
|
|
511
|
-
}
|
|
512
|
-
} catch (_) { /* room may not be a voice room · ignore */ }
|
|
513
|
-
});
|
|
514
|
-
}
|
|
486
|
+
// [removed 2026-05] The 2D/3D stage toggle wire-up used to live
|
|
487
|
+
// here · the voice room is 3D-only now, no toggle to bind.
|
|
515
488
|
// Typing-sound toggle · the persistence + audio context lives in
|
|
516
489
|
// window.boardroomTypingSfx (typing-sfx.js); this row only mirrors
|
|
517
490
|
// the current state and proxies clicks. Reading inside wire-up
|
|
@@ -1840,11 +1813,14 @@
|
|
|
1840
1813
|
|
|
1841
1814
|
/* Avatar generation · same flow as the agent profile's regenerate
|
|
1842
1815
|
button (see agent-profile.js / regenerateProfileAvatar): each
|
|
1843
|
-
click pulls a fresh seed from
|
|
1844
|
-
to the user prefs (`avatarSeed`), and re-paints.
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1816
|
+
click pulls a fresh seed from Avatar3DSnap.randomSeed(), saves
|
|
1817
|
+
it to the user prefs (`avatarSeed`), and re-paints. Renders a
|
|
1818
|
+
3D voxel head-and-shoulders portrait (the legacy AvatarSkill
|
|
1819
|
+
8-bit SVG generator was retired). */
|
|
1820
|
+
// Synchronous "still rendering" placeholder used while the async
|
|
1821
|
+
// 3D snap is in flight · pure CSS via the .us-avatar-frame parent.
|
|
1822
|
+
function loadingHtml() {
|
|
1823
|
+
return '<div class="us-avatar-loading" aria-hidden="true">…</div>';
|
|
1848
1824
|
}
|
|
1849
1825
|
|
|
1850
1826
|
/* ── Modal shell ──────────────────────────────────────────── */
|
|
@@ -1918,21 +1894,44 @@
|
|
|
1918
1894
|
const frame = paneEl.querySelector("[data-us-avatar]");
|
|
1919
1895
|
if (!frame) return;
|
|
1920
1896
|
const u = getUser();
|
|
1921
|
-
//
|
|
1922
|
-
//
|
|
1923
|
-
//
|
|
1897
|
+
// 3D portrait takes precedence · if the user customised a 3D
|
|
1898
|
+
// avatar in the editor (avatarUrl is the rendered PNG), show
|
|
1899
|
+
// that. Otherwise render an async 3D snap from the user's seed.
|
|
1900
|
+
if (u.avatarUrl) {
|
|
1901
|
+
frame.innerHTML = `<img src="${u.avatarUrl}" alt="">`;
|
|
1902
|
+
return;
|
|
1903
|
+
}
|
|
1904
|
+
const snap = window.Avatar3DSnap;
|
|
1924
1905
|
let seed = u.avatarSeed;
|
|
1925
|
-
if (!seed &&
|
|
1926
|
-
seed =
|
|
1906
|
+
if (!seed && snap) {
|
|
1907
|
+
seed = snap.randomSeed();
|
|
1927
1908
|
saveUser({ avatarSeed: seed });
|
|
1928
|
-
// Cascade the freshly-minted seed to app.prefs so the sidebar
|
|
1929
|
-
// foot picks it up on the same paint.
|
|
1930
1909
|
if (window.app) {
|
|
1931
1910
|
window.app.prefs = { ...(window.app.prefs || {}), avatarSeed: seed };
|
|
1932
1911
|
if (typeof window.app.renderUserBlock === "function") window.app.renderUserBlock();
|
|
1933
1912
|
}
|
|
1934
1913
|
}
|
|
1935
|
-
|
|
1914
|
+
if (!seed || !snap) {
|
|
1915
|
+
// No snap helper / no seed · clear the frame so the underlying
|
|
1916
|
+
// CSS placeholder shows (the .us-avatar-frame already has its
|
|
1917
|
+
// own initial styling).
|
|
1918
|
+
frame.innerHTML = "";
|
|
1919
|
+
return;
|
|
1920
|
+
}
|
|
1921
|
+
const cached = typeof snap.cacheGet === "function" ? snap.cacheGet(seed) : null;
|
|
1922
|
+
if (cached) {
|
|
1923
|
+
frame.innerHTML = `<img src="${cached}" alt="">`;
|
|
1924
|
+
return;
|
|
1925
|
+
}
|
|
1926
|
+
frame.innerHTML = loadingHtml();
|
|
1927
|
+
snap.generate(seed).then((url) => {
|
|
1928
|
+
if (!url) return;
|
|
1929
|
+
// Only paint if the frame is still in the DOM and showing the
|
|
1930
|
+
// same loading state (user may have already swapped avatars).
|
|
1931
|
+
const f2 = paneEl.querySelector("[data-us-avatar]");
|
|
1932
|
+
if (!f2) return;
|
|
1933
|
+
f2.innerHTML = `<img src="${url}" alt="">`;
|
|
1934
|
+
}).catch(() => { /* */ });
|
|
1936
1935
|
}
|
|
1937
1936
|
|
|
1938
1937
|
function wireUserSection() {
|
|
@@ -1960,25 +1959,34 @@
|
|
|
1960
1959
|
introCount.textContent = introInput.value.length;
|
|
1961
1960
|
|
|
1962
1961
|
// Regenerate avatar · same pattern as agent-profile's
|
|
1963
|
-
// regenerateProfileAvatar: pull a fresh
|
|
1964
|
-
//
|
|
1965
|
-
//
|
|
1962
|
+
// regenerateProfileAvatar: pull a fresh seed, persist to the
|
|
1963
|
+
// user prefs, and repaint. Clears any captured 3D customizer
|
|
1964
|
+
// PNG (avatarUrl / avatar3d) so the next paint takes the new
|
|
1965
|
+
// seed-derived 3D snap rather than the previous capture.
|
|
1966
1966
|
paneEl.querySelector("[data-us-regen-avatar]").addEventListener("click", (e) => {
|
|
1967
1967
|
e.preventDefault();
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1968
|
+
const snap = window.Avatar3DSnap;
|
|
1969
|
+
if (!snap || typeof snap.randomSeed !== "function") return;
|
|
1970
|
+
const seed = snap.randomSeed();
|
|
1971
|
+
saveUser({ avatarSeed: seed, avatarUrl: null, avatar3d: null });
|
|
1971
1972
|
paintUserAvatar();
|
|
1972
|
-
// Push the new seed into app.prefs so the sidebar foot's user
|
|
1973
|
-
// avatar repaints with the same SVG. Without this, the settings
|
|
1974
|
-
// overlay shows the new face but the sidebar keeps the old one
|
|
1975
|
-
// until the next reload.
|
|
1976
1973
|
if (window.app) {
|
|
1977
|
-
window.app.prefs = { ...(window.app.prefs || {}), avatarSeed: seed };
|
|
1974
|
+
window.app.prefs = { ...(window.app.prefs || {}), avatarSeed: seed, avatarUrl: null, avatar3d: null };
|
|
1978
1975
|
if (typeof window.app.renderUserBlock === "function") window.app.renderUserBlock();
|
|
1979
1976
|
}
|
|
1980
1977
|
});
|
|
1981
1978
|
|
|
1979
|
+
// Customize 3D avatar · opens the shared editor in "user" mode. The
|
|
1980
|
+
// editor saves the rendered PNG + config to prefs (PUT /api/prefs) and
|
|
1981
|
+
// fires "pb:user-avatar-updated"; we repaint the frame on that event.
|
|
1982
|
+
const a3dBtn = paneEl.querySelector("[data-us-avatar3d]");
|
|
1983
|
+
if (a3dBtn) {
|
|
1984
|
+
a3dBtn.addEventListener("click", (e) => {
|
|
1985
|
+
e.preventDefault();
|
|
1986
|
+
if (typeof window.openAvatar3DEditor === "function") window.openAvatar3DEditor({ kind: "user" });
|
|
1987
|
+
});
|
|
1988
|
+
}
|
|
1989
|
+
|
|
1982
1990
|
paintUserAvatar();
|
|
1983
1991
|
}
|
|
1984
1992
|
|