@bongos/core 1.24.86 → 1.24.88
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/.bongos-core.json +76 -66
- package/docs/adr/0402-helm-is-the-halls-look-and-the-hall-is-dark-only.md +15 -0
- package/docs/copy-inventory.md +6 -6
- package/docs/copy-registry.json +6 -6
- package/docs/module-api-changelog.md +4 -0
- package/docs/page-inventory.json +2 -0
- package/docs/page-readings.json +36 -36
- package/modules/hall-ui/public/ai-studio.html +1 -1
- package/modules/hall-ui/public/atlas.html +1 -1
- package/modules/hall-ui/public/blockers.html +1 -1
- package/modules/hall-ui/public/board-room.html +1 -1
- package/modules/hall-ui/public/city-draw.js +127 -69
- package/modules/hall-ui/public/city.css +37 -3
- package/modules/hall-ui/public/city.html +16 -5
- package/modules/hall-ui/public/city.js +26 -1
- package/modules/hall-ui/public/collab.html +1 -1
- package/modules/hall-ui/public/commands.html +1 -1
- package/modules/hall-ui/public/copy-desk.html +1 -1
- package/modules/hall-ui/public/deploy.html +1 -1
- package/modules/hall-ui/public/goal-map.html +2 -2
- package/modules/hall-ui/public/goals.html +1 -1
- package/modules/hall-ui/public/government.html +1 -1
- package/modules/hall-ui/public/home-city-draw.js +88 -54
- package/modules/hall-ui/public/home-city.css +25 -3
- package/modules/hall-ui/public/idea.html +1 -1
- package/modules/hall-ui/public/ideas.html +1 -1
- package/modules/hall-ui/public/index.html +6 -4
- package/modules/hall-ui/public/market-watch-item.html +1 -1
- package/modules/hall-ui/public/market-watch-rules.html +1 -1
- package/modules/hall-ui/public/market-watch.html +1 -1
- package/modules/hall-ui/public/modules.html +1 -1
- package/modules/hall-ui/public/money.html +1 -1
- package/modules/hall-ui/public/my-agents.html +1 -1
- package/modules/hall-ui/public/primer.html +1 -1
- package/modules/hall-ui/public/profile.html +1 -1
- package/modules/hall-ui/public/project-settings.html +1 -1
- package/modules/hall-ui/public/roster.html +1 -1
- package/modules/hall-ui/public/settings.html +1 -1
- package/modules/hall-ui/public/sky-time.js +206 -0
- package/modules/hall-ui/public/street.html +2 -2
- package/modules/hall-ui/public/studio.html +1 -1
- package/modules/hall-ui/public/style.css +86 -1
- package/modules/hall-ui/public/task.html +1 -1
- package/modules/hall-ui/public/thinking.html +2 -2
- package/modules/hall-ui/public/tweak-editor.html +1 -1
- package/modules/hall-ui/public/visor.css +13 -14
- package/modules/hall-ui/public/watch.html +1 -1
- package/modules/hall-ui/public/work.html +1 -1
- package/modules/hall-ui/records/home-city.md +13 -0
- package/modules/hall-ui/records/living-city.md +12 -0
- package/modules/hall-ui/records/visor.md +1 -1
- package/modules/ui-design/public/brand.html +1 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +12 -0
- package/src/module-api.js +1 -1
- package/tests/hall_city.mjs +72 -22
- package/tests/hall_city_living.mjs +10 -3
- package/tests/hall_sky_time.mjs +361 -0
- package/tests/hall_street.mjs +2 -1
- package/tests/hall_visor.mjs +18 -8
- package/tests/home_city.mjs +54 -5
|
@@ -37,10 +37,13 @@
|
|
|
37
37
|
// shapes, so tests run it in node (the roadmap-timeline.js precedent). The scene
|
|
38
38
|
// comes back as a tree of plain shape objects, never markup (see citySvg).
|
|
39
39
|
//
|
|
40
|
-
// THE PALETTE
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
// (
|
|
40
|
+
// THE PALETTE (task 1005196: the city in the clouds) is the hour's sky tokens
|
|
41
|
+
// (--sky-now-*, style.css; set by sky-time.js) and mixes of them, as city-draw.js
|
|
42
|
+
// isoTheme is: this file types in no colour. There is no ground; a face that stands in
|
|
43
|
+
// the cloud fades into it (the gradients are city-draw.js skyDefs, put in this scene's
|
|
44
|
+
// <defs>), and cloud lies behind the city, at each tower's foot and in front of it.
|
|
45
|
+
// A face pin, the artists' glass and the salmon of what waits on the viewer are the
|
|
46
|
+
// hall's own tokens, so they mean the same at every hour.
|
|
44
47
|
(function (root) {
|
|
45
48
|
'use strict';
|
|
46
49
|
|
|
@@ -67,50 +70,64 @@
|
|
|
67
70
|
const LOOSE = { cx: 690, cy: 312, rx: 150, ry: 54 };
|
|
68
71
|
const MOON = { x: 905, y: 70, r: 28 };
|
|
69
72
|
// the museum as the skyline sees it: the marble block with its portico, the atrium behind
|
|
73
|
+
// Where the banks of cloud lie about the city's back corner (dx, dy from it, scale): far
|
|
74
|
+
// and back behind it, near in front. The cloud's shape is city-draw.js's (cloudAt, puffAt).
|
|
75
|
+
const BANKS = {
|
|
76
|
+
far: [[-250, 50, 0.55], [250, 40, 0.55], [0, -60, 0.7]],
|
|
77
|
+
back: [[-200, 130, 0.55], [220, 120, 0.55], [0, 20, 0.5]],
|
|
78
|
+
near: [[-330, 322, 0.45], [215, 336, 0.45], [-60, 392, 0.5]],
|
|
79
|
+
};
|
|
70
80
|
const MUSEUM_SIL = [{ k: 'museum', x0: 4.9, y0: 12.4, x1: 11.1, y1: 13.7, h: 43, portico: true }, { k: 'museum', x0: 5.6, y0: 10.9, x1: 10.4, y1: 12.3, h: 40 }];
|
|
71
81
|
|
|
72
82
|
const r1 = (n) => Math.round(n * 10) / 10;
|
|
73
83
|
const num = (v) => (Number.isFinite(Number(v)) ? Number(v) : 0);
|
|
74
84
|
const sum = (a) => (Array.isArray(a) ? a.reduce((s, v) => s + num(v), 0) : 0);
|
|
75
85
|
|
|
76
|
-
//
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
86
|
+
// now('lit') is the token the hour's blend is written to; mix() is a share of one colour
|
|
87
|
+
// in another (or in nothing: a glaze or a thin line).
|
|
88
|
+
// The banks and the sky gradients never change with the week, and citySvg runs once a
|
|
89
|
+
// frame while the slider glides, so both are worked out once and kept (per scene origin).
|
|
90
|
+
const bankPaths = new Map();
|
|
91
|
+
const bankPath = (Gov, key, at, ox, oy) => {
|
|
92
|
+
const k = key + '|' + ox + '|' + oy;
|
|
93
|
+
if (!bankPaths.has(k)) bankPaths.set(k, at.map((c) => Gov.cloudAt(ox + c[0], oy + c[1], c[2])).join(''));
|
|
94
|
+
return bankPaths.get(k);
|
|
95
|
+
};
|
|
96
|
+
let gradDefs = null;
|
|
97
|
+
const skyGrads = (Gov, node) => {
|
|
98
|
+
if (!(Gov && typeof Gov.skyDefs === 'function')) return [];
|
|
99
|
+
if (!gradDefs) gradDefs = Gov.skyDefs([]);
|
|
100
|
+
return gradDefs.map((g) => node('linearGradient', { id: g.id, x1: 0, y1: 0, x2: 0, y2: 1 }, g.stops.map((st) => node('stop', { offset: st[0], 'stop-color': st[1] }))));
|
|
101
|
+
};
|
|
102
|
+
const now = (role) => 'var(--sky-now-' + role + ')';
|
|
103
|
+
const mix = (a, pct, b) => 'color-mix(in srgb, ' + a + ' ' + pct + '%, ' + (b || 'transparent') + ')';
|
|
104
|
+
// a face that stands in the cloud: the scene's gradient for that side (city-draw.js
|
|
105
|
+
// skyDefs), then the plain face colour for a scene drawn without them
|
|
106
|
+
const FOOT_L = 'url(#sky-face-l) ' + now('lit'), FOOT_R = 'url(#sky-face-r) ' + now('shade');
|
|
107
|
+
const SEA = 'var(--sea)';
|
|
108
|
+
|
|
109
|
+
// The sky's drawing data: the hour's tokens (the labels are words, so they are the hall's ink).
|
|
110
|
+
function skyTheme() {
|
|
111
|
+
const win = now('lamp');
|
|
112
|
+
return { star: win, glow: mix(win, 32), line: mix(win, 32), label: 'var(--ink-soft)', near: now('shade'), far: now('lit'), civic: mix(now('shade'), 70, now('top')), win: mix(win, 88), moon: now('cloud'), shade: now('mid'), streak: mix(win, 92), field: mix(now('line'), 30), beacon: win, outline: win };
|
|
82
113
|
}
|
|
83
114
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
work: { t: '#f6f5f8', l: '#e6e5e9', r: '#d2d1d6', s: 'rgba(23,24,26,0.22)' },
|
|
88
|
-
plinth: { t: '#efeef1', l: '#e2e1e5', r: '#cfced3', s: 'rgba(23,24,26,0.22)' },
|
|
89
|
-
glassL: 'rgba(91,111,208,0.30)', glassR: 'rgba(91,111,208,0.42)', glassT: 'rgba(91,111,208,0.22)',
|
|
90
|
-
floor: 'rgba(23,24,26,0.10)', steel: 'rgba(23,24,26,0.62)', scaffold: 'rgba(23,24,26,0.40)', lit: 'rgba(226,150,90,0.55)',
|
|
91
|
-
slab: { t: '#d9d8dd', l: '#c4c3c9', r: '#b2b1b8', s: 'rgba(23,24,26,0.4)' },
|
|
92
|
-
ground: 'rgba(23,24,26,0.035)', groundLine: 'rgba(23,24,26,0.08)',
|
|
93
|
-
orb: '#d98a4e', orbGlow: 'rgba(217,138,78,0.30)', ideaLine: 'rgba(217,138,78,0.55)',
|
|
94
|
-
av: '#e4e3e7', avAgent: '#d3d8f2', avInk: '#17181a',
|
|
95
|
-
star: '#b8732f',
|
|
96
|
-
marble: { t: '#fbfaf7', l: '#ece9e2', r: '#d8d4cb', s: 'rgba(23,24,26,0.28)' }, granite: { t: '#cfcdd2', l: '#bcbac0', r: '#a9a7ae', s: 'rgba(23,24,26,0.25)' },
|
|
97
|
-
mglass: { t: 'rgba(91,111,208,0.16)', l: 'rgba(91,111,208,0.22)', r: 'rgba(91,111,208,0.3)', s: 'rgba(60,80,180,0.5)' },
|
|
98
|
-
grass: '#c9ddbf', grassLine: 'rgba(40,70,40,0.2)', path: '#ece6da', water: '#a9cbe3', tree: ['#8fb27c', '#7aa36b', '#9dbd89'], col: '#ffffff', dark: 'rgba(23,24,26,0.35)',
|
|
99
|
-
};
|
|
100
|
-
}
|
|
115
|
+
// One palette: the hall is dark only (ADR 0402) and the hour, not a mode, changes it.
|
|
116
|
+
function theme() {
|
|
117
|
+
const roof = now('roof'), lit = now('lit'), shade = now('shade'), line = now('line');
|
|
101
118
|
return {
|
|
102
|
-
work: { t:
|
|
103
|
-
plinth: { t: '
|
|
104
|
-
glassL:
|
|
105
|
-
floor:
|
|
106
|
-
slab: { t:
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
119
|
+
work: { t: roof, l: lit, r: shade, lg: FOOT_L, rg: FOOT_R, s: mix(roof, 40) },
|
|
120
|
+
plinth: { t: mix(roof, 60, now('base')), l: lit, r: shade, lg: FOOT_L, rg: FOOT_R, s: mix(roof, 30) },
|
|
121
|
+
glassL: mix(SEA, 36), glassR: mix(SEA, 26), glassT: mix(SEA, 36),
|
|
122
|
+
floor: mix(roof, 24), steel: mix(line, 90), scaffold: mix(line, 60), lit: mix(now('lamp'), 72),
|
|
123
|
+
slab: { t: roof, l: mix(lit, 70, roof), r: lit, s: mix(line, 40) },
|
|
124
|
+
orbGlow: mix(now('lamp'), 35),
|
|
125
|
+
av: 'var(--bg-card)', avAgent: mix(SEA, 26, 'var(--bg-card)'), avInk: 'var(--ink)',
|
|
126
|
+
star: now('lamp'),
|
|
127
|
+
marble: { t: roof, l: mix(lit, 42, roof), r: mix(shade, 46, roof), s: mix(line, 36) }, granite: { t: mix(roof, 70, lit), l: lit, r: shade, lg: FOOT_L, rg: FOOT_R, s: mix(roof, 30) },
|
|
128
|
+
mglass: { t: mix(SEA, 20), l: mix(SEA, 26), r: mix(SEA, 34), s: mix(SEA, 55) },
|
|
129
|
+
grass: mix(now('cloud-shade'), 34), grassLine: mix(line, 14), path: mix(now('cloud'), 46), water: mix(now('mid'), 46), tree: [mix(lit, 70, now('cloud-shade')), mix(lit, 86, now('cloud-shade')), mix(lit, 55, now('cloud-shade'))], col: roof, dark: mix(shade, 72),
|
|
130
|
+
plaza: mix(now('cloud'), 34), plazaLine: mix(line, 34),
|
|
114
131
|
};
|
|
115
132
|
}
|
|
116
133
|
|
|
@@ -138,11 +155,11 @@
|
|
|
138
155
|
const row = (k) => Array.from({ length: W }, (_, i) => num(p[k] && p[k][i]));
|
|
139
156
|
people[String(p.id)] = { id: String(p.id), login: p.login || '', name: p.name || p.login || 'Builder', avatar: p.avatar_url || null, agent: !!p.agent, build: row('build'), art: row('art'), idea: row('idea'), gov: row('gov'), vote: row('vote') };
|
|
140
157
|
});
|
|
141
|
-
const
|
|
158
|
+
const nowAt = d.now || {};
|
|
142
159
|
const sites = {};
|
|
143
|
-
(Array.isArray(
|
|
160
|
+
(Array.isArray(nowAt.sites) ? nowAt.sites : []).forEach((s) => { if (s && s.goal_id != null && s.builder_id != null) sites[String(s.goal_id)] = { builder: String(s.builder_id), agent: !!s.agent }; });
|
|
144
161
|
const waiting = {};
|
|
145
|
-
(Array.isArray(
|
|
162
|
+
(Array.isArray(nowAt.waiting) ? nowAt.waiting : []).forEach((w) => { if (w && w.goal_id != null && num(w.count) > 0) waiting[String(w.goal_id)] = num(w.count); });
|
|
146
163
|
const ideas = (Array.isArray(d.ideas) ? d.ideas : []).map((x) => ({
|
|
147
164
|
id: String(x.id), week: num(x.week), by: x.by != null ? String(x.by) : null, title: x.title == null ? 'A private idea' : String(x.title),
|
|
148
165
|
goal: x.goal_id != null ? String(x.goal_id) : null,
|
|
@@ -217,7 +234,7 @@
|
|
|
217
234
|
// attribute value or a text node, which is also why this file needs no escaper.
|
|
218
235
|
function citySvg(m, t, opts) {
|
|
219
236
|
const o = opts || {};
|
|
220
|
-
const I = theme(
|
|
237
|
+
const I = theme();
|
|
221
238
|
const Gov = o.gov || null;
|
|
222
239
|
const vb = viewBoxOf(m);
|
|
223
240
|
const i = Math.max(0, Math.min(m.W - 1, Math.floor(t + 1e-6)));
|
|
@@ -229,28 +246,41 @@
|
|
|
229
246
|
const line = (a, b, s, w, dash) => node('line', Object.assign({ x1: r1(a[0]), y1: r1(a[1]), x2: r1(b[0]), y2: r1(b[1]), stroke: s, 'stroke-width': w || 1, 'stroke-linecap': 'round' }, dash ? { 'stroke-dasharray': dash } : {}));
|
|
230
247
|
const circle = (cx, cy, r, attrs) => node('circle', Object.assign({ cx: r1(cx), cy: r1(cy), r }, attrs));
|
|
231
248
|
const box = (x0, y0, x1, y1, z0, h, tn) => {
|
|
232
|
-
|
|
249
|
+
// a box on the ground stands in the cloud: its two seen faces fade into it
|
|
250
|
+
const z1 = z0 + h, inCloud = !(z0 > 0);
|
|
233
251
|
return [
|
|
234
|
-
face([P(x0, y1, z1), P(x1, y1, z1), P(x1, y1, z0), P(x0, y1, z0)], tn.l, tn.s),
|
|
235
|
-
face([P(x1, y1, z1), P(x1, y0, z1), P(x1, y0, z0), P(x1, y1, z0)], tn.r, tn.s),
|
|
252
|
+
face([P(x0, y1, z1), P(x1, y1, z1), P(x1, y1, z0), P(x0, y1, z0)], (inCloud && tn.lg) || tn.l, tn.s),
|
|
253
|
+
face([P(x1, y1, z1), P(x1, y0, z1), P(x1, y0, z0), P(x1, y1, z0)], (inCloud && tn.rg) || tn.r, tn.s),
|
|
236
254
|
face([P(x0, y0, z1), P(x1, y0, z1), P(x1, y1, z1), P(x0, y1, z1)], tn.t, tn.s),
|
|
237
255
|
];
|
|
238
256
|
};
|
|
239
257
|
const quiet = (key) => (o.focus === key ? '' : ' hc-quiet');
|
|
240
258
|
|
|
259
|
+
// No ground: the city stands in cloud (task 1005196). The face gradients and the cloud's
|
|
260
|
+
// shape are the Governor City's own (Gov.skyDefs, Gov.cloudAt, Gov.puffAt), never copied:
|
|
261
|
+
// a scene drawn without it has plain faces and no cloud.
|
|
262
|
+
const cloudy = !!(Gov && typeof Gov.cloudAt === 'function' && typeof Gov.puffAt === 'function');
|
|
263
|
+
const bank = (key, at) => node('path', { d: bankPath(Gov, key, at, vb.OX, vb.OY), class: 'hc-cloud hc-cloud--' + key, filter: 'url(#hc-soft' + (key === 'near' ? '' : 'er') + ')', 'aria-hidden': 'true' });
|
|
264
|
+
const puff = (x, y, r) => { const c = P(x, y, 0); return node('path', { d: Gov.puffAt(c[0], c[1] + 4, r), class: 'hc-cloud hc-cloud--row', filter: 'url(#hc-soft)', 'aria-hidden': 'true' }); };
|
|
265
|
+
const grads = skyGrads(Gov, node);
|
|
266
|
+
// the two filters that soften the cloud (nothing that moves is blurred)
|
|
267
|
+
const soft = (id, blur) => node('filter', { id, x: -0.2, y: -0.8, width: 1.4, height: 2.6 }, [node('feGaussianBlur', { stdDeviation: blur })]);
|
|
241
268
|
const out = [
|
|
242
|
-
node('defs', {}, [node('radialGradient', { id: 'hc-orb' }, [node('stop', { offset: 0, 'stop-color': I.orbGlow }), node('stop', { offset: 1, 'stop-color': 'transparent' })])]),
|
|
243
|
-
face([P(0, 0), P(m.width, 0), P(m.width, m.depth), P(0, m.depth)], I.ground, I.groundLine),
|
|
269
|
+
node('defs', {}, [node('radialGradient', { id: 'hc-orb' }, [node('stop', { offset: 0, 'stop-color': I.orbGlow }), node('stop', { offset: 1, 'stop-color': 'transparent' })]), soft('hc-soft', 7), soft('hc-softer', 12)].concat(grads)),
|
|
244
270
|
];
|
|
271
|
+
if (cloudy) out.push(bank('far', BANKS.far), bank('back', BANKS.back));
|
|
245
272
|
|
|
246
273
|
// the ideas: a thin band of stars high above the city, apart from it — one door to the sky
|
|
247
274
|
const seen = m.ideas.filter((x) => x.week <= i);
|
|
248
275
|
const fresh = m.ideas.filter((x) => x.week === i).length;
|
|
249
|
-
|
|
276
|
+
// the stars sit in one group the sheet shows at the hour's star strength (out at night,
|
|
277
|
+
// gone by day); the door under them is there at every hour
|
|
278
|
+
const stars = [];
|
|
250
279
|
seen.forEach((x) => {
|
|
251
280
|
const h = hash(x.id), recent = i - x.week <= 1;
|
|
252
|
-
|
|
281
|
+
stars.push(circle(80 + (h % 1000) / 1000 * 840, 14 + (Math.floor(h / 1000) % 1000) / 1000 * (SKY_H - 34), recent ? 1.7 : 1.1, Object.assign({ fill: I.star, opacity: recent ? 0.75 : 0.28 }, x.week === i ? { class: 'hc-twinkle' } : {})));
|
|
253
282
|
});
|
|
283
|
+
const band = [node('rect', { x: 60, y: 8, width: 880, height: SKY_H - 16, fill: 'transparent' }), node('g', { class: 'hc-stars' }, stars)];
|
|
254
284
|
out.push(node('a', { href: '/thinking', class: 'hc-door hc-sky', 'aria-label': `The ideas: ${fresh} new this week. Open the sky.`, 'data-tip': 'Ideas', 'data-tip-body': `${fresh} new this week. Click to look up at the sky.` }, band));
|
|
255
285
|
|
|
256
286
|
// every building on the ground, back to front; the civic core draws as one district
|
|
@@ -306,7 +336,11 @@
|
|
|
306
336
|
const shipped = Math.round(d.build + d.art), byArt = Math.round(d.art);
|
|
307
337
|
const tip = `${shipped} shipped${byArt ? ` · ${byArt} by artists` : ''}${who ? ` · ${agent ? `${who.name}'s agent` : who.name} on site` : ''} · click to open the goal`;
|
|
308
338
|
out.push(node('a', { href: `/goals#/goal/${encodeURIComponent(a.id)}`, class: 'hc-tower', 'aria-label': `${a.title}: ${shipped} shipped. Open the goal.`, 'data-tip': a.title, 'data-tip-body': tip }, g));
|
|
339
|
+
// the cloud at its foot, over this tower and under the next one forward
|
|
340
|
+
if (cloudy) out.push(puff(x1 - 0.5, y1 - 0.5, 62));
|
|
309
341
|
});
|
|
342
|
+
// the near banks, either side of the garden and under the front corner
|
|
343
|
+
if (cloudy) out.push(bank('near', BANKS.near));
|
|
310
344
|
|
|
311
345
|
over.forEach((v, n) => {
|
|
312
346
|
if (v.k === 'face') { out.push(avatarNode(v.p, v.who, v.agent, v.a, I, n, node, line, circle)); return; }
|
|
@@ -321,9 +355,9 @@
|
|
|
321
355
|
// The government district: the plaza and the nine civic buildings, drawn by
|
|
322
356
|
// city-draw.js's own recipes in its own palette — one hover, one door, to the street.
|
|
323
357
|
function coreNode() {
|
|
324
|
-
const CI = Gov.isoTheme(
|
|
325
|
-
const k = Gov.isoKit(TW, TH, vb.OX, vb.OY, CIVIC_S, CI,
|
|
326
|
-
const kids = [face([P(CORE.x0, CORE.y0), P(CORE.x1, CORE.y0), P(CORE.x1, CORE.y1), P(CORE.x0, CORE.y1)],
|
|
358
|
+
const CI = Gov.isoTheme();
|
|
359
|
+
const k = Gov.isoKit(TW, TH, vb.OX, vb.OY, CIVIC_S, CI, true);
|
|
360
|
+
const kids = [face([P(CORE.x0, CORE.y0), P(CORE.x1, CORE.y0), P(CORE.x1, CORE.y1), P(CORE.x0, CORE.y1)], I.plaza, I.plazaLine)];
|
|
327
361
|
Gov.CIVIC_SLOTS.slice().sort((p, q) => (p[1] + p[2]) - (q[1] + q[2])).forEach((sl) => {
|
|
328
362
|
const list = [];
|
|
329
363
|
Gov.isoInstitution(list, k, sl[0], sl[1] - 0.6, sl[2] - 0.6, {});
|
|
@@ -424,7 +458,7 @@
|
|
|
424
458
|
// The sky for week t as shapes (citySvg's contract: a tree of plain nodes, never markup).
|
|
425
459
|
function skySvg(m, t, opts) {
|
|
426
460
|
const o = opts || {};
|
|
427
|
-
const C = skyTheme(
|
|
461
|
+
const C = skyTheme();
|
|
428
462
|
const Gov = o.gov || null;
|
|
429
463
|
const i = Math.max(0, Math.min(m.W - 1, Math.floor(t + 1e-6)));
|
|
430
464
|
const latest = t >= m.W - 1 - 1e-3;
|
|
@@ -1,14 +1,36 @@
|
|
|
1
1
|
/* modules/hall-ui/public/home-city.css — Home's project city (task 1005054; v16, task 1005058).
|
|
2
2
|
The scene card, the ladder of builders beside it and the time slider under it
|
|
3
3
|
(home-city.js; record modules/hall-ui/records/home-city.md). Every colour is a
|
|
4
|
-
hall token or a mix of one; the tower faces are
|
|
5
|
-
home-city-draw.js. One sky for both the city and the ladder, so the two read
|
|
4
|
+
hall token or a mix of one; the tower faces are the hour's sky tokens, named
|
|
5
|
+
in home-city-draw.js. One sky for both the city and the ladder, so the two read
|
|
6
6
|
as one scene. No :root here; motion is CSS and the hall's reduced-motion rule (style.css, `prefers-reduced-motion: reduce`)
|
|
7
7
|
stops it. */
|
|
8
8
|
|
|
9
9
|
.home-city { padding: 0; overflow: hidden; background: linear-gradient(var(--bg-card), var(--bg)); }
|
|
10
10
|
.hc-stage { display: flex; align-items: center; gap: 4px; }
|
|
11
11
|
.hc-svg { display: block; flex: 1; min-width: 0; height: auto; }
|
|
12
|
+
/* THE CITY IN THE CLOUDS, AND THE HOUR (task 1005196; ADR 0402). The sky is the hour's
|
|
13
|
+
(--sky-now-*, set by sky-time.js; night at rest) and it is art. It runs edge to edge and
|
|
14
|
+
nothing darkens it: the far sky above, and the light from below behind the city (the
|
|
15
|
+
scene's own glow, so it sits under the city at any width). With the bars up the sky fills
|
|
16
|
+
the city's panel; in game mode it is the ground of the whole Home view, behind the visor,
|
|
17
|
+
and the panel is clear. What you read or press on it stands on a plate of the night
|
|
18
|
+
(--night-plate): the ladder, and in game mode the greeting; the slider keeps its own strip. */
|
|
19
|
+
.hc-stage { background: linear-gradient(to bottom, var(--sky-now-top), var(--sky-now-mid) 46%, var(--sky-now-haze)); }
|
|
20
|
+
.hc-svg { background: radial-gradient(ellipse closest-side at 46% 62%, var(--sky-now-cloud), var(--sky-now-base) 30%, var(--sky-now-haze) 62%, transparent); }
|
|
21
|
+
.hc-svg .hc-stars { opacity: var(--sky-now-stars); }
|
|
22
|
+
/* the ground is the hall's own plate seam (style.css body::before: fixed, the whole view, under the page), with no veil over it */
|
|
23
|
+
html[data-game="on"] body[data-page="home"] { --plate: linear-gradient(to bottom, var(--sky-now-top), var(--sky-now-mid) 46%, var(--sky-now-haze)); --plate-veil: none; --plate-blend: normal; }
|
|
24
|
+
html[data-game="on"] body[data-page="home"] .home-city, html[data-game="on"] body[data-page="home"] .hc-stage { background: none; }
|
|
25
|
+
html[data-game="on"] body[data-page="home"] .page-head--hall .page-head__h { width: fit-content; padding: var(--ds-space-hair) var(--ds-space-xs); background: var(--night-plate); clip-path: var(--cut-path-sm); }
|
|
26
|
+
/* the ladder's plate: the night between two strong hairlines, sized to the rungs */
|
|
27
|
+
.hc-ladder { isolation: isolate; }
|
|
28
|
+
.hc-ladder::before { content: ""; position: absolute; inset: calc(-1 * var(--ds-space-xs)) calc(-1 * var(--ds-space-sm)); z-index: -1; background: var(--night-plate); border: 0 solid var(--rule); border-left-width: var(--line-strong); border-right-width: var(--line-strong); }
|
|
29
|
+
.hc-cloud { stroke: none; pointer-events: none; }
|
|
30
|
+
.hc-cloud--row { fill: var(--sky-now-cloud); opacity: .5; }
|
|
31
|
+
.hc-cloud--far { fill: color-mix(in srgb, var(--sky-now-mid) 62%, var(--sky-now-cloud-shade)); opacity: .6; }
|
|
32
|
+
.hc-cloud--back { fill: var(--sky-now-cloud); opacity: .8; }
|
|
33
|
+
.hc-cloud--near { fill: var(--sky-now-cloud); opacity: .95; }
|
|
12
34
|
.hc-svg .hc-wait__n { font: 700 11px var(--font-display); fill: var(--accent-on); }
|
|
13
35
|
.hc-svg .hc-av__i { font: 600 13px var(--font-display); }
|
|
14
36
|
.hc-svg [data-tip] { cursor: default; }
|
|
@@ -18,7 +40,7 @@
|
|
|
18
40
|
.hc-svg .hc-tower:hover .hc-face { filter: brightness(1.3); }
|
|
19
41
|
/* the core and the museum stay quiet on the builder's Home so the new buildings lead;
|
|
20
42
|
each comes back to full colour under the pointer or the keyboard */
|
|
21
|
-
.hc-svg .hc-quiet { opacity: .
|
|
43
|
+
.hc-svg .hc-quiet { opacity: .62; filter: saturate(.3); transition: opacity .3s, filter .3s; }
|
|
22
44
|
.hc-svg .hc-quiet:hover, .hc-svg .hc-quiet:focus-visible { opacity: .95; filter: none; }
|
|
23
45
|
.hc-svg .hc-core:hover .hc-face, .hc-svg .hc-museum:hover .hc-face { filter: brightness(1.15); }
|
|
24
46
|
.hc-svg .hc-sky:hover circle, .hc-svg .hc-sky:focus-visible circle { opacity: 1; }
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<link rel="icon" href="/modules/ui-design/public/brand/favicon.svg" type="image/svg+xml">
|
|
9
9
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
10
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
|
-
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-
|
|
11
|
+
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-helm4d">
|
|
12
12
|
<!-- The record archetype, shared with task.html (task 1003305). idea.css below
|
|
13
13
|
carries only what an idea record has and a task record does not. -->
|
|
14
14
|
<link rel="stylesheet" href="/builders/record.css">
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
<link rel="icon" href="/modules/ui-design/public/brand/favicon.svg" type="image/svg+xml">
|
|
13
13
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
14
14
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
15
|
-
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-
|
|
15
|
+
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-helm4d">
|
|
16
16
|
<link rel="stylesheet" href="/builders/ideas.css">
|
|
17
17
|
</head>
|
|
18
18
|
<body data-page="ideas" data-page-title="Ideas">
|
|
@@ -18,12 +18,12 @@
|
|
|
18
18
|
<link rel="icon" href="/modules/ui-design/public/brand/favicon.svg" type="image/svg+xml">
|
|
19
19
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
20
20
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
21
|
-
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-
|
|
22
|
-
<link rel="stylesheet" href="/builders/visor.css?v=2026-11-11-
|
|
21
|
+
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-helm4d">
|
|
22
|
+
<link rel="stylesheet" href="/builders/visor.css?v=2026-11-11-helm4c">
|
|
23
23
|
<link rel="stylesheet" href="/builders/welcome-boot.css?v=2026-11-07-brand-mark">
|
|
24
24
|
<link rel="stylesheet" href="/builders/shell-game.css?v=2026-11-11-view2">
|
|
25
25
|
<link rel="stylesheet" href="/builders/hall-ask.css">
|
|
26
|
-
<link rel="stylesheet" href="/builders/home-city.css?v=2026-11-11-
|
|
26
|
+
<link rel="stylesheet" href="/builders/home-city.css?v=2026-11-11-helm4c">
|
|
27
27
|
<link rel="stylesheet" href="/builders/home-gallery.css">
|
|
28
28
|
<link rel="stylesheet" href="/builders/home-idea-box.css">
|
|
29
29
|
</head>
|
|
@@ -136,7 +136,9 @@
|
|
|
136
136
|
<!-- task 1005054: the project city — the drawing (pure) and the widget — in the
|
|
137
137
|
home-stats zone; the Goals card (goals.js) left Home with it. -->
|
|
138
138
|
<script src="/builders/city-draw.js" defer></script>
|
|
139
|
-
|
|
139
|
+
<!-- task 1005196: the hour of the city's sky (sets the --sky-now-* tokens the city spends) -->
|
|
140
|
+
<script src="/builders/sky-time.js?v=2026-11-11-helm4" defer></script>
|
|
141
|
+
<script src="/builders/home-city-draw.js?v=2026-11-11-helm4d" defer></script>
|
|
140
142
|
<script src="/builders/home-gallery.js" defer></script>
|
|
141
143
|
<script src="/builders/home-idea-box.js" defer></script>
|
|
142
144
|
<script src="/builders/home-city.js?v=2026-11-10-visor" defer></script>
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<link rel="icon" href="/modules/ui-design/public/brand/favicon.svg" type="image/svg+xml">
|
|
9
9
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
10
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
|
-
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-
|
|
11
|
+
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-helm4d">
|
|
12
12
|
<link rel="stylesheet" href="/builders/market-watch.css">
|
|
13
13
|
</head>
|
|
14
14
|
<body data-page="market-watch-item" data-page-title="Market Watch">
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<link rel="icon" href="/modules/ui-design/public/brand/favicon.svg" type="image/svg+xml">
|
|
9
9
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
10
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
|
-
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-
|
|
11
|
+
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-helm4d">
|
|
12
12
|
<link rel="stylesheet" href="/builders/hall-ask.css">
|
|
13
13
|
<link rel="stylesheet" href="/builders/market-watch-rules.css">
|
|
14
14
|
</head>
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<link rel="icon" href="/modules/ui-design/public/brand/favicon.svg" type="image/svg+xml">
|
|
9
9
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
10
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
|
-
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-
|
|
11
|
+
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-helm4d">
|
|
12
12
|
<link rel="stylesheet" href="/builders/market-watch.css">
|
|
13
13
|
<link rel="stylesheet" href="/builders/market-watch-settings.css">
|
|
14
14
|
</head>
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<link rel="icon" href="/modules/ui-design/public/brand/favicon.svg" type="image/svg+xml">
|
|
9
9
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
10
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
|
-
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-
|
|
11
|
+
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-helm4d">
|
|
12
12
|
<!-- task 1004366: a store version's how-to reads as a document, so it borrows the
|
|
13
13
|
reading room's article card (room.css is scoped to its own primer- classes). -->
|
|
14
14
|
<link rel="stylesheet" href="/builders/room.css">
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<link rel="icon" href="/modules/ui-design/public/brand/favicon.svg" type="image/svg+xml">
|
|
9
9
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
10
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
|
-
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-
|
|
11
|
+
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-helm4d">
|
|
12
12
|
<link rel="stylesheet" href="/builders/oversight.css">
|
|
13
13
|
<link rel="stylesheet" href="/builders/project-settings.css?v=2026-11-02-outflow">
|
|
14
14
|
</head>
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<link rel="icon" href="/modules/ui-design/public/brand/favicon.svg" type="image/svg+xml">
|
|
9
9
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
10
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
|
-
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-
|
|
11
|
+
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-helm4d">
|
|
12
12
|
<!-- The oversight family's archetype: a titled row with facts and actions, the
|
|
13
13
|
group head and the foot line (records/oversight-family.md). This page's
|
|
14
14
|
repeated thing is that row at the desk's one-line density. -->
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<link rel="icon" href="/modules/ui-design/public/brand/favicon.svg" type="image/svg+xml">
|
|
9
9
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
10
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
|
-
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-
|
|
11
|
+
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-helm4d">
|
|
12
12
|
<link rel="stylesheet" href="/builders/room.css">
|
|
13
13
|
<link rel="stylesheet" href="/builders/primer.css?v=2026-07-02-shell1">
|
|
14
14
|
<link rel="stylesheet" href="/builders/diagram-viewer.css?v=2026-11-04-reading-room">
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
<link rel="icon" href="/modules/ui-design/public/brand/favicon.svg" type="image/svg+xml">
|
|
15
15
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
16
16
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
17
|
-
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-
|
|
17
|
+
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-helm4d">
|
|
18
18
|
<!-- The PANEL archetype (task 1003308) before the page's own sheet. -->
|
|
19
19
|
<link rel="stylesheet" href="/builders/panel.css">
|
|
20
20
|
<link rel="stylesheet" href="/builders/hall-ask.css">
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<link rel="icon" href="/modules/ui-design/public/brand/favicon.svg" type="image/svg+xml">
|
|
9
9
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
10
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
|
-
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-
|
|
11
|
+
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-helm4d">
|
|
12
12
|
<link rel="stylesheet" href="/builders/oversight.css">
|
|
13
13
|
<link rel="stylesheet" href="/builders/project-settings.css?v=2026-11-02-outflow">
|
|
14
14
|
</head>
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<link rel="icon" href="/modules/ui-design/public/brand/favicon.svg" type="image/svg+xml">
|
|
9
9
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
10
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
|
-
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-
|
|
11
|
+
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-helm4d">
|
|
12
12
|
<!-- task 1003441: the identity cell (avatar, name, login). It was shared with
|
|
13
13
|
the cross-project /people page until task 1003444 deleted it. -->
|
|
14
14
|
<link rel="stylesheet" href="/builders/roster.css">
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
<link rel="icon" href="/modules/ui-design/public/brand/favicon.svg" type="image/svg+xml">
|
|
12
12
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
13
13
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
14
|
-
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-
|
|
14
|
+
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-helm4d">
|
|
15
15
|
<!-- The PANEL archetype (task 1003308): the row, the switch, the field, the
|
|
16
16
|
chip control and the family's voices, shared with profile and pair.
|
|
17
17
|
settings.css then holds only what this page
|