privateboard 0.1.40 → 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/version.d.ts CHANGED
@@ -12,6 +12,6 @@
12
12
  * number ends up surfaced in the user-facing footer or banner. Keep
13
13
  * this file as the canonical source — every callsite reads from here.
14
14
  */
15
- declare const VERSION = "0.1.40";
15
+ declare const VERSION = "0.1.41";
16
16
 
17
17
  export { VERSION };
package/dist/version.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/version.ts
4
- var VERSION = "0.1.40";
4
+ var VERSION = "0.1.41";
5
5
  export {
6
6
  VERSION
7
7
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/version.ts"],"sourcesContent":["/**\n * Single source of truth for the app version.\n *\n * Imported by `cli.ts` (CLI banner / `--version`), `server.ts` (the\n * `/health` payload + the `/api/version` endpoint), and bundled into\n * the frontend via the version endpoint. Bump alongside `package.json`\n * on every release — the existing `npm version <patch|minor|major>`\n * + commit pattern updates package.json automatically; this file\n * needs the matching manual bump.\n *\n * If two strings drift (bumped one but not the other), the wrong\n * number ends up surfaced in the user-facing footer or banner. Keep\n * this file as the canonical source — every callsite reads from here.\n */\nexport const VERSION = \"0.1.40\";\n"],"mappings":";;;AAcO,IAAM,UAAU;","names":[]}
1
+ {"version":3,"sources":["../src/version.ts"],"sourcesContent":["/**\n * Single source of truth for the app version.\n *\n * Imported by `cli.ts` (CLI banner / `--version`), `server.ts` (the\n * `/health` payload + the `/api/version` endpoint), and bundled into\n * the frontend via the version endpoint. Bump alongside `package.json`\n * on every release — the existing `npm version <patch|minor|major>`\n * + commit pattern updates package.json automatically; this file\n * needs the matching manual bump.\n *\n * If two strings drift (bumped one but not the other), the wrong\n * number ends up surfaced in the user-facing footer or banner. Keep\n * this file as the canonical source — every callsite reads from here.\n */\nexport const VERSION = \"0.1.41\";\n"],"mappings":";;;AAcO,IAAM,UAAU;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "privateboard",
3
- "version": "0.1.40",
3
+ "version": "0.1.41",
4
4
  "description": "PrivateBoard · your private board meeting, on call. Local-first, multi-agent thinking amplifier.",
5
5
  "type": "module",
6
6
  "main": "electron-entry.cjs",
@@ -113,13 +113,10 @@ img[data-agent]:hover { filter: brightness(1.15); }
113
113
  border-bottom: 0.5px dashed var(--line-bright);
114
114
  }
115
115
  .agent-card-avatar {
116
- width: 68px;
117
- height: 68px;
118
- background: var(--panel-2);
119
- border: 0.5px solid var(--line-bright);
120
- padding: 5px;
116
+ width: 72px;
117
+ height: 72px;
118
+ margin: -10px 0 10px;
121
119
  display: block;
122
- image-rendering: pixelated;
123
120
  }
124
121
  .agent-card-id .name {
125
122
  font-size: 18px;
@@ -528,6 +525,17 @@ img[data-agent]:hover { filter: brightness(1.15); }
528
525
  border-color: var(--lime-dim);
529
526
  }
530
527
 
