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/boot.js +7 -3
- package/dist/boot.js.map +1 -1
- package/dist/cli.js +7 -3
- package/dist/cli.js.map +1 -1
- package/dist/server.js +4 -3
- 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/agent-overlay.css +14 -6
- package/public/agent-overlay.js +6 -6
- package/public/agent-profile.css +6 -3
- package/public/agent-profile.js +6 -6
- package/public/app.js +2 -2
- package/public/avatar-3d.js +48 -4
- package/public/avatar3d-editor.js +5 -2
- package/public/home-3d-mock.js +7 -7
- package/public/home.html +1 -1
- package/public/i18n.js +0 -4
- package/public/icons/new-style6.glb +0 -0
- package/public/index.html +21 -20
- package/public/magazine.html +1 -1
- package/public/newspaper.html +1 -1
- package/public/ppt.html +1 -1
- package/public/thread.css +8 -7
- package/public/user-settings.css +0 -21
- package/public/user-settings.js +0 -22
- package/public/voice-3d-banner.js +7 -7
- package/public/voice-3d.js +1 -1
- 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/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
package/dist/version.js.map
CHANGED
|
@@ -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.
|
|
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
package/public/agent-overlay.css
CHANGED
|
@@ -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:
|
|
117
|
-
height:
|
|
118
|
-
|
|
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; }
|
package/public/agent-overlay.js
CHANGED
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
name: "Socrates",
|
|
40
40
|
role: "The Skeptic",
|
|
41
41
|
handle: "@socrates",
|
|
42
|
-
avatar: "avatars/socrates.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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: [
|
package/public/agent-profile.css
CHANGED
|
@@ -1635,9 +1635,12 @@
|
|
|
1635
1635
|
}
|
|
1636
1636
|
.ap-avatar {
|
|
1637
1637
|
position: relative;
|
|
1638
|
-
width:
|
|
1639
|
-
height:
|
|
1640
|
-
margin-top
|
|
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;
|
package/public/agent-profile.js
CHANGED
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
/* ════════════════════════════════════ SOCRATES ════════════════════════════════════ */
|
|
44
44
|
"socrates": {
|
|
45
45
|
name: "Socrates", role: "The Skeptic", handle: "@socrates",
|
|
46
|
-
avatar: "avatars/socrates.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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) {
|
package/public/avatar-3d.js
CHANGED
|
@@ -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
|
-
* `
|
|
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) {
|
package/public/home-3d-mock.js
CHANGED
|
@@ -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.
|
|
36
|
-
{ id: "socrates", name: "Socrates", avatarPath: "/avatars/socrates.
|
|
37
|
-
{ id: "first-principles", name: "First Principles", avatarPath: "/avatars/first-principles.
|
|
38
|
-
{ id: "value-investor", name: "Value Investor", avatarPath: "/avatars/value-investor.
|
|
39
|
-
{ id: "user-empathy", name: "User-Empathy", avatarPath: "/avatars/user-empathy.
|
|
40
|
-
{ id: "long-horizon", name: "Long Horizon", avatarPath: "/avatars/long-horizon.
|
|
41
|
-
{ id: "phenomenologist", name: "Phenomenologist", avatarPath: "/avatars/phenomenologist.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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>
|
package/public/magazine.html
CHANGED
|
@@ -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.
|
|
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. -->
|
package/public/newspaper.html
CHANGED
|
@@ -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.
|
|
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
|