@bongos/core 1.24.18 → 1.24.20
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 +21 -21
- package/docs/copy-inventory.md +27 -21
- package/docs/copy-registry.json +86 -22
- package/docs/module-api-changelog.md +4 -0
- package/docs/page-readings.json +81 -79
- package/modules/ai-studio/studio.js +1 -1
- package/modules/hall-ui/public/ai-studio-lib.js +74 -9
- package/modules/hall-ui/public/ai-studio.css +12 -0
- package/modules/hall-ui/public/ai-studio.js +37 -1
- package/modules/hall-ui/public/roster.css +43 -0
- package/modules/hall-ui/records/builders-roster.md +9 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +16 -0
- package/src/module-api.js +1 -1
- package/tests/hall_ai_studio.mjs +44 -1
- package/tests/hall_roster_world.mjs +10 -0
|
@@ -3292,5 +3292,9 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
3292
3292
|
landed since 1.24.16 with no explicit bump. run 41129472650. (task 1002620)
|
|
3293
3293
|
1.24.18 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
3294
3294
|
landed since 1.24.17 with no explicit bump. run 41131020363. (task 1002620)
|
|
3295
|
+
1.24.19 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
3296
|
+
landed since 1.24.18 with no explicit bump. run 41137645458. (task 1002620)
|
|
3297
|
+
1.24.20 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
3298
|
+
landed since 1.24.19 with no explicit bump. run 41141610027. (task 1002620)
|
|
3295
3299
|
---------------------------------------------------------------------------
|
|
3296
3300
|
```
|
package/docs/page-readings.json
CHANGED
|
@@ -5,16 +5,16 @@
|
|
|
5
5
|
"adr": "0341 D3",
|
|
6
6
|
"reread": "node scripts/bongos/page-reader.js --stale",
|
|
7
7
|
"how": ["Generated by node scripts/bongos/page-reader.js (BV2.TW04, task 1004315; ADR 0341 D3). Do not hand-edit.","One entry per page of docs/page-inventory.json. Lines are in page order: the default state first, and a line only another state shows sits where that state shows it, with its state named.","placement: placed = a docs/copy-registry.json row renders it (file, line, string_id); shared = shell text every page of the surface carries (top bar, sidebar, footer), with its row when the registry has one; unplaced = the registry cannot place it (a rewrite becomes an engineer task, ADR 0341 D4).","text keeps {…} where the registry row has a hole, or where a value the page read from its API was filled in. A string that is only such data is counted under omitted.data, not listed.","reading_hash is over the non-shared lines (key, section, text); files_hash is over the page's inventory files. --check compares files_hash only and never opens a browser.","Rendered through the hall-preview harness (hall) and the ui-design kit stub (landing, status), at 1280x800 with the clock pinned, so a reading is the fixture world's page."],
|
|
8
|
-
"counts": {"pages":52,"lines":
|
|
8
|
+
"counts": {"pages":52,"lines":5614,"placed":1753,"shared":461,"unplaced":3400,"omitted_data":3766},
|
|
9
9
|
"pages": [
|
|
10
10
|
{
|
|
11
11
|
"id": "builders:ai-studio",
|
|
12
12
|
"surface": "builders",
|
|
13
13
|
"title": "Studio",
|
|
14
14
|
"states_read": ["pick","describe","make","waiting","result","result-own","failed","balance","balance-all","out"],
|
|
15
|
-
"files_hash": "
|
|
16
|
-
"reading_hash": "
|
|
17
|
-
"counts": {"lines":
|
|
15
|
+
"files_hash": "f90837ff3546b240",
|
|
16
|
+
"reading_hash": "495f0ef9f7d7a1b7",
|
|
17
|
+
"counts": {"lines":104,"placed":38,"shared":8,"unplaced":58},
|
|
18
18
|
"omitted": {"data":15},
|
|
19
19
|
"notes": [],
|
|
20
20
|
"lines": [
|
|
@@ -28,13 +28,13 @@
|
|
|
28
28
|
{"key":"L0008","section":"top bar","text":"Ideating","placement":"shared"},
|
|
29
29
|
{"key":"L0009","section":"page top","text":"← Studio","placement":"placed","file":"modules/hall-ui/public/ai-studio.js","line":122,"string_id":"a857d79bc0df"},
|
|
30
30
|
{"key":"L0010","section":"{…} left","text":"left","placement":"placed","file":"modules/hall-ui/public/market-watch.js","line":73,"string_id":"92b79edf21f6","state":"balance"},
|
|
31
|
-
{"key":"L0011","section":"{…} left","text":"Add how much?","placement":"placed","file":"modules/hall-ui/public/ai-studio.js","line":
|
|
31
|
+
{"key":"L0011","section":"{…} left","text":"Add how much?","placement":"placed","file":"modules/hall-ui/public/ai-studio.js","line":563,"string_id":"cb46cfb66dfd","state":"balance"},
|
|
32
32
|
{"key":"L0012","section":"{…} left","text":"other","placement":"unplaced","state":"balance"},
|
|
33
|
-
{"key":"L0013","section":"{…} left","text":"Add {…}","placement":"placed","file":"modules/hall-ui/public/ai-studio.js","line":
|
|
34
|
-
{"key":"L0014","section":"{…} left","text":"{…} lands in your balance; your card is charged {…}.","placement":"placed","file":"modules/hall-ui/public/ai-studio.js","line":
|
|
33
|
+
{"key":"L0013","section":"{…} left","text":"Add {…}","placement":"placed","file":"modules/hall-ui/public/ai-studio.js","line":567,"string_id":"e4da002ae135","state":"balance"},
|
|
34
|
+
{"key":"L0014","section":"{…} left","text":"{…} lands in your balance; your card is charged {…}.","placement":"placed","file":"modules/hall-ui/public/ai-studio.js","line":615,"string_id":"5ad81ff61920","state":"balance"},
|
|
35
35
|
{"key":"L0015","section":"{…} left","text":"Test mode: no real money moves.","placement":"unplaced","state":"balance"},
|
|
36
36
|
{"key":"L0016","section":"{…} left","text":"September","placement":"unplaced","state":"balance"},
|
|
37
|
-
{"key":"L0017","section":"{…} left","text":"Nothing yet this month.","placement":"placed","file":"modules/hall-ui/public/ai-studio.js","line":
|
|
37
|
+
{"key":"L0017","section":"{…} left","text":"Nothing yet this month.","placement":"placed","file":"modules/hall-ui/public/ai-studio.js","line":573,"string_id":"8d0e0cbaa5ff","state":"balance"},
|
|
38
38
|
{"key":"L0018","section":"{…} left","text":"Show this month only","placement":"unplaced","state":"balance-all"},
|
|
39
39
|
{"key":"L0019","section":"{…} left","text":"Turn the sketch into a finished hero pi…","placement":"unplaced","state":"balance-all","occurrences":3},
|
|
40
40
|
{"key":"L0020","section":"{…} left","text":"set aside while it ran","placement":"unplaced","state":"balance-all","occurrences":3},
|
|
@@ -51,75 +51,77 @@
|
|
|
51
51
|
{"key":"L0031","section":"{…} left","text":"Builders hall · this session","placement":"placed","file":"modules/hall-ui/public/craft-mode.js","line":670,"string_id":"fd1903586e8e","state":"balance"},
|
|
52
52
|
{"key":"L0032","section":"page top","text":"No picture this time.","placement":"unplaced","state":"failed"},
|
|
53
53
|
{"key":"L0033","section":"page top","text":"Save picture","placement":"unplaced","state":"result"},
|
|
54
|
-
{"key":"L0034","section":"page top","text":"
|
|
55
|
-
{"key":"L0035","section":"page top","text":"
|
|
56
|
-
{"key":"L0036","section":"page top","text":"
|
|
57
|
-
{"key":"L0037","section":"page top","text":"
|
|
58
|
-
{"key":"L0038","section":"page top","text":"
|
|
59
|
-
{"key":"L0039","section":"page top","text":"
|
|
60
|
-
{"key":"L0040","section":"page top","text":"
|
|
61
|
-
{"key":"L0041","section":"page top","text":"
|
|
62
|
-
{"key":"L0042","section":"page top","text":"
|
|
63
|
-
{"key":"L0043","section":"page top","text":"
|
|
64
|
-
{"key":"L0044","section":"page top","text":"
|
|
65
|
-
{"key":"L0045","section":"page top","text":"
|
|
66
|
-
{"key":"L0046","section":"page top","text":"
|
|
67
|
-
{"key":"L0047","section":"page top","text":"
|
|
68
|
-
{"key":"L0048","section":"page top","text":"
|
|
69
|
-
{"key":"L0049","section":"page top","text":"
|
|
70
|
-
{"key":"L0050","section":"page top","text":"
|
|
71
|
-
{"key":"L0051","section":"page top","text":"
|
|
72
|
-
{"key":"L0052","section":"
|
|
73
|
-
{"key":"L0053","section":"
|
|
74
|
-
{"key":"L0054","section":"{…} so far","text":"
|
|
75
|
-
{"key":"L0055","section":"{…} so far","text":"
|
|
76
|
-
{"key":"L0056","section":"{…} so far","text":"
|
|
77
|
-
{"key":"L0057","section":"{…} so far","text":"
|
|
78
|
-
{"key":"L0058","section":"
|
|
79
|
-
{"key":"L0059","section":"
|
|
80
|
-
{"key":"L0060","section":"page top","text":"1 Pick","placement":"unplaced"},
|
|
81
|
-
{"key":"L0061","section":"page top","text":"2 Describe","placement":"unplaced"},
|
|
82
|
-
{"key":"L0062","section":"page top","text":"
|
|
83
|
-
{"key":"L0063","section":"
|
|
84
|
-
{"key":"L0064","section":"
|
|
85
|
-
{"key":"L0065","section":"How do you want to pay?","text":"
|
|
86
|
-
{"key":"L0066","section":"How do you want to pay?","text":"
|
|
87
|
-
{"key":"L0067","section":"How do you want to pay?","text":"
|
|
88
|
-
{"key":"L0068","section":"How do you want to pay?","text":"
|
|
89
|
-
{"key":"L0069","section":"How do you want to pay?","text":"
|
|
90
|
-
{"key":"L0070","section":"How do you want to pay?","text":"
|
|
91
|
-
{"key":"L0071","section":"How do you want to pay?","text":"
|
|
92
|
-
{"key":"L0072","section":"How do you want to pay?","text":"
|
|
93
|
-
{"key":"L0073","section":"How do you want to pay?","text":"
|
|
94
|
-
{"key":"L0074","section":"How do you want to pay?","text":"
|
|
95
|
-
{"key":"L0075","section":"
|
|
96
|
-
{"key":"L0076","section":"
|
|
97
|
-
{"key":"L0077","section":"What should it make?","text":"
|
|
98
|
-
{"key":"L0078","section":"What should it make?","text":"
|
|
99
|
-
{"key":"L0079","section":"What should it make?","text":"
|
|
100
|
-
{"key":"L0080","section":"What should it make?","text":"
|
|
101
|
-
{"key":"L0081","section":"What
|
|
102
|
-
{"key":"L0082","section":"What
|
|
103
|
-
{"key":"L0083","section":"What are you starting from?","text":"
|
|
104
|
-
{"key":"L0084","section":"What are you starting from?","text":"or","placement":"
|
|
105
|
-
{"key":"L0085","section":"What are you starting from?","text":"
|
|
106
|
-
{"key":"L0086","section":"What are you starting from?","text":"
|
|
107
|
-
{"key":"L0087","section":"What are you starting from?","text":"
|
|
108
|
-
{"key":"L0088","section":"What are you starting from?","text":"
|
|
109
|
-
{"key":"L0089","section":"What are you starting from?","text":"
|
|
110
|
-
{"key":"L0090","section":"What are you starting from?","text":"
|
|
111
|
-
{"key":"L0091","section":"What are you starting from?","text":"
|
|
112
|
-
{"key":"L0092","section":"What are you starting from?","text":"
|
|
113
|
-
{"key":"L0093","section":"What are you starting from?","text":"3
|
|
114
|
-
{"key":"L0094","section":"What are you starting from?","text":"
|
|
115
|
-
{"key":"L0095","section":"What are you
|
|
116
|
-
{"key":"L0096","section":"What are you
|
|
117
|
-
{"key":"L0097","section":"What are you doing now?","text":"
|
|
118
|
-
{"key":"L0098","section":"What are you doing now?","text":"
|
|
119
|
-
{"key":"L0099","section":"What are you doing now?","text":"
|
|
120
|
-
{"key":"L0100","section":"What are you doing now?","text":"
|
|
121
|
-
{"key":"L0101","section":"What are you doing now?","text":"
|
|
122
|
-
{"key":"L0102","section":"What are you doing now?","text":"
|
|
54
|
+
{"key":"L0034","section":"page top","text":"This cost about $0.0640 on your Gemini key.","placement":"unplaced","state":"result-own"},
|
|
55
|
+
{"key":"L0035","section":"page top","text":"This cost $0.0421, taken from your balance.","placement":"unplaced","state":"result"},
|
|
56
|
+
{"key":"L0036","section":"page top","text":"{…} and {…}","placement":"placed","file":"modules/hall-ui/public/profile-nudge.js","line":77,"string_id":"56b00d773232","state":"result","occurrences":4},
|
|
57
|
+
{"key":"L0037","section":"page top","text":"lit it from the lamp","placement":"unplaced","state":"result"},
|
|
58
|
+
{"key":"L0038","section":"page top","text":"If you want it closer to the landing page's salmon, ask for","placement":"unplaced","state":"result"},
|
|
59
|
+
{"key":"L0039","section":"page top","text":"\"warmer lamp, pinker glow\"","placement":"unplaced","state":"result"},
|
|
60
|
+
{"key":"L0040","section":"page top","text":"Your request","placement":"placed","file":"modules/hall-ui/public/ai-studio.js","line":514,"string_id":"573a5581aa7a","state":"result"},
|
|
61
|
+
{"key":"L0041","section":"page top","text":"Make it again","placement":"placed","file":"modules/hall-ui/public/ai-studio.js","line":514,"string_id":"d535454fac6d","state":"result"},
|
|
62
|
+
{"key":"L0042","section":"page top","text":"Change files","placement":"placed","file":"modules/hall-ui/public/ai-studio.js","line":514,"string_id":"f5a83e058206","state":"result"},
|
|
63
|
+
{"key":"L0043","section":"page top","text":"Start something new","placement":"placed","file":"modules/hall-ui/public/ai-studio.js","line":514,"string_id":"45e2495c0dbd","state":"result"},
|
|
64
|
+
{"key":"L0044","section":"page top","text":"Paid with","placement":"unplaced","state":"result"},
|
|
65
|
+
{"key":"L0045","section":"page top","text":"your own Gemini key","placement":"unplaced","state":"result-own"},
|
|
66
|
+
{"key":"L0046","section":"page top","text":"Cost","placement":"unplaced","state":"result-own"},
|
|
67
|
+
{"key":"L0047","section":"page top","text":"about $0.0640","placement":"unplaced","state":"result-own"},
|
|
68
|
+
{"key":"L0048","section":"page top","text":"Google doesn't tell us the exact price on your own key, so this is an estimate. Your Google bill has the real figure. We charged nothing.","placement":"unplaced","state":"result-own"},
|
|
69
|
+
{"key":"L0049","section":"page top","text":"your balance","placement":"unplaced","state":"result"},
|
|
70
|
+
{"key":"L0050","section":"page top","text":"OpenRouter","placement":"unplaced","state":"result"},
|
|
71
|
+
{"key":"L0051","section":"page top","text":"Our 8%","placement":"unplaced","state":"result"},
|
|
72
|
+
{"key":"L0052","section":"page top","text":"You paid","placement":"unplaced","state":"result"},
|
|
73
|
+
{"key":"L0053","section":"page top","text":"Builders hall · this session","placement":"placed","file":"modules/hall-ui/public/craft-mode.js","line":670,"string_id":"fd1903586e8e","state":"result"},
|
|
74
|
+
{"key":"L0054","section":"{…} so far","text":"usually done in about a minute","placement":"placed","file":"modules/hall-ui/public/ai-studio.js","line":473,"string_id":"f26117caa2f1","state":"waiting"},
|
|
75
|
+
{"key":"L0055","section":"{…} so far","text":"Read your 3 files","placement":"unplaced","state":"waiting"},
|
|
76
|
+
{"key":"L0056","section":"{…} so far","text":"Wrote the answer","placement":"unplaced","state":"waiting"},
|
|
77
|
+
{"key":"L0057","section":"{…} so far","text":"Drawing the pictures","placement":"unplaced","state":"waiting"},
|
|
78
|
+
{"key":"L0058","section":"{…} so far","text":"The lamp stays on until it's done. You can close this page; the result waits in your studio.","placement":"placed","file":"modules/hall-ui/public/ai-studio.js","line":473,"string_id":"5a2220cd0d71","state":"waiting"},
|
|
79
|
+
{"key":"L0059","section":"{…} so far","text":"Builders hall · this session","placement":"placed","file":"modules/hall-ui/public/craft-mode.js","line":670,"string_id":"fd1903586e8e","state":"waiting"},
|
|
80
|
+
{"key":"L0060","section":"page top","text":"1 Pick ✓","placement":"unplaced","state":"describe"},
|
|
81
|
+
{"key":"L0061","section":"page top","text":"2 Describe ✓","placement":"unplaced","state":"make"},
|
|
82
|
+
{"key":"L0062","section":"page top","text":"1 Pick","placement":"unplaced"},
|
|
83
|
+
{"key":"L0063","section":"page top","text":"2 Describe","placement":"unplaced"},
|
|
84
|
+
{"key":"L0064","section":"page top","text":"3 Make","placement":"unplaced"},
|
|
85
|
+
{"key":"L0065","section":"How do you want to pay?","text":"How do you want to pay?","placement":"placed","file":"modules/hall-ui/public/ai-studio.js","line":351,"string_id":"5c442fe0f174","state":"make"},
|
|
86
|
+
{"key":"L0066","section":"How do you want to pay?","text":"PDF","placement":"unplaced","state":"make"},
|
|
87
|
+
{"key":"L0067","section":"How do you want to pay?","text":"“Turn the sketch into a finished hero picture for the landing pa…”","placement":"unplaced","state":"make"},
|
|
88
|
+
{"key":"L0068","section":"How do you want to pay?","text":"change","placement":"unplaced","state":"make"},
|
|
89
|
+
{"key":"L0069","section":"How do you want to pay?","text":"My own key","placement":"unplaced","state":"make"},
|
|
90
|
+
{"key":"L0070","section":"How do you want to pay?","text":"Free here. {…} bills you for it directly.","placement":"placed","file":"modules/hall-ui/public/ai-studio.js","line":336,"string_id":"e9a1af5dc515","state":"make"},
|
|
91
|
+
{"key":"L0071","section":"How do you want to pay?","text":"Gemini key ending {…}","placement":"unplaced","state":"make"},
|
|
92
|
+
{"key":"L0072","section":"How do you want to pay?","text":"My balance","placement":"placed","file":"modules/hall-ui/public/ai-studio.js","line":340,"string_id":"39afdc03594a","state":"make"},
|
|
93
|
+
{"key":"L0073","section":"How do you want to pay?","text":"Usually a few cents. Up to {…} is set aside, and the rest comes back.","placement":"placed","file":"modules/hall-ui/public/ai-studio.js","line":340,"string_id":"664555b65658","state":"make"},
|
|
94
|
+
{"key":"L0074","section":"How do you want to pay?","text":"{…} left","placement":"placed","file":"modules/hall-ui/public/market-watch.js","line":73,"string_id":"92b79edf21f6","state":"make"},
|
|
95
|
+
{"key":"L0075","section":"How do you want to pay?","text":"You {…}.","placement":"placed","file":"modules/hall-ui/public/board-room.js","line":471,"string_id":"819dfb951611","state":"make"},
|
|
96
|
+
{"key":"L0076","section":"How do you want to pay?","text":"Builders hall · this session","placement":"placed","file":"modules/hall-ui/public/craft-mode.js","line":670,"string_id":"fd1903586e8e","state":"make"},
|
|
97
|
+
{"key":"L0077","section":"What should it make?","text":"What should it make?","placement":"placed","file":"modules/hall-ui/public/ai-studio.js","line":301,"string_id":"dc5f6264af0f","state":"describe"},
|
|
98
|
+
{"key":"L0078","section":"What should it make?","text":"Say what you want, in your own words.","placement":"placed","file":"modules/hall-ui/public/ai-studio.js","line":301,"string_id":"53b9f8b2c279","attr":"placeholder","state":"describe"},
|
|
99
|
+
{"key":"L0079","section":"What should it make?","text":"Your project's look and words are added for you, so you don't need to describe them.","placement":"placed","file":"modules/hall-ui/public/ai-studio.js","line":301,"string_id":"e8afba68c0ee","state":"describe"},
|
|
100
|
+
{"key":"L0080","section":"What should it make?","text":"Next","placement":"unplaced","state":"describe"},
|
|
101
|
+
{"key":"L0081","section":"What should it make?","text":"Back","placement":"unplaced","state":"describe"},
|
|
102
|
+
{"key":"L0082","section":"What should it make?","text":"Builders hall · this session","placement":"placed","file":"modules/hall-ui/public/craft-mode.js","line":670,"string_id":"fd1903586e8e","state":"describe"},
|
|
103
|
+
{"key":"L0083","section":"What are you starting from?","text":"What are you starting from?","placement":"placed","file":"modules/hall-ui/public/ai-studio.js","line":180,"string_id":"b5426a29991c"},
|
|
104
|
+
{"key":"L0084","section":"What are you starting from?","text":"Drop sketches, pictures or a PDF here, paste a picture,","placement":"placed","file":"modules/hall-ui/public/ai-studio.js","line":180,"string_id":"39f897eaff3c"},
|
|
105
|
+
{"key":"L0085","section":"What are you starting from?","text":"choose files","placement":"placed","file":"modules/hall-ui/public/ai-studio.js","line":180,"string_id":"ad625012b13c"},
|
|
106
|
+
{"key":"L0086","section":"What are you starting from?","text":"or","placement":"unplaced"},
|
|
107
|
+
{"key":"L0087","section":"What are you starting from?","text":"take a photo","placement":"placed","file":"modules/hall-ui/public/ai-studio.js","line":180,"string_id":"e25936f449c7"},
|
|
108
|
+
{"key":"L0088","section":"What are you starting from?","text":"Up to {…}. Pictures up to 4 MB, PDFs up to 8 MB.","placement":"placed","file":"modules/hall-ui/public/ai-studio.js","line":180,"string_id":"56f9e72dc635"},
|
|
109
|
+
{"key":"L0089","section":"What are you starting from?","text":"1.2 MB","placement":"unplaced"},
|
|
110
|
+
{"key":"L0090","section":"What are you starting from?","text":"remove","placement":"unplaced","occurrences":3},
|
|
111
|
+
{"key":"L0091","section":"What are you starting from?","text":"840 KB","placement":"unplaced"},
|
|
112
|
+
{"key":"L0092","section":"What are you starting from?","text":"PDF","placement":"unplaced"},
|
|
113
|
+
{"key":"L0093","section":"What are you starting from?","text":"3.1 MB","placement":"unplaced"},
|
|
114
|
+
{"key":"L0094","section":"What are you starting from?","text":"Next","placement":"unplaced"},
|
|
115
|
+
{"key":"L0095","section":"What are you starting from?","text":"3 files ready","placement":"unplaced"},
|
|
116
|
+
{"key":"L0096","section":"What are you starting from?","text":"Builders hall · this session","placement":"placed","file":"modules/hall-ui/public/craft-mode.js","line":670,"string_id":"fd1903586e8e"},
|
|
117
|
+
{"key":"L0097","section":"What are you doing now?","text":"What are you doing now?","placement":"placed","file":"modules/hall-ui/public/craft-mode.js","line":671,"string_id":"60853319f290"},
|
|
118
|
+
{"key":"L0098","section":"What are you doing now?","text":"Pick one. You can switch any time from the top bar.","placement":"placed","file":"modules/hall-ui/public/craft-mode.js","line":672,"string_id":"4f87d5b17b54"},
|
|
119
|
+
{"key":"L0099","section":"What are you doing now?","text":"Building","placement":"unplaced"},
|
|
120
|
+
{"key":"L0100","section":"What are you doing now?","text":"{…} and {…}","placement":"placed","file":"modules/hall-ui/public/profile-nudge.js","line":77,"string_id":"56b00d773232","occurrences":3},
|
|
121
|
+
{"key":"L0101","section":"What are you doing now?","text":"Artistry","placement":"unplaced"},
|
|
122
|
+
{"key":"L0102","section":"What are you doing now?","text":"Ideating","placement":"unplaced"},
|
|
123
|
+
{"key":"L0103","section":"What are you doing now?","text":"Turn thoughts into ideas.","placement":"unplaced"},
|
|
124
|
+
{"key":"L0104","section":"What are you doing now?","text":"Ask me again next session","placement":"placed","file":"modules/hall-ui/public/craft-mode.js","line":675,"string_id":"fa86bf403775"}
|
|
123
125
|
]
|
|
124
126
|
},
|
|
125
127
|
{
|
|
@@ -2941,7 +2943,7 @@
|
|
|
2941
2943
|
"surface": "builders",
|
|
2942
2944
|
"title": "Builders",
|
|
2943
2945
|
"states_read": ["roster","artists","search","out"],
|
|
2944
|
-
"files_hash": "
|
|
2946
|
+
"files_hash": "6b822ffa6ef8523d",
|
|
2945
2947
|
"reading_hash": "a61b867b5e26fa40",
|
|
2946
2948
|
"counts": {"lines":45,"placed":12,"shared":8,"unplaced":25},
|
|
2947
2949
|
"omitted": {"data":60},
|
|
@@ -4216,7 +4218,7 @@
|
|
|
4216
4218
|
"surface": "builders",
|
|
4217
4219
|
"title": "Studio",
|
|
4218
4220
|
"states_read": ["home","out","flow","flow-pick","status","words-offer","words-edit","reviews","full","full-back","approvals","approvals-before","approvals-phone","approvals-note","approved","sent-back","approvals-page"],
|
|
4219
|
-
"files_hash": "
|
|
4221
|
+
"files_hash": "a07e1e7a763b27b0",
|
|
4220
4222
|
"reading_hash": "bcba11e6cef56218",
|
|
4221
4223
|
"counts": {"lines":31,"placed":16,"shared":6,"unplaced":9},
|
|
4222
4224
|
"omitted": {"data":4},
|
|
@@ -100,7 +100,7 @@ function buildContext({ branding, projectDoc, designDoc }) {
|
|
|
100
100
|
const palette = branding && branding.theme && branding.theme.colors ? JSON.stringify(branding.theme.colors).slice(0, 800) : '';
|
|
101
101
|
const parts = [
|
|
102
102
|
`You are the art director's assistant for ${id.productName || 'this project'}${id.worldName && id.worldName !== id.productName ? `, set in the world of ${id.worldName}` : ''}.`,
|
|
103
|
-
'An artist on the project has sent a sketch or reference images with a request. Answer as a thoughtful collaborator: say what you see, what works, and how to take it further, in plain words.',
|
|
103
|
+
'An artist on the project has sent a sketch or reference images with a request. Answer as a thoughtful collaborator: say what you see, what works, and how to take it further, in plain words. Keep it short and friendly for a visual artist: a few short paragraphs or a brief list, no code, no markup symbols, and no technical file formats unless they asked for one.',
|
|
104
104
|
'Keep everything you suggest consistent with the project as described below.',
|
|
105
105
|
];
|
|
106
106
|
if (palette) parts.push(`## Brand colours\n${palette}`);
|
|
@@ -98,6 +98,48 @@
|
|
|
98
98
|
}));
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
// What a request will probably cost, from this builder's own finished ones
|
|
102
|
+
// paid the same way: the median of what we billed (ours) or of the cost the
|
|
103
|
+
// provider reported (their own key). max is the most one can ever cost on
|
|
104
|
+
// our key (max_cost_micro).
|
|
105
|
+
// typical is null when there is no history yet: the page then says so
|
|
106
|
+
// instead of inventing a number.
|
|
107
|
+
function estimate(requests, maxMicro, ours) {
|
|
108
|
+
const costs = (requests || [])
|
|
109
|
+
.filter((r) => r && r.status === 'done' && (r.key_source === 'ours') === !!ours)
|
|
110
|
+
.map((r) => (ours ? r.price_micro : r.provider_cost_micro))
|
|
111
|
+
.filter((n) => isMicro(n) && n > 0)
|
|
112
|
+
.sort((a, b) => a - b);
|
|
113
|
+
const max = isMicro(maxMicro) ? maxMicro : null;
|
|
114
|
+
if (!costs.length) return { typical: null, max, basis: 0 };
|
|
115
|
+
const mid = Math.floor(costs.length / 2);
|
|
116
|
+
const median = costs.length % 2 ? costs[mid] : Math.round((costs[mid - 1] + costs[mid]) / 2);
|
|
117
|
+
return { typical: max === null ? median : Math.min(median, max), max, basis: costs.length };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Google reports no price on a builder's own Gemini key, so the page says
|
|
121
|
+
// "about" and works it out from Google's published rates: a written reply
|
|
122
|
+
// (gemini-2.5-pro, a few thousand tokens in and about a thousand out) and
|
|
123
|
+
// each picture (gemini-2.5-flash-image, about $0.039 each). The two numbers
|
|
124
|
+
// are named here and spelled nowhere else; update them if Google's change.
|
|
125
|
+
const GEMINI_REPLY_MICRO = 25000;
|
|
126
|
+
const GEMINI_IMAGE_MICRO = 39000;
|
|
127
|
+
function geminiEstimate(imageCount) {
|
|
128
|
+
const n = Math.max(1, Math.floor(Number(imageCount) || 0));
|
|
129
|
+
return GEMINI_REPLY_MICRO + n * GEMINI_IMAGE_MICRO;
|
|
130
|
+
}
|
|
131
|
+
const outputCount = (r) => ((r && r.files) || []).filter((f) => f.role === 'output').length;
|
|
132
|
+
|
|
133
|
+
// The headline cost on the result: one sentence an artist can read at a glance.
|
|
134
|
+
function costHeadline(req) {
|
|
135
|
+
const r = req || {};
|
|
136
|
+
if (r.status !== 'done') return '';
|
|
137
|
+
if (r.key_source === 'ours' && isMicro(r.price_micro)) return `This cost ${usd(r.price_micro)}, taken from your balance.`;
|
|
138
|
+
if (r.key_source === 'own' && isMicro(r.provider_cost_micro)) return `This cost ${usd(r.provider_cost_micro)}, billed to your own key.`;
|
|
139
|
+
if (r.key_source === 'own') return `This cost about ${usd(geminiEstimate(outputCount(r)))} on your Gemini key.`;
|
|
140
|
+
return '';
|
|
141
|
+
}
|
|
142
|
+
|
|
101
143
|
// The prompt as one quoted line for step 3's summary row.
|
|
102
144
|
function quoteLine(prompt, max) {
|
|
103
145
|
const t = String(prompt || '').replace(/\s+/g, ' ').trim();
|
|
@@ -189,8 +231,8 @@
|
|
|
189
231
|
}
|
|
190
232
|
if (r.key_source === 'own') {
|
|
191
233
|
return {
|
|
192
|
-
rows: [['Paid with', 'your own Gemini key'], ['Cost',
|
|
193
|
-
note: "Google doesn't tell us the price on your own key, so
|
|
234
|
+
rows: [['Paid with', 'your own Gemini key'], ['Cost', `about ${usd(geminiEstimate(outputCount(r)))}`]],
|
|
235
|
+
note: "Google doesn't tell us the exact price on your own key, so this is an estimate. Your Google bill has the real figure. We charged nothing.",
|
|
194
236
|
};
|
|
195
237
|
}
|
|
196
238
|
return { rows: [], note: '' };
|
|
@@ -238,15 +280,38 @@
|
|
|
238
280
|
}
|
|
239
281
|
}
|
|
240
282
|
|
|
241
|
-
// The model's reply
|
|
242
|
-
//
|
|
283
|
+
// The model's reply read the way an artist wants to see it: headings as
|
|
284
|
+
// headings, bullets as a list, **bold** and `names` kept, divider dashes
|
|
285
|
+
// dropped, and any code listing folded away behind one line instead of
|
|
286
|
+
// pouring down the page. Every character of text goes through the hall's ONE
|
|
287
|
+
// escaper, handed in (window.OTB.escapeHtml in the page), before any tag is
|
|
288
|
+
// added.
|
|
243
289
|
function replyHtml(md, escape) {
|
|
244
290
|
const text = String(md || '').replace(/\r\n/g, '\n').trim();
|
|
245
291
|
if (!text || typeof escape !== 'function') return '';
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
292
|
+
const inline = (s) => escape(s).replace(/\*\*([^*\n]+)\*\*/g, '<b>$1</b>').replace(/`([^`\n]+)`/g, '<code>$1</code>');
|
|
293
|
+
const out = [];
|
|
294
|
+
let para = [];
|
|
295
|
+
let list = [];
|
|
296
|
+
let code = null;
|
|
297
|
+
const flushPara = () => { if (para.length) out.push(`<p>${para.map(inline).join('<br>')}</p>`); para = []; };
|
|
298
|
+
const flushList = () => { if (list.length) out.push(`<ul>${list.map((t) => `<li>${inline(t)}</li>`).join('')}</ul>`); list = []; };
|
|
299
|
+
for (const raw of text.split('\n')) {
|
|
300
|
+
const line = raw.trimEnd();
|
|
301
|
+
if (/^\s*```/.test(line)) {
|
|
302
|
+
if (code) { out.push(`<details class="ais-code"><summary>Code from the answer</summary><pre>${escape(code.join('\n'))}</pre></details>`); code = null; } else { flushPara(); flushList(); code = []; }
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
if (code) { code.push(raw); continue; }
|
|
306
|
+
const head = /^#{1,6}\s+(.+)$/.exec(line);
|
|
307
|
+
const item = /^\s*[*•-]\s+(.+)$/.exec(line);
|
|
308
|
+
if (!line.trim()) { flushPara(); flushList(); } else if (/^\s*-{2,}\s*$/.test(line)) { flushPara(); flushList(); } else if (head) {
|
|
309
|
+
flushPara(); flushList(); out.push(`<h3 class="ais-rh">${inline(head[1].replace(/\*\*/g, ''))}</h3>`);
|
|
310
|
+
} else if (item) { flushPara(); list.push(item[1]); } else { flushList(); para.push(line.trim()); }
|
|
311
|
+
}
|
|
312
|
+
if (code) out.push(`<details class="ais-code"><summary>Code from the answer</summary><pre>${escape(code.join('\n'))}</pre></details>`);
|
|
313
|
+
flushPara(); flushList();
|
|
314
|
+
return out.join('');
|
|
250
315
|
}
|
|
251
316
|
|
|
252
317
|
// The home's AI action line: the newest request, while it is being made or
|
|
@@ -266,7 +331,7 @@
|
|
|
266
331
|
|
|
267
332
|
const lib = {
|
|
268
333
|
MAX_FILES, MAX_IMAGE_BYTES, MAX_PDF_BYTES, IMAGE_TYPES, PDF_TYPE, STEPS, TOPUP_CHOICES, ANSWER_AFTER_SEC,
|
|
269
|
-
usd, balanceUsd, sizeText, routeOf, checkFile, isImage, stepMarks, quoteLine, ownKey, ownKeys, payChoices,
|
|
334
|
+
usd, balanceUsd, sizeText, routeOf, checkFile, isImage, stepMarks, quoteLine, ownKey, ownKeys, payChoices, estimate, geminiEstimate, costHeadline,
|
|
270
335
|
waitSteps, clock, isFinished, receipt, againLine, monthSummary, ledgerLine, replyHtml, homeLine,
|
|
271
336
|
};
|
|
272
337
|
if (typeof module !== 'undefined' && module.exports) module.exports = lib;
|
|
@@ -138,12 +138,24 @@
|
|
|
138
138
|
.ais-pick img { display: block; width: 100%; height: 100%; object-fit: cover; }
|
|
139
139
|
.ais-pick--on { outline: 2px solid var(--st-accent); outline-offset: 0; }
|
|
140
140
|
.ais-reply p { margin: 0 0 12px; font-size: 15px; line-height: 1.6; color: var(--st-ink-sub); font-weight: 300; }
|
|
141
|
+
.ais-rh { margin: 18px 0 6px; font-size: 16px; font-weight: 500; color: var(--st-ink); }
|
|
142
|
+
.ais-reply ul { margin: 0 0 12px; padding-left: 20px; font-size: 15px; line-height: 1.6; color: var(--st-ink-sub); font-weight: 300; }
|
|
143
|
+
.ais-reply code { font-size: 13.5px; }
|
|
144
|
+
.ais-code { margin: 0 0 12px; font-size: 13.5px; color: var(--st-ink-faint); }
|
|
145
|
+
.ais-code summary { cursor: pointer; min-height: 24px; }
|
|
146
|
+
.ais-code pre { margin: 8px 0 0; padding: 12px; overflow-x: auto; border-radius: 12px; background: var(--st-glass); white-space: pre; }
|
|
141
147
|
.ais-reply b { color: var(--st-ink); font-weight: 500; }
|
|
142
148
|
.ais-again { display: flex; flex-direction: column; gap: 8px; }
|
|
143
149
|
.ais-receipt, .ais-topup {
|
|
144
150
|
display: flex; flex-direction: column; padding: 10px 20px; border-radius: 22px;
|
|
145
151
|
background: var(--st-glass); border: 1px solid var(--st-glass-edge);
|
|
146
152
|
}
|
|
153
|
+
.ais-confirm {
|
|
154
|
+
display: flex; flex-direction: column; gap: 8px; padding: 16px 20px; border-radius: 22px;
|
|
155
|
+
background: var(--st-glass); border: 1px solid var(--st-glass-edge);
|
|
156
|
+
}
|
|
157
|
+
.ais-confirm__head { margin: 0; font-size: 20px; font-weight: 500; color: var(--st-ink); }
|
|
158
|
+
.ais-cost { margin: 0 0 12px; font-size: 17px; font-weight: 500; color: var(--st-ink); }
|
|
147
159
|
.ais-line { display: flex; align-items: center; gap: 14px; min-height: 40px; border-top: 1px solid var(--st-track); font-size: 14px; color: var(--st-ink); }
|
|
148
160
|
.ais-line:first-child, .ais-head + .ais-line { border-top: 0; }
|
|
149
161
|
.ais-line a { color: var(--st-link); display: inline-flex; align-items: center; min-height: 24px; }
|
|
@@ -352,13 +352,47 @@
|
|
|
352
352
|
<h1 class="ais-ask" data-head tabindex="-1">How do you want to pay?</h1>
|
|
353
353
|
<div class="ais-row ais-row--summary">${thumbs}<span class="ais-grow ais-soft">${esc(lib.quoteLine(state.draft.prompt))}</span><a class="ais-link" href="/builders/ai-studio?step=describe" data-nav="step=describe">change</a></div>
|
|
354
354
|
${ownCard || balanceCard ? `<div class="ais-cards">${ownCard}${balanceCard}</div>` : ''}
|
|
355
|
+
<div class="ais-confirm" id="ais-confirm" role="group" aria-label="Confirm the cost" hidden></div>
|
|
355
356
|
<p class="ais-faint">${esc(foot)}</p>
|
|
356
357
|
${extra}
|
|
357
358
|
<p class="ais-err" id="ais-err" role="alert" hidden></p>`;
|
|
358
|
-
page.querySelectorAll('[data-pay]').forEach((b) => b.addEventListener('click', () =>
|
|
359
|
+
page.querySelectorAll('[data-pay]').forEach((b) => b.addEventListener('click', () => askToConfirm(b.getAttribute('data-pay'), c)));
|
|
359
360
|
wireNavLinks();
|
|
360
361
|
}
|
|
361
362
|
|
|
363
|
+
// Before anything is sent or set aside: say what it will probably cost and
|
|
364
|
+
// wait for a yes. Past runs set the guess; the ceiling is what a run can
|
|
365
|
+
// never exceed.
|
|
366
|
+
async function askToConfirm(payWith, choices) {
|
|
367
|
+
if (state.busy) return;
|
|
368
|
+
const own = payWith !== 'ours';
|
|
369
|
+
if (payWith !== 'gemini' && !state.history) {
|
|
370
|
+
const res = await api.request('GET', `${API}/ai-studio/requests`);
|
|
371
|
+
state.history = res.ok && res.data ? res.data.requests : [];
|
|
372
|
+
}
|
|
373
|
+
const est = lib.estimate(state.history || [], state.balance && state.balance.max_cost_micro, !own);
|
|
374
|
+
const typical = payWith === 'gemini' ? lib.geminiEstimate(1) : est.typical;
|
|
375
|
+
const guess = typical === null ? 'A few cents' : `About ${lib.usd(typical)}`;
|
|
376
|
+
const ceiling = own || est.max === null ? '' : `It will never cost more than ${lib.usd(est.max)}.`;
|
|
377
|
+
const who = own ? 'Your own key pays, so nothing comes out of your balance here.' : `Taken from your balance (${choices.left}), and anything unused comes back.`;
|
|
378
|
+
const basis = payWith === 'gemini' ? 'Google reports no price on your own key, so this is worked out from its published rates: one reply and one picture.' : est.basis ? `Based on your last ${est.basis === 1 ? 'request' : `${est.basis} requests`}.` : 'You have no finished requests yet, so this is a rough guess.';
|
|
379
|
+
const box = page.querySelector('#ais-confirm');
|
|
380
|
+
if (!box) return;
|
|
381
|
+
box.hidden = false;
|
|
382
|
+
box.innerHTML = `
|
|
383
|
+
<h2 class="ais-confirm__head" data-confirm-head tabindex="-1">${esc(guess)} to make this</h2>
|
|
384
|
+
<p class="ais-soft">${esc([ceiling, who].filter(Boolean).join(' '))}</p>
|
|
385
|
+
<p class="ais-faint">${esc(basis)}</p>
|
|
386
|
+
<div class="ais-go ais-go--wrap">
|
|
387
|
+
<button type="button" class="ais-btn" id="ais-confirm-go">Make it</button>
|
|
388
|
+
<button type="button" class="ais-ghost" id="ais-confirm-cancel">Not yet</button>
|
|
389
|
+
</div>`;
|
|
390
|
+
const head = box.querySelector('[data-confirm-head]');
|
|
391
|
+
if (head) head.focus();
|
|
392
|
+
box.querySelector('#ais-confirm-cancel').addEventListener('click', () => { box.hidden = true; box.innerHTML = ''; });
|
|
393
|
+
box.querySelector('#ais-confirm-go').addEventListener('click', (ev) => sendRequest(payWith, state.draft.prompt, readyFiles(), ev.currentTarget));
|
|
394
|
+
}
|
|
395
|
+
|
|
362
396
|
// Same-page links move through history, so the steps keep the back button.
|
|
363
397
|
function wireNavLinks() {
|
|
364
398
|
page.querySelectorAll('[data-nav]').forEach((a) => a.addEventListener('click', (ev) => {
|
|
@@ -465,6 +499,7 @@
|
|
|
465
499
|
const rc = lib.receipt(req, state.balance && state.balance.price_multiplier);
|
|
466
500
|
const receiptHtml = rc.rows.length ? `<div class="ais-receipt">${rc.rows.map(([k, v]) => `<div class="ais-line"><span class="ais-grow">${esc(k)}</span><span>${esc(v)}</span></div>`).join('')}${rc.note ? `<div class="ais-line"><span class="ais-grow ais-faint ais-wrap">${esc(rc.note)}</span></div>` : ''}</div>` : '';
|
|
467
501
|
const failed = req.status !== 'done';
|
|
502
|
+
const headline = lib.costHeadline(req);
|
|
468
503
|
main.setAttribute('data-view', 'result');
|
|
469
504
|
page.innerHTML = `
|
|
470
505
|
<h1 class="ais-sr" data-head tabindex="-1">${failed ? 'That did not work' : 'Your result'}</h1>
|
|
@@ -476,6 +511,7 @@
|
|
|
476
511
|
</div>
|
|
477
512
|
<div class="ais-result__words">
|
|
478
513
|
${failed ? `<p class="ais-err">${esc(req.error || 'It did not work, and nothing was charged.')}</p>` : ''}
|
|
514
|
+
${headline ? `<p class="ais-cost" data-cost>${esc(headline)}</p>` : ''}
|
|
479
515
|
<div class="ais-reply">${lib.replyHtml(req.reply_md, esc)}</div>
|
|
480
516
|
<div class="ais-again">
|
|
481
517
|
<label class="ais-head" for="ais-again">Your request</label>
|
|
@@ -52,3 +52,46 @@
|
|
|
52
52
|
font-size: 11.5px;
|
|
53
53
|
color: var(--ink-faint);
|
|
54
54
|
}
|
|
55
|
+
|
|
56
|
+
/* ---- the circuit divider (task 1005032, the owner's Studio idea 1001297; mock:
|
|
57
|
+
docs/design/mocks/builders-leaderboard/) -----------------------------------
|
|
58
|
+
A trace between the column headings and the first row: a fixed cap at each
|
|
59
|
+
end, a hairline stretched between them, and orange nodes on the traces. It is
|
|
60
|
+
drawn on the FIRST BODY ROW (its top 30px, which the row's own top padding
|
|
61
|
+
makes room for) rather than under the sticky heading, so it scrolls with the
|
|
62
|
+
rows and never strands a blank band under a stuck header. Two masks, two
|
|
63
|
+
tokens: the traces are --ink-faint, the nodes --accent, so both modes follow
|
|
64
|
+
the world. The empty-state row has no trace. Pure decoration, no markup. */
|
|
65
|
+
#roster-body .ledger th { border-bottom-color: transparent; }
|
|
66
|
+
#roster-body .ledger tbody tr:first-child:not(:has(.ledger__empty)) { position: relative; }
|
|
67
|
+
#roster-body .ledger tbody tr:first-child:not(:has(.ledger__empty)) td { padding-top: 44px; }
|
|
68
|
+
#roster-body .ledger tbody tr:first-child:not(:has(.ledger__empty)) td:first-child::before,
|
|
69
|
+
#roster-body .ledger tbody tr:first-child:not(:has(.ledger__empty)) td:first-child::after {
|
|
70
|
+
content: ""; position: absolute; left: 0; right: 0; top: 0; height: 30px;
|
|
71
|
+
pointer-events: none;
|
|
72
|
+
-webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
|
|
73
|
+
}
|
|
74
|
+
#roster-body .ledger tbody tr:first-child:not(:has(.ledger__empty)) td:first-child::before {
|
|
75
|
+
background: var(--ink-faint);
|
|
76
|
+
-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 30'%3E%3Cg fill='none' stroke='black' stroke-width='1.5'%3E%3Cpath d='M6 18H88V6H100V14H156V18H300'/%3E%3Cpath stroke-opacity='.55' stroke-width='1.2' d='M12 22H80M104 12H124M132 14H152M160 16H180M92 10V24'/%3E%3C/g%3E%3C/svg%3E"),
|
|
77
|
+
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 30'%3E%3Cg transform='matrix(-1 0 0 1 300 0)' fill='none' stroke='black' stroke-width='1.5'%3E%3Cpath d='M6 18H88V22H168V28H196V18H300'/%3E%3Cpath stroke-opacity='.55' stroke-width='1.2' d='M12 14H70M110 10H128M136 16H160M170 4V14M200 8V24'/%3E%3C/g%3E%3C/svg%3E"),
|
|
78
|
+
linear-gradient(black, black);
|
|
79
|
+
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 30'%3E%3Cg fill='none' stroke='black' stroke-width='1.5'%3E%3Cpath d='M6 18H88V6H100V14H156V18H300'/%3E%3Cpath stroke-opacity='.55' stroke-width='1.2' d='M12 22H80M104 12H124M132 14H152M160 16H180M92 10V24'/%3E%3C/g%3E%3C/svg%3E"),
|
|
80
|
+
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 30'%3E%3Cg transform='matrix(-1 0 0 1 300 0)' fill='none' stroke='black' stroke-width='1.5'%3E%3Cpath d='M6 18H88V22H168V28H196V18H300'/%3E%3Cpath stroke-opacity='.55' stroke-width='1.2' d='M12 14H70M110 10H128M136 16H160M170 4V14M200 8V24'/%3E%3C/g%3E%3C/svg%3E"),
|
|
81
|
+
linear-gradient(black, black);
|
|
82
|
+
-webkit-mask-size: 300px 30px, 300px 30px, calc(100% - 598px) 1.5px;
|
|
83
|
+
mask-size: 300px 30px, 300px 30px, calc(100% - 598px) 1.5px;
|
|
84
|
+
-webkit-mask-position: left top, right top, 299px 17.25px;
|
|
85
|
+
mask-position: left top, right top, 299px 17.25px;
|
|
86
|
+
}
|
|
87
|
+
#roster-body .ledger tbody tr:first-child:not(:has(.ledger__empty)) td:first-child::after {
|
|
88
|
+
background: var(--accent);
|
|
89
|
+
-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 30'%3E%3Cg fill='black'%3E%3Ccircle cx='6' cy='18' r='7' fill-opacity='.25'/%3E%3Ccircle cx='88' cy='6' r='7' fill-opacity='.25'/%3E%3Ccircle cx='296' cy='18' r='7' fill-opacity='.25'/%3E%3Ccircle cx='6' cy='18' r='3.5'/%3E%3Ccircle cx='88' cy='6' r='3.5'/%3E%3Ccircle cx='296' cy='18' r='3.5'/%3E%3C/g%3E%3C/svg%3E"),
|
|
90
|
+
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 30'%3E%3Cg transform='matrix(-1 0 0 1 300 0)' fill='black'%3E%3Ccircle cx='6' cy='18' r='7' fill-opacity='.25'/%3E%3Ccircle cx='196' cy='28' r='7' fill-opacity='.25'/%3E%3Ccircle cx='296' cy='18' r='7' fill-opacity='.25'/%3E%3Ccircle cx='6' cy='18' r='3.5'/%3E%3Ccircle cx='196' cy='28' r='3.5'/%3E%3Ccircle cx='296' cy='18' r='3.5'/%3E%3C/g%3E%3C/svg%3E");
|
|
91
|
+
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 30'%3E%3Cg fill='black'%3E%3Ccircle cx='6' cy='18' r='7' fill-opacity='.25'/%3E%3Ccircle cx='88' cy='6' r='7' fill-opacity='.25'/%3E%3Ccircle cx='296' cy='18' r='7' fill-opacity='.25'/%3E%3Ccircle cx='6' cy='18' r='3.5'/%3E%3Ccircle cx='88' cy='6' r='3.5'/%3E%3Ccircle cx='296' cy='18' r='3.5'/%3E%3C/g%3E%3C/svg%3E"),
|
|
92
|
+
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 30'%3E%3Cg transform='matrix(-1 0 0 1 300 0)' fill='black'%3E%3Ccircle cx='6' cy='18' r='7' fill-opacity='.25'/%3E%3Ccircle cx='196' cy='28' r='7' fill-opacity='.25'/%3E%3Ccircle cx='296' cy='18' r='7' fill-opacity='.25'/%3E%3Ccircle cx='6' cy='18' r='3.5'/%3E%3Ccircle cx='196' cy='28' r='3.5'/%3E%3Ccircle cx='296' cy='18' r='3.5'/%3E%3C/g%3E%3C/svg%3E");
|
|
93
|
+
-webkit-mask-size: 300px 30px, 300px 30px;
|
|
94
|
+
mask-size: 300px 30px, 300px 30px;
|
|
95
|
+
-webkit-mask-position: left top, right top;
|
|
96
|
+
mask-position: left top, right top;
|
|
97
|
+
}
|
|
@@ -28,3 +28,12 @@ Pinned by `tests/leaderboard_roles.mjs` (the read, the route, the REAL roster.js
|
|
|
28
28
|
- **The roster keeps its live columns**: place with the builder's number, rank, karma and tokens, the founding mark and the laurels, and its search and sort lenses. The mock draws the leaderboard bare; the live hall's chrome wins (the blend rule).
|
|
29
29
|
- **The column is "Roles", not "Preferred roles"**: it lists roles the builder has earned in as well as the one they chose, so "preferred" would understate it.
|
|
30
30
|
- **The status page has the roles but not the toggle.** It is a one-glance public dashboard of the top builders on its own palette; the toggle lives on the roster, which is the leaderboard a builder works from.
|
|
31
|
+
|
|
32
|
+
## The circuit divider (task 1005032)
|
|
33
|
+
|
|
34
|
+
The owner's Studio idea 1001297 (a circuit-trace image as a table divider; mock `docs/design/mocks/builders-leaderboard/`, task 1005030) now sits between the roster's column headings and its first row. It is **CSS only, in `roster.css`**: the ledger kit is untouched and no markup was added.
|
|
35
|
+
|
|
36
|
+
- **It is drawn on the first BODY row, not under the sticky heading.** A divider hung under the sticky `th` would stay stuck while the rows scrolled away, leaving a blank band; on the first row it scrolls with the data. The row's top padding makes room for it.
|
|
37
|
+
- **The pseudo-elements sit on the row's first `td`, never on the `tr`.** On the `tr` they became two extra table cells and pushed every cell in the row two columns right (seen in the first render). The `tr` only carries `position: relative`, so the `td`'s absolute children size against the whole row.
|
|
38
|
+
- **Two masks, two tokens.** Traces are `--ink-faint` and the orange nodes `--accent`, each shown through an SVG mask, so light and dark follow the world with no hard-coded colour. Left cap, right cap and the stretching hairline are three layers of one mask.
|
|
39
|
+
- **The empty-state row has no trace** (`:not(:has(.ledger__empty))`). Checked at desktop and 375px, light and dark: the table scrolls inside its card on a phone and the divider spans it; the page does not scroll sideways.
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.24.
|
|
3
|
+
"version": "1.24.20",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.24.
|
|
9
|
+
"version": "1.24.20",
|
|
10
10
|
"license": "AGPL-3.0-or-later",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"express": "^4.21.2",
|