528
+ /* Hide the secondary voice-block sections inside the agent overlay.
529
+ The same renderVoiceBlock() is shared with the full agent-profile
530
+ page (where these stay visible); the overlay is meant to be a
531
+ quick read-only summary, not a place to type a preview line, run
532
+ a multi-minute clone job, or tune speed / pitch / timbre sliders.
533
+ Scope by parent so the profile page is untouched. */
534
+ .agent-overlay .ap-voice-section:has(> .ap-voice-forge),
535
+ .agent-overlay .ap-voice-section:has(.ap-voice-preview-text),
536
+ .agent-overlay .ap-voice-section:has(.ap-voice-emotion-row),
537
+ .agent-overlay .ap-voice-section:has(.ap-voice-advanced) { display: none; }
538
+
531
539
  @media (max-width: 600px) {
532
540
  .agent-overlay { padding: 12px; }
533
541
  .agent-card-head { grid-template-columns: auto 1fr; gap: 12px; padding: 14px 14px 12px; }
@@ -39,7 +39,7 @@
39
39
  name: "Socrates",
40
40
  role: "The Skeptic",
41
41
  handle: "@socrates",
42
- avatar: "avatars/socrates.svg",
42
+ avatar: "avatars/3d/socrates.png",
43
43
  lens: "Won't let any sentence pass without unpacking its assumptions three layers deep. Treats every word as a contract that must be defined before reasoning can begin.",
44
44
  traits: ["probing", "definitional", "patient", "rarely concedes"],
45
45
  memory: [
@@ -63,7 +63,7 @@
63
63
  name: "First Principles",
64
64
  role: "Causal Reasoning",
65
65
  handle: "@first_p",
66
- avatar: "avatars/first-principles.svg",
66
+ avatar: "avatars/3d/first-principles.png",
67
67
  lens: "Strips problems to their primitives. Refuses to reason in the middle layer where most thinking dies. Will rebuild the argument from physics if necessary.",
68
68
  traits: ["reductive", "literal", "cold", "physics-first"],
69
69
  memory: [
@@ -87,7 +87,7 @@
87
87
  name: "Value Investor",
88
88
  role: "Pattern Recognition",
89
89
  handle: "@value_inv",
90
- avatar: "avatars/value-investor.svg",
90
+ avatar: "avatars/3d/value-investor.png",
91
91
  lens: "Reads every judgment through a ten-year lens. Pattern recognition trained on twenty years of market history. Sees what's already been tried — and how it ended.",
92
92
  traits: ["historical", "skeptical of hype", "long-horizon", "selectively quiet"],
93
93
  memory: [
@@ -111,7 +111,7 @@
111
111
  name: "User-Empathy",
112
112
  role: "Empathy Lens",
113
113
  handle: "@user_e",
114
- avatar: "avatars/user-empathy.svg",
114
+ avatar: "avatars/3d/user-empathy.png",
115
115
  lens: "Asks why anyone would actually use this — never lets a feature pass without a real-person scenario. Holds the room accountable to people who aren't in it.",
116
116
  traits: ["narrative", "scenario-driven", "warm", "uncompromising"],
117
117
  memory: [
@@ -135,7 +135,7 @@
135
135
  name: "Long Horizon",
136
136
  role: "Historical Lens",
137
137
  handle: "@long_h",
138
- avatar: "avatars/long-horizon.svg",
138
+ avatar: "avatars/3d/long-horizon.png",
139
139
  lens: "Reads everything on a hundred-year scale. Knows which patterns repeat and which never do. Treats the present as a single frame in a much longer film.",
140
140
  traits: ["macro", "civilizational", "calm", "rare interjector"],
141
141
  memory: [
@@ -159,7 +159,7 @@
159
159
  name: "Phenomenologist",
160
160
  role: "Experience-First · Intern",
161
161
  handle: "@phen",
162
- avatar: "avatars/phenomenologist.svg",
162
+ avatar: "avatars/3d/phenomenologist.png",
163
163
  lens: "Begins from experience itself, without imposing structure. Currently on probation — has to earn a permanent seat, or step back to observer.",
164
164
  traits: ["unstructured", "first-person", "uneven", "promising"],
165
165
  memory: [
@@ -1635,9 +1635,12 @@
1635
1635
  }
1636
1636
  .ap-avatar {
1637
1637
  position: relative;
1638
- width: 76px;
1639
- height: 76px;
1640
- margin-top: -46px;
1638
+ width: 96px;
1639
+ height: 96px;
1640
+ /* Straddles the 84px cover · margin-top scaled with the size bump
1641
+ (was 76px/-46px) so the avatar keeps the same ~60% overlap into
1642
+ the cover and ~40% dropping into the body row. */
1643
+ margin-top: -58px;
1641
1644
  margin-bottom: 0;
1642
1645
  overflow: hidden;
1643
1646
  display: flex;
@@ -43,7 +43,7 @@
43
43
  /* ════════════════════════════════════ SOCRATES ════════════════════════════════════ */
44
44
  "socrates": {
45
45
  name: "Socrates", role: "The Skeptic", handle: "@socrates",
46
- avatar: "avatars/socrates.svg", status: "active", tenure: "core · 4 yr",
46
+ avatar: "avatars/3d/socrates.png", status: "active", tenure: "core · 4 yr",
47
47
  coverQuote: "won't let any sentence pass",
48
48
  meta: { creator: "@Kay", joined: "2024-04-01" },
49
49
  bio: [
@@ -114,7 +114,7 @@
114
114
  /* ════════════════════════════════════ FIRST PRINCIPLES ════════════════════════════ */
115
115
  "first-principles": {
116
116
  name: "First Principles", role: "Causal Reasoning", handle: "@first_p",
117
- avatar: "avatars/first-principles.svg", status: "active", tenure: "core · 4 yr",
117
+ avatar: "avatars/3d/first-principles.png", status: "active", tenure: "core · 4 yr",
118
118
  coverQuote: "what's the smallest unit?",
119
119
  meta: { creator: "@Kay", joined: "2024-04-01" },
120
120
  bio: [
@@ -177,7 +177,7 @@
177
177
  /* ════════════════════════════════════ VALUE INVESTOR ════════════════════════════ */
178
178
  "value-investor": {
179
179
  name: "Value Investor", role: "Pattern Recognition", handle: "@value_inv",
180
- avatar: "avatars/value-investor.svg", status: "active", tenure: "core · 3 yr",
180
+ avatar: "avatars/3d/value-investor.png", status: "active", tenure: "core · 3 yr",
181
181
  coverQuote: "who's tried this before?",
182
182
  meta: { creator: "@Kay", joined: "2024-08-14" },
183
183
  bio: [
@@ -242,7 +242,7 @@
242
242
  /* ════════════════════════════════════ USER-EMPATHY ════════════════════════════════ */
243
243
  "user-empathy": {
244
244
  name: "User-Empathy", role: "Empathy Lens", handle: "@user_e",
245
- avatar: "avatars/user-empathy.svg", status: "active", tenure: "core · 2 yr",
245
+ avatar: "avatars/3d/user-empathy.png", status: "active", tenure: "core · 2 yr",
246
246
  coverQuote: "name one user who'd reach for it",
247
247
  meta: { creator: "@Kay", joined: "2024-11-02" },
248
248
  bio: [
@@ -306,7 +306,7 @@
306
306
  /* ════════════════════════════════════ LONG HORIZON ════════════════════════════════ */
307
307
  "long-horizon": {
308
308
  name: "Long Horizon", role: "Historical Lens", handle: "@long_h",
309
- avatar: "avatars/long-horizon.svg", status: "active", tenure: "core · 2 yr",
309
+ avatar: "avatars/3d/long-horizon.png", status: "active", tenure: "core · 2 yr",
310
310
  coverQuote: "this is the cycle's mid-point",
311
311
  meta: { creator: "@Kay", joined: "2025-01-22" },
312
312
  bio: [
@@ -368,7 +368,7 @@
368
368
  /* ════════════════════════════════════ PHENOMENOLOGIST ═══════════════════════════ */
369
369
  "phenomenologist": {
370
370
  name: "Phenomenologist", role: "Experience-First", handle: "@phen",
371
- avatar: "avatars/phenomenologist.svg", status: "intern", tenure: "intern · trial",
371
+ avatar: "avatars/3d/phenomenologist.png", status: "intern", tenure: "intern · trial",
372
372
  coverQuote: "what is it like, actually?",
373
373
  meta: { creator: "@Kay", joined: "2026-03-08" },
374
374
  bio: [
package/public/app.js CHANGED
@@ -18206,7 +18206,7 @@
18206
18206
  }
18207
18207
  const avatarHtml = isUser
18208
18208
  ? userAvHtml
18209
- : `<img class="msg-av" src="${this.escape(author?.avatarPath || "/avatars/socrates.svg")}" alt=""${agentTag}>`;
18209
+ : `<img class="msg-av" src="${this.escape(author?.avatarPath || "/avatars/3d/socrates.png")}" alt=""${agentTag}>`;
18210
18210
 
18211
18211
  // Chair round-end: trim the POINTS: block from the bubble; the
18212
18212
  // vote card below the bubble surfaces the points as toggles.
@@ -19029,7 +19029,7 @@
19029
19029
  },
19030
19030
 
19031
19031
  /** Inline pixel-art chair sprite · 32×40 viewBox, painted as 1×1
19032
- * rect cells in the same vocabulary as /public/avatars/chair.svg.
19032
+ * rect cells in the same vocabulary as /public/avatars/3d/chair.png.
19033
19033
  * `isModerator: true` adds two cyan side-rails + a cyan headrest
19034
19034
  * gem to distinguish the chair's seat from the directors'. */
19035
19035
  renderRoundTableChairSvg(isModerator) {
@@ -128,6 +128,29 @@ export const AVATAR_MODELS = [
128
128
  { role: "tie", color: [0.074, 0.631, 0.753] }, // teal bow (neckwear)
129
129
  ],
130
130
  },
131
+ {
132
+ // Parts source only · supplies a top hat ("礼帽"), a low-ponytail
133
+ // hairstyle, distinct eyes, and a sleeveless dress. Not a standalone
134
+ // body (partsOnly).
135
+ id: "style6", label: "礼帽 · 背心裙", partsOnly: true,
136
+ url: "/icons/new-style6.glb",
137
+ accessory: "tophat",
138
+ colorRoles: [
139
+ { c: [0.913, 0.565, 0.376], role: "skin" },
140
+ { c: [0.147, 0.076, 0.031], role: "hair" }, // long ponytail hair
141
+ { c: [0.054, 0.054, 0.054], role: "outfit" }, // dark dress
142
+ { c: [0.913, 0.913, 0.913], role: "outfit" }, // light dress trim
143
+ ],
144
+ // The top hat is the only textured mesh → tag it as its own accessory
145
+ // role so it doesn't collide with classic's "hat". The dress's second
146
+ // white mesh is named "White.001", which the name rule would mis-tag as
147
+ // eyewhite (it sits at torso level, not the eyes) — force it to outfit so
148
+ // the outfit swap carries the whole dress.
149
+ partTags: [
150
+ { role: "tophat", textured: true },
151
+ { role: "outfit", name: "white" },
152
+ ],
153
+ },
131
154
  ];
132
155
  /** Back-compat · the first style's GLB. */
133
156
  export const DEFAULT_AVATAR_URL = AVATAR_MODELS[0].url;
@@ -306,7 +329,8 @@ function tagEyebrows(root, model) {
306
329
  * parts that colour/name classification can't separate — e.g. a white cap
307
330
  * that shares the shorts' colour, or sunglasses that would misfire as a hat
308
331
  * via the textured-mesh rule. Each rule matches on `textured` (has a map),
309
- * `color` ( base colour), and/or a `minY`/`maxY` band on the mesh's raw
332
+ * `name` (case-insensitive substring of the material name), `color`
333
+ * (≈ base colour), and/or a `minY`/`maxY` band on the mesh's raw
310
334
  * bounding-box centre; the first matching rule wins. Runs after tagEyebrows. */
311
335
  function tagModelParts(root, model) {
312
336
  if (!model.partTags || !model.partTags.length) return;
@@ -317,6 +341,7 @@ function tagModelParts(root, model) {
317
341
  let cy = null;
318
342
  for (const rule of model.partTags) {
319
343
  if (rule.textured && !m.map) continue;
344
+ if (rule.name && !(m.name || "").toLowerCase().includes(rule.name.toLowerCase())) continue;
320
345
  if (rule.color && !(m.color && colorNear(m.color, rule.color))) continue;
321
346
  if (rule.minY != null || rule.maxY != null) {
322
347
  if (cy == null) {
@@ -413,6 +438,12 @@ export function buildAvatar3D(seed, opts = {}) {
413
438
  const tieStyle = opts.tieStyle && opts.tieStyle !== "none" ? opts.tieStyle : null;
414
439
  if (tieStyle) overlayRole(group, inst, model, tieStyle, "tie");
415
440
 
441
+ // Eye-shape dimension · `opts.eyeStyle` is a model id whose eyes (role
442
+ // "eye") to wear; "default" / omitted / own id keeps the body's own eyes.
443
+ // Overlaid BEFORE painting so the swapped-in eyes still pick up 瞳色.
444
+ const eyeStyle = opts.eyeStyle && opts.eyeStyle !== "default" ? opts.eyeStyle : null;
445
+ if (eyeStyle) overlayRole(group, inst, model, eyeStyle, "eye");
446
+
416
447
  // Accessory dimension · independent of body style. `opts.accessory` is a
417
448
  // style id ("none" / "glasses" / "hat"); back-compat: false → "none",
418
449
  // true / undefined → the body's own accessory.
@@ -441,6 +472,7 @@ export function buildAvatar3D(seed, opts = {}) {
441
472
  group.userData.avatarOutfitStyle = outfitStyle;
442
473
  group.userData.avatarBrowStyle = browStyle || "default";
443
474
  group.userData.avatarTieStyle = tieStyle || "none";
475
+ group.userData.avatarEyeStyle = eyeStyle || "default";
444
476
  group.userData.avatarAccessory = accStyle;
445
477
  return group;
446
478
  }
@@ -496,8 +528,8 @@ function swapHair(group, inst, bodyModel, hairStyle) {
496
528
  }
497
529
 
498
530
  /** Which model supplies each accessory (it's baked into that model). */
499
- const ACCESSORY_SRC = { hat: "classic", glasses: "glasses", headphones: "casual", cap: "street", crown: "royal", santa: "xmas", shades: "xmas" };
500
- const ACCESSORY_ROLES = ["hat", "glasses", "headphones", "cap", "crown", "santa", "shades"];
531
+ const ACCESSORY_SRC = { hat: "classic", glasses: "glasses", headphones: "casual", cap: "street", crown: "royal", santa: "xmas", shades: "xmas", tophat: "style6" };
532
+ const ACCESSORY_ROLES = ["hat", "glasses", "headphones", "cap", "crown", "santa", "shades", "tophat"];
501
533
 
502
534
  /** Swap the avatar's accessory · independent of body style. Hides the
503
535
  * body's OWN accessory, then (if `accStyle` isn't "none" and isn't the
@@ -637,6 +669,7 @@ export const HAIR_STYLES = [
637
669
  { id: "street", label: "街头短发" },
638
670
  { id: "royal", label: "中长发/刘海" },
639
671
  { id: "xmas", label: "披肩长发" },
672
+ { id: "style6", label: "低马尾" },
640
673
  { id: "none", label: "无 (光头)" },
641
674
  ];
642
675
 
@@ -656,6 +689,14 @@ export const TIE_STYLES = [
656
689
  { id: "xmas", label: "蝴蝶结" },
657
690
  ];
658
691
 
692
+ /** Eye-shape dimension · "default" keeps the body's own eyes; each model id
693
+ * overlays that model's eye mesh (role "eye"), still tinted by 瞳色. The
694
+ * pupil COLOUR is a separate dimension (AVATAR_PALETTES.eye). */
695
+ export const EYE_STYLES = [
696
+ { id: "default", label: "默认" },
697
+ { id: "style6", label: "圆亮眼" },
698
+ ];
699
+
659
700
  /** Clothing styles offered by the customizer · an independent dimension.
660
701
  * Each id is a model whose outfit (role "outfit") is overlaid onto the
661
702
  * body. The body's own clothing is the default for each style. */
@@ -664,6 +705,7 @@ export const OUTFIT_STYLES = [
664
705
  { id: "glasses", label: "蓝白校园" },
665
706
  { id: "casual", label: "T恤短裤" },
666
707
  { id: "street", label: "黑T短裤·街头" },
708
+ { id: "style6", label: "背心裙" },
667
709
  ];
668
710
 
669
711
  /** Accessory styles offered by the customizer · an independent dimension.
@@ -677,6 +719,7 @@ export const ACCESSORY_STYLES = [
677
719
  { id: "cap", label: "鸭舌帽" },
678
720
  { id: "crown", label: "王冠" },
679
721
  { id: "santa", label: "圣诞帽" },
722
+ { id: "tophat", label: "礼帽" },
680
723
  ];
681
724
 
682
725
  /** Live-recolour an existing avatar Group without rebuilding (customizer
@@ -714,6 +757,7 @@ export function deriveDefaultAvatarConfig(seed) {
714
757
  accessory: pickId(ACCESSORY_STYLES),
715
758
  browStyle: "default", // keep the body's own brows by default
716
759
  tieStyle: "none", // no tie by default
760
+ eyeStyle: "default", // keep the body's own eyes by default
717
761
  skin: pick(SKIN_TONES, rng),
718
762
  hair,
719
763
  brow: hair,
@@ -787,6 +831,6 @@ if (typeof window !== "undefined") {
787
831
  deriveDefaultAvatarConfig,
788
832
  getFaceBox, applyFaceFraming,
789
833
  DEFAULT_AVATAR_URL, AVATAR_MODELS, AVATAR_PALETTES, HAIR_STYLES, OUTFIT_STYLES, ACCESSORY_STYLES,
790
- BROW_STYLES, TIE_STYLES,
834
+ BROW_STYLES, TIE_STYLES, EYE_STYLES,
791
835
  };
792
836
  }
@@ -55,6 +55,7 @@
55
55
  <div class="av3d-body">
56
56
  <div class="av3d-grp"><div class="av3d-lab">发型 Hair</div><div class="av3d-sw is-pill" data-row="hairStyle"></div></div>
57
57
  <div class="av3d-grp"><div class="av3d-lab">眼眉 Brow</div><div class="av3d-sw is-pill" data-row="browStyle"></div></div>
58
+ <div class="av3d-grp"><div class="av3d-lab">眼睛 Eyes</div><div class="av3d-sw is-pill" data-row="eyeStyle"></div></div>
58
59
  <div class="av3d-grp"><div class="av3d-lab">衣服款式 Outfit</div><div class="av3d-sw is-pill" data-row="outfitStyle"></div></div>
59
60
  <div class="av3d-grp"><div class="av3d-lab">领带 Tie</div><div class="av3d-sw is-pill" data-row="tieStyle"></div></div>
60
61
  <div class="av3d-grp"><div class="av3d-lab">装饰 Accessory</div><div class="av3d-sw is-pill" data-row="accessory"></div></div>
@@ -160,7 +161,7 @@
160
161
  if (group) { scene.remove(group); group = null; }
161
162
  group = av.buildAvatar3D(buildSeed || "editor", {
162
163
  model: sel.model, hairStyle: sel.hairStyle, outfitStyle: sel.outfitStyle,
163
- browStyle: sel.browStyle, tieStyle: sel.tieStyle,
164
+ browStyle: sel.browStyle, tieStyle: sel.tieStyle, eyeStyle: sel.eyeStyle,
164
165
  accessory: sel.accessory, height: AVATAR_HEIGHT,
165
166
  skin: sel.skin, hair: sel.hair, brow: sel.brow, outfit: sel.outfit, tie: sel.tie, eye: sel.eye,
166
167
  });
@@ -174,6 +175,7 @@
174
175
  const PILL_LISTS = () => ({
175
176
  hairStyle: av.HAIR_STYLES,
176
177
  browStyle: av.BROW_STYLES,
178
+ eyeStyle: av.EYE_STYLES,
177
179
  outfitStyle: av.OUTFIT_STYLES,
178
180
  tieStyle: av.TIE_STYLES,
179
181
  accessory: av.ACCESSORY_STYLES,
@@ -253,6 +255,7 @@
253
255
  // Newer dimensions · default when absent (configs saved before they existed).
254
256
  if (typeof out.browStyle !== "string" || !out.browStyle) out.browStyle = "default";
255
257
  if (typeof out.tieStyle !== "string" || !out.tieStyle) out.tieStyle = "none";
258
+ if (typeof out.eyeStyle !== "string" || !out.eyeStyle) out.eyeStyle = "default";
256
259
  if (typeof out.tie !== "string" || !out.tie) out.tie = (av.AVATAR_PALETTES.tie || ["#3b5b78"])[0];
257
260
  if (typeof out.eye !== "string" || !out.eye) out.eye = (av.AVATAR_PALETTES.eye || ["#0d0d0d"])[0];
258
261
  return out;
@@ -455,7 +458,7 @@
455
458
  try {
456
459
  const g = av.buildAvatar3D("portrait", {
457
460
  model: cfg.model, hairStyle: cfg.hairStyle, outfitStyle: cfg.outfitStyle,
458
- browStyle: cfg.browStyle, tieStyle: cfg.tieStyle, accessory: cfg.accessory, height: AVATAR_HEIGHT,
461
+ browStyle: cfg.browStyle, tieStyle: cfg.tieStyle, eyeStyle: cfg.eyeStyle, accessory: cfg.accessory, height: AVATAR_HEIGHT,
459
462
  skin: cfg.skin, hair: cfg.hair, brow: cfg.brow, outfit: cfg.outfit, tie: cfg.tie, eye: cfg.eye,
460
463
  });
461
464
  if (g) {
@@ -32,13 +32,13 @@
32
32
  with the moderator chair as the bottom-row anchor. 7 seats total
33
33
  fills the ring without empty arcs. */
34
34
  const CAST = [
35
- { id: "chair", name: "Chair", avatarPath: "/avatars/chair.svg", roleKind: "chair" },
36
- { id: "socrates", name: "Socrates", avatarPath: "/avatars/socrates.svg", roleKind: "director" },
37
- { id: "first-principles", name: "First Principles", avatarPath: "/avatars/first-principles.svg", roleKind: "director" },
38
- { id: "value-investor", name: "Value Investor", avatarPath: "/avatars/value-investor.svg", roleKind: "director" },
39
- { id: "user-empathy", name: "User-Empathy", avatarPath: "/avatars/user-empathy.svg", roleKind: "director" },
40
- { id: "long-horizon", name: "Long Horizon", avatarPath: "/avatars/long-horizon.svg", roleKind: "director" },
41
- { id: "phenomenologist", name: "Phenomenologist", avatarPath: "/avatars/phenomenologist.svg", roleKind: "director" },
35
+ { id: "chair", name: "Chair", avatarPath: "/avatars/3d/chair.png", roleKind: "chair" },
36
+ { id: "socrates", name: "Socrates", avatarPath: "/avatars/3d/socrates.png", roleKind: "director" },
37
+ { id: "first-principles", name: "First Principles", avatarPath: "/avatars/3d/first-principles.png", roleKind: "director" },
38
+ { id: "value-investor", name: "Value Investor", avatarPath: "/avatars/3d/value-investor.png", roleKind: "director" },
39
+ { id: "user-empathy", name: "User-Empathy", avatarPath: "/avatars/3d/user-empathy.png", roleKind: "director" },
40
+ { id: "long-horizon", name: "Long Horizon", avatarPath: "/avatars/3d/long-horizon.png", roleKind: "director" },
41
+ { id: "phenomenologist", name: "Phenomenologist", avatarPath: "/avatars/3d/phenomenologist.png", roleKind: "director" },
42
42
  ];
43
43
 
44
44
  /* Which of the five tone-keyed rooms (voice-3d.js) the homepage hero
package/public/home.html CHANGED
@@ -1670,7 +1670,7 @@
1670
1670
 
1671
1671
  <div class="hero-actions">
1672
1672
  <a href="#install" class="big-btn primary">[ ◆ Convene a Room ]</a>
1673
- <a href="https://github.com/kaysaith1900/privateboard/releases/download/v0.1.40/PrivateBoard-0.1.40-arm64.dmg"
1673
+ <a href="https://github.com/kaysaith1900/privateboard/releases/download/v0.1.41/PrivateBoard-0.1.41-arm64.dmg"
1674
1674
  class="big-btn secondary"
1675
1675
  download
1676
1676
  aria-label="Download PrivateBoard for macOS (Apple Silicon)"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M12 3v12"/><polyline points="6 11 12 17 18 11"/><path d="M5 21h14"/></svg> Download for Mac</a>
package/public/i18n.js CHANGED
@@ -1261,7 +1261,6 @@ When the room ___, raise an objection.`,
1261
1261
  us_user_tag: "▸ User",
1262
1262
  us_user_deck: "how the boardroom addresses you and what it knows about your context.",
1263
1263
  us_avatar: "Avatar",
1264
- us_regen_avatar: "8-bit avatar",
1265
1264
  us_avatar3d: "3D avatar",
1266
1265
  us_name: "Name",
1267
1266
  us_about: "About you",
@@ -2614,7 +2613,6 @@ When the room ___, raise an objection.`,
2614
2613
  us_user_tag: "▸ 用户",
2615
2614
  us_user_deck: "董事会如何称呼你,以及它需要知道的背景。",
2616
2615
  us_avatar: "头像",
2617
- us_regen_avatar: "8-bit 头像",
2618
2616
  us_avatar3d: "3D 形象",
2619
2617
  us_name: "姓名",
2620
2618
  us_about: "关于你",
@@ -3599,7 +3597,6 @@ When the room ___, raise an objection.`,
3599
3597
  us_user_tag: "▸ ユーザー",
3600
3598
  us_user_deck: "ボードルームでの呼称と、文脈として保持される情報。",
3601
3599
  us_avatar: "アバター",
3602
- us_regen_avatar: "8ビットアバター",
3603
3600
  us_avatar3d: "3Dアバター",
3604
3601
  us_name: "名前",
3605
3602
  us_about: "あなたについて",
@@ -4549,7 +4546,6 @@ When the room ___, raise an objection.`,
4549
4546
  us_user_tag: "▸ Usuario",
4550
4547
  us_user_deck: "cómo te llama la sala y qué sabe sobre tu contexto.",
4551
4548
  us_avatar: "Avatar",
4552
- us_regen_avatar: "avatar 8-bit",
4553
4549
  us_avatar3d: "avatar 3D",
4554
4550
  us_name: "Nombre",
4555
4551
  us_about: "Sobre ti",
Binary file
package/public/index.html CHANGED
@@ -1309,6 +1309,7 @@
1309
1309
  .agent-row .agent-row-av {
1310
1310
  width: 32px;
1311
1311
  height: 32px;
1312
+ margin-top: -10px;
1312
1313
  image-rendering: pixelated;
1313
1314
  image-rendering: crisp-edges;
1314
1315
  flex-shrink: 0;
@@ -17622,27 +17623,27 @@
17622
17623
  <svg class="rt-plant rt-plant-2" viewBox="0 0 48 60"><use href="#vrp-plant-2"/></svg>
17623
17624
  <div class="rt-seat rt-seat-chair" style="left:50%; top:82%;">
17624
17625
  <svg class="rt-chair rt-chair--mod" viewBox="0 0 32 40" preserveAspectRatio="xMidYMid meet"><use href="#vrp-chair-mod"/></svg>
17625
- <img class="rt-avatar" src="avatars/chair.svg" alt="">
17626
+ <img class="rt-avatar" src="avatars/3d/chair.png" alt="">
17626
17627
  <div class="rt-name">CHAIR</div>
17627
17628
  </div>
17628
17629
  <div class="rt-seat" style="left:14.89%; top:43.11%;">
17629
17630
  <svg class="rt-chair" viewBox="0 0 32 40" preserveAspectRatio="xMidYMid meet"><use href="#vrp-chair"/></svg>
17630
- <img class="rt-avatar" src="avatars/socrates.svg" alt="">
17631
+ <img class="rt-avatar" src="avatars/3d/socrates.png" alt="">
17631
17632
  <div class="rt-name">SOCRATES</div>
17632
17633
  </div>
17633
17634
  <div class="rt-seat rt-seat-speaking" style="left:35.45%; top:33.37%;">
17634
17635
  <svg class="rt-chair" viewBox="0 0 32 40" preserveAspectRatio="xMidYMid meet"><use href="#vrp-chair"/></svg>
17635
- <img class="rt-avatar" src="avatars/first-principles.svg" alt="">
17636
+ <img class="rt-avatar" src="avatars/3d/first-principles.png" alt="">
17636
17637
  <div class="rt-bubble">Speaking</div>
17637
17638
  </div>
17638
17639
  <div class="rt-seat" style="left:64.55%; top:33.37%;">
17639
17640
  <svg class="rt-chair" viewBox="0 0 32 40" preserveAspectRatio="xMidYMid meet"><use href="#vrp-chair"/></svg>
17640
- <img class="rt-avatar" src="avatars/value-investor.svg" alt="">
17641
+ <img class="rt-avatar" src="avatars/3d/value-investor.png" alt="">
17641
17642
  <div class="rt-name">INVESTOR</div>
17642
17643
  </div>
17643
17644
  <div class="rt-seat" style="left:85.11%; top:43.11%;">
17644
17645
  <svg class="rt-chair" viewBox="0 0 32 40" preserveAspectRatio="xMidYMid meet"><use href="#vrp-chair"/></svg>
17645
- <img class="rt-avatar" src="avatars/historian.svg" alt="">
17646
+ <img class="rt-avatar" src="avatars/3d/historian.png" alt="">
17646
17647
  <div class="rt-name">HISTORIAN</div>
17647
17648
  </div>
17648
17649
  </div>
@@ -17660,32 +17661,32 @@
17660
17661
  <svg class="rt-plant rt-plant-2" viewBox="0 0 48 60"><use href="#vrp-plant-2"/></svg>
17661
17662
  <div class="rt-seat rt-seat-chair" style="left:50%; top:82%;">
17662
17663
  <svg class="rt-chair rt-chair--mod" viewBox="0 0 32 40" preserveAspectRatio="xMidYMid meet"><use href="#vrp-chair-mod"/></svg>
17663
- <img class="rt-avatar" src="avatars/chair.svg" alt="">
17664
+ <img class="rt-avatar" src="avatars/3d/chair.png" alt="">
17664
17665
  <div class="rt-name">CHAIR</div>
17665
17666
  </div>
17666
17667
  <div class="rt-seat" style="left:13.86%; top:44.44%;">
17667
17668
  <svg class="rt-chair" viewBox="0 0 32 40" preserveAspectRatio="xMidYMid meet"><use href="#vrp-chair"/></svg>
17668
- <img class="rt-avatar" src="avatars/socrates.svg" alt="">
17669
+ <img class="rt-avatar" src="avatars/3d/socrates.png" alt="">
17669
17670
  <div class="rt-name">SOCRATES</div>
17670
17671
  </div>
17671
17672
  <div class="rt-seat" style="left:27.66%; top:35.44%;">
17672
17673
  <svg class="rt-chair" viewBox="0 0 32 40" preserveAspectRatio="xMidYMid meet"><use href="#vrp-chair"/></svg>
17673
- <img class="rt-avatar" src="avatars/first-principles.svg" alt="">
17674
+ <img class="rt-avatar" src="avatars/3d/first-principles.png" alt="">
17674
17675
  <div class="rt-name">PRINCIPLES</div>
17675
17676
  </div>
17676
17677
  <div class="rt-seat" style="left:50%; top:32%;">
17677
17678
  <svg class="rt-chair" viewBox="0 0 32 40" preserveAspectRatio="xMidYMid meet"><use href="#vrp-chair"/></svg>
17678
- <img class="rt-avatar" src="avatars/value-investor.svg" alt="">
17679
+ <img class="rt-avatar" src="avatars/3d/value-investor.png" alt="">
17679
17680
  <div class="rt-name">INVESTOR</div>
17680
17681
  </div>
17681
17682
  <div class="rt-seat rt-seat-speaking" style="left:72.34%; top:35.44%;">
17682
17683
  <svg class="rt-chair" viewBox="0 0 32 40" preserveAspectRatio="xMidYMid meet"><use href="#vrp-chair"/></svg>
17683
- <img class="rt-avatar" src="avatars/historian.svg" alt="">
17684
+ <img class="rt-avatar" src="avatars/3d/historian.png" alt="">
17684
17685
  <div class="rt-bubble">Speaking</div>
17685
17686
  </div>
17686
17687
  <div class="rt-seat" style="left:86.14%; top:44.44%;">
17687
17688
  <svg class="rt-chair" viewBox="0 0 32 40" preserveAspectRatio="xMidYMid meet"><use href="#vrp-chair"/></svg>
17688
- <img class="rt-avatar" src="avatars/long-horizon.svg" alt="">
17689
+ <img class="rt-avatar" src="avatars/3d/long-horizon.png" alt="">
17689
17690
  <div class="rt-name">HORIZON</div>
17690
17691
  </div>
17691
17692
  </div>
@@ -17703,22 +17704,22 @@
17703
17704
  <svg class="rt-plant rt-plant-2" viewBox="0 0 48 60"><use href="#vrp-plant-2"/></svg>
17704
17705
  <div class="rt-seat rt-seat-chair" style="left:50%; top:82%;">
17705
17706
  <svg class="rt-chair rt-chair--mod" viewBox="0 0 32 40" preserveAspectRatio="xMidYMid meet"><use href="#vrp-chair-mod"/></svg>
17706
- <img class="rt-avatar" src="avatars/chair.svg" alt="">
17707
+ <img class="rt-avatar" src="avatars/3d/chair.png" alt="">
17707
17708
  <div class="rt-name">CHAIR</div>
17708
17709
  </div>
17709
17710
  <div class="rt-seat" style="left:17.09%; top:41%;">
17710
17711
  <svg class="rt-chair" viewBox="0 0 32 40" preserveAspectRatio="xMidYMid meet"><use href="#vrp-chair"/></svg>
17711
- <img class="rt-avatar" src="avatars/socrates.svg" alt="">
17712
+ <img class="rt-avatar" src="avatars/3d/socrates.png" alt="">
17712
17713
  <div class="rt-name">SOCRATES</div>
17713
17714
  </div>
17714
17715
  <div class="rt-seat rt-seat-speaking" style="left:50%; top:32%;">
17715
17716
  <svg class="rt-chair" viewBox="0 0 32 40" preserveAspectRatio="xMidYMid meet"><use href="#vrp-chair"/></svg>
17716
- <img class="rt-avatar" src="avatars/first-principles.svg" alt="">
17717
+ <img class="rt-avatar" src="avatars/3d/first-principles.png" alt="">
17717
17718
  <div class="rt-bubble">Speaking</div>
17718
17719
  </div>
17719
17720
  <div class="rt-seat" style="left:82.91%; top:41%;">
17720
17721
  <svg class="rt-chair" viewBox="0 0 32 40" preserveAspectRatio="xMidYMid meet"><use href="#vrp-chair"/></svg>
17721
- <img class="rt-avatar" src="avatars/value-investor.svg" alt="">
17722
+ <img class="rt-avatar" src="avatars/3d/value-investor.png" alt="">
17722
17723
  <div class="rt-name">INVESTOR</div>
17723
17724
  </div>
17724
17725
  </div>
@@ -17736,27 +17737,27 @@
17736
17737
  <svg class="rt-plant rt-plant-2" viewBox="0 0 48 60"><use href="#vrp-plant-2"/></svg>
17737
17738
  <div class="rt-seat rt-seat-chair" style="left:50%; top:82%;">
17738
17739
  <svg class="rt-chair rt-chair--mod" viewBox="0 0 32 40" preserveAspectRatio="xMidYMid meet"><use href="#vrp-chair-mod"/></svg>
17739
- <img class="rt-avatar" src="avatars/chair.svg" alt="">
17740
+ <img class="rt-avatar" src="avatars/3d/chair.png" alt="">
17740
17741
  <div class="rt-name">CHAIR</div>
17741
17742
  </div>
17742
17743
  <div class="rt-seat rt-seat-speaking" style="left:14.89%; top:43.11%;">
17743
17744
  <svg class="rt-chair" viewBox="0 0 32 40" preserveAspectRatio="xMidYMid meet"><use href="#vrp-chair"/></svg>
17744
- <img class="rt-avatar" src="avatars/socrates.svg" alt="">
17745
+ <img class="rt-avatar" src="avatars/3d/socrates.png" alt="">
17745
17746
  <div class="rt-bubble">Speaking</div>
17746
17747
  </div>
17747
17748
  <div class="rt-seat" style="left:35.45%; top:33.37%;">
17748
17749
  <svg class="rt-chair" viewBox="0 0 32 40" preserveAspectRatio="xMidYMid meet"><use href="#vrp-chair"/></svg>
17749
- <img class="rt-avatar" src="avatars/first-principles.svg" alt="">
17750
+ <img class="rt-avatar" src="avatars/3d/first-principles.png" alt="">
17750
17751
  <div class="rt-name">PRINCIPLES</div>
17751
17752
  </div>
17752
17753
  <div class="rt-seat" style="left:64.55%; top:33.37%;">
17753
17754
  <svg class="rt-chair" viewBox="0 0 32 40" preserveAspectRatio="xMidYMid meet"><use href="#vrp-chair"/></svg>
17754
- <img class="rt-avatar" src="avatars/value-investor.svg" alt="">
17755
+ <img class="rt-avatar" src="avatars/3d/value-investor.png" alt="">
17755
17756
  <div class="rt-name">INVESTOR</div>
17756
17757
  </div>
17757
17758
  <div class="rt-seat" style="left:85.11%; top:43.11%;">
17758
17759
  <svg class="rt-chair" viewBox="0 0 32 40" preserveAspectRatio="xMidYMid meet"><use href="#vrp-chair"/></svg>
17759
- <img class="rt-avatar" src="avatars/phenomenologist.svg" alt="">
17760
+ <img class="rt-avatar" src="avatars/3d/phenomenologist.png" alt="">
17760
17761
  <div class="rt-name">PHENOM</div>
17761
17762
  </div>
17762
17763
  </div>
@@ -4,7 +4,7 @@
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=900, initial-scale=1">
6
6
  <title>Magazine · PrivateBoard</title>
7
- <link rel="icon" href="/avatars/chair.svg" type="image/svg+xml">
7
+ <link rel="icon" href="/avatars/3d/chair.png" type="image/svg+xml">
8
8
  <!-- Playfair Display for the Vogue-style high-contrast Didot
9
9
  logotype + serif headlines. Free Google font · no fallback
10
10
  drama since the system Tiempos / Bodoni stack picks up. -->
@@ -4,7 +4,7 @@
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=900, initial-scale=1">
6
6
  <title>Newspaper · PrivateBoard</title>
7
- <link rel="icon" href="/avatars/chair.svg" type="image/svg+xml">
7
+ <link rel="icon" href="/avatars/3d/chair.png" type="image/svg+xml">
8
8
  <!-- NYT blackletter nameplate · UnifrakturMaguntia is the free
9
9
  open-source font that reads as "Old English / Fraktur" the way
10
10
  the iconic NYT mast does. Loaded from Google Fonts; system