@oddessentials/agent-guild 1.28.0 → 1.30.0
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/bin/native/win32-arm64/agent-guild-report.exe +0 -0
- package/bin/native/win32-x64/agent-guild-report.exe +0 -0
- package/bin/windows/arm64/agent-guild-start.exe +0 -0
- package/bin/windows/x64/agent-guild-start.exe +0 -0
- package/docs/api.md +10 -2
- package/node_modules/@jsquash/jpeg/CHANGELOG.md +54 -0
- package/node_modules/@jsquash/jpeg/LICENSE +201 -0
- package/node_modules/@jsquash/jpeg/README.md +105 -0
- package/node_modules/@jsquash/jpeg/codec/LICENSE.codec.md +132 -0
- package/node_modules/@jsquash/jpeg/codec/dec/mozjpeg_dec.d.ts +7 -0
- package/node_modules/@jsquash/jpeg/codec/dec/mozjpeg_dec.js +15 -0
- package/node_modules/@jsquash/jpeg/codec/dec/mozjpeg_dec.wasm +0 -0
- package/node_modules/@jsquash/jpeg/codec/enc/mozjpeg_enc.d.ts +37 -0
- package/node_modules/@jsquash/jpeg/codec/enc/mozjpeg_enc.js +15 -0
- package/node_modules/@jsquash/jpeg/codec/enc/mozjpeg_enc.wasm +0 -0
- package/node_modules/@jsquash/jpeg/codec/pre.js +24 -0
- package/node_modules/@jsquash/jpeg/decode.d.ts +16 -0
- package/node_modules/@jsquash/jpeg/decode.js +36 -0
- package/node_modules/@jsquash/jpeg/emscripten-types.d.ts +137 -0
- package/node_modules/@jsquash/jpeg/encode.d.ts +21 -0
- package/node_modules/@jsquash/jpeg/encode.js +35 -0
- package/node_modules/@jsquash/jpeg/index.d.ts +3 -0
- package/node_modules/@jsquash/jpeg/index.js +2 -0
- package/node_modules/@jsquash/jpeg/meta.d.ts +24 -0
- package/node_modules/@jsquash/jpeg/meta.js +25 -0
- package/node_modules/@jsquash/jpeg/package.json +32 -0
- package/node_modules/@jsquash/jpeg/utils.d.ts +17 -0
- package/node_modules/@jsquash/jpeg/utils.js +31 -0
- package/node_modules/@jsquash/png/CHANGELOG.md +69 -0
- package/node_modules/@jsquash/png/LICENSE +201 -0
- package/node_modules/@jsquash/png/README.md +114 -0
- package/node_modules/@jsquash/png/codec/LICENSE.codec.md +29 -0
- package/node_modules/@jsquash/png/codec/README.md +5 -0
- package/node_modules/@jsquash/png/codec/pkg/README.md +5 -0
- package/node_modules/@jsquash/png/codec/pkg/squoosh_png.d.ts +71 -0
- package/node_modules/@jsquash/png/codec/pkg/squoosh_png.js +314 -0
- package/node_modules/@jsquash/png/codec/pkg/squoosh_png_bg.wasm +0 -0
- package/node_modules/@jsquash/png/codec/pkg/squoosh_png_bg.wasm.d.ts +13 -0
- package/node_modules/@jsquash/png/codec/pre.js +24 -0
- package/node_modules/@jsquash/png/decode.d.ts +29 -0
- package/node_modules/@jsquash/png/decode.js +35 -0
- package/node_modules/@jsquash/png/encode.d.ts +31 -0
- package/node_modules/@jsquash/png/encode.js +40 -0
- package/node_modules/@jsquash/png/index.d.ts +3 -0
- package/node_modules/@jsquash/png/index.js +2 -0
- package/node_modules/@jsquash/png/meta.d.ts +16 -0
- package/node_modules/@jsquash/png/meta.js +15 -0
- package/node_modules/@jsquash/png/package.json +34 -0
- package/node_modules/@jsquash/webp/CHANGELOG.md +48 -0
- package/node_modules/@jsquash/webp/LICENSE +201 -0
- package/node_modules/@jsquash/webp/README.md +100 -0
- package/node_modules/@jsquash/webp/codec/LICENSE.codec.md +29 -0
- package/node_modules/@jsquash/webp/codec/Makefile.animated.backup +88 -0
- package/node_modules/@jsquash/webp/codec/README.md +5 -0
- package/node_modules/@jsquash/webp/codec/dec/README.md +18 -0
- package/node_modules/@jsquash/webp/codec/dec/webp_dec.d.ts +7 -0
- package/node_modules/@jsquash/webp/codec/dec/webp_dec.js +16 -0
- package/node_modules/@jsquash/webp/codec/dec/webp_dec.wasm +0 -0
- package/node_modules/@jsquash/webp/codec/enc/README.md +22 -0
- package/node_modules/@jsquash/webp/codec/enc/webp_enc.d.ts +42 -0
- package/node_modules/@jsquash/webp/codec/enc/webp_enc.js +16 -0
- package/node_modules/@jsquash/webp/codec/enc/webp_enc.wasm +0 -0
- package/node_modules/@jsquash/webp/codec/enc/webp_enc_simd.d.ts +1 -0
- package/node_modules/@jsquash/webp/codec/enc/webp_enc_simd.js +16 -0
- package/node_modules/@jsquash/webp/codec/enc/webp_enc_simd.wasm +0 -0
- package/node_modules/@jsquash/webp/codec/pre.js +24 -0
- package/node_modules/@jsquash/webp/decode.d.ts +15 -0
- package/node_modules/@jsquash/webp/decode.js +34 -0
- package/node_modules/@jsquash/webp/emscripten-types.d.ts +137 -0
- package/node_modules/@jsquash/webp/encode.d.ts +23 -0
- package/node_modules/@jsquash/webp/encode.js +43 -0
- package/node_modules/@jsquash/webp/index.d.ts +3 -0
- package/node_modules/@jsquash/webp/index.js +2 -0
- package/node_modules/@jsquash/webp/meta.d.ts +19 -0
- package/node_modules/@jsquash/webp/meta.js +33 -0
- package/node_modules/@jsquash/webp/package.json +35 -0
- package/node_modules/@jsquash/webp/utils.d.ts +17 -0
- package/node_modules/@jsquash/webp/utils.js +31 -0
- package/node_modules/argparse/lib/argparse.js +1 -1
- package/node_modules/argparse/lib/textwrap.js +13 -2
- package/node_modules/argparse/package.json +1 -1
- package/node_modules/markdown-it/dist/browser/markdown-it.esm.min.mjs +737 -686
- package/node_modules/markdown-it/dist/browser/markdown-it.esm.min.mjs.map +1 -1
- package/node_modules/markdown-it/dist/browser/markdown-it.umd.min.js +8 -8
- package/node_modules/markdown-it/dist/browser/markdown-it.umd.min.js.map +1 -1
- package/node_modules/markdown-it/dist/markdown-it.cjs.js +660 -518
- package/node_modules/markdown-it/dist/markdown-it.cjs.js.map +1 -1
- package/node_modules/markdown-it/dist/markdown-it.d.mts +1 -0
- package/node_modules/markdown-it/dist/markdown-it.mjs +179 -124
- package/node_modules/markdown-it/dist/markdown-it.mjs.map +1 -1
- package/node_modules/markdown-it/package.json +11 -11
- package/node_modules/node-pty/prebuilds/win32-arm64/conpty.node +0 -0
- package/node_modules/node-pty/prebuilds/win32-arm64/conpty_console_list.node +0 -0
- package/node_modules/node-pty/prebuilds/win32-x64/conpty.node +0 -0
- package/node_modules/node-pty/prebuilds/win32-x64/conpty_console_list.node +0 -0
- package/node_modules/wasm-feature-detect/LICENSE +202 -0
- package/node_modules/wasm-feature-detect/README.md +109 -0
- package/node_modules/wasm-feature-detect/README.md.ejs +89 -0
- package/node_modules/wasm-feature-detect/dist/cjs/index.cjs +1 -0
- package/node_modules/wasm-feature-detect/dist/esm/index.js +1 -0
- package/node_modules/wasm-feature-detect/dist/index.d.cts +24 -0
- package/node_modules/wasm-feature-detect/dist/index.d.ts +24 -0
- package/node_modules/wasm-feature-detect/dist/umd/index.js +1 -0
- package/node_modules/wasm-feature-detect/package.json +53 -0
- package/node_modules/ws/README.md +21 -29
- package/node_modules/ws/lib/buffer-util.js +13 -2
- package/node_modules/ws/lib/sender.js +4 -1
- package/node_modules/ws/lib/websocket.js +8 -3
- package/node_modules/ws/package.json +1 -1
- package/package.json +7 -4
- package/src/manager/config.mjs +2 -0
- package/src/manager/folder-browser.mjs +39 -3
- package/src/manager/main.mjs +4 -0
- package/src/manager/server.mjs +32 -5
- package/src/manager/steam-workshop.mjs +64 -0
- package/src/manager/yard-art.mjs +1 -1
- package/src/manager/yard-piece-check.mjs +424 -0
- package/src/manager/yard-pieces.mjs +188 -0
- package/src/manager/yard-worlds.mjs +214 -0
- package/web/app.js +175 -11
- package/web/index.html +20 -2
- package/web/skins/grove/ui/companion-bird.webp +0 -0
- package/web/skins/guild/skin.css +2 -13
- package/web/styles.css +15 -1
- package/web/yard/art.json +1 -1
- package/web/yard/model.mjs +44 -2
- package/web/yard/photo.js +3 -4
- package/web/yard/renderer.js +150 -38
- package/web/yard/vendor/engine.js +500 -495
- package/web/yard/view.js +160 -14
- package/web/yard/yard.css +55 -12
- package/web/skins/grove/ui/install-now-dark.svg +0 -91
- package/web/skins/grove/ui/install-now-light.svg +0 -91
package/web/yard/view.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { WORLDS, sessionPose } from './model.mjs';
|
|
1
|
+
import { WORLDS, PROVIDER_ORDER, sessionPose } from './model.mjs';
|
|
2
2
|
|
|
3
3
|
const $ = id => document.getElementById(id);
|
|
4
4
|
const make = (tag, cls, text) => Object.assign(document.createElement(tag), { className: cls, ...(text === undefined ? {} : { textContent: text }) });
|
|
@@ -17,6 +17,8 @@ async function boundedLoad(start, onProgress) {
|
|
|
17
17
|
} finally { settled = true; clearTimeout(timer); }
|
|
18
18
|
}
|
|
19
19
|
const megabytes = bytes => (bytes / 1048576).toFixed(1) + ' MB';
|
|
20
|
+
const CREWS = { anthropic: 'Claude Code', openai: 'Codex CLI', google: 'Antigravity CLI', xai: 'Grok Build', shell: 'Shell', docker: 'Docker Agent' };
|
|
21
|
+
const pieceKind = slot => slot === 'companion' ? 'companion' : 'character';
|
|
20
22
|
|
|
21
23
|
/** A layout with injected canonical controls. No API, sockets, or business rules. */
|
|
22
24
|
export function initYard(controller) {
|
|
@@ -28,7 +30,139 @@ export function initYard(controller) {
|
|
|
28
30
|
const root = document.documentElement;
|
|
29
31
|
let view = root.dataset.view === 'yard' ? 'yard' : 'cards';
|
|
30
32
|
let snapshot = controller.snapshot();
|
|
31
|
-
let lastSkin = '', lastTheme = '', wasConnected = false;
|
|
33
|
+
let lastSkin = '', lastTheme = '', lastRevision = null, wasConnected = false;
|
|
34
|
+
// Worlds that failed to draw here: skin to revision. The Yard shows its original until the world changes.
|
|
35
|
+
const unloadable = new Map();
|
|
36
|
+
const customFor = (skin) => {
|
|
37
|
+
const world = controller.yardWorld(skin);
|
|
38
|
+
return world && !world.problem && unloadable.get(skin) !== world.revision ? world : null;
|
|
39
|
+
};
|
|
40
|
+
const titleFor = (skin) => customFor(skin)?.title ?? WORLDS[skin].title;
|
|
41
|
+
const worldShown = new Map();
|
|
42
|
+
const loadWorld = (target, skin, theme, progress) => {
|
|
43
|
+
if (target.skin !== skin) {
|
|
44
|
+
worldShown.delete(skin);
|
|
45
|
+
for (const [key, shown] of pieceShown) if (key.startsWith(skin + '/') && shown.ok) pieceShown.delete(key);
|
|
46
|
+
target.setPieces(skin, piecesFor(skin));
|
|
47
|
+
worldSpot();
|
|
48
|
+
}
|
|
49
|
+
const custom = customFor(skin);
|
|
50
|
+
return target.setWorld(skin, theme, { progress, custom }).then(() => {
|
|
51
|
+
if (custom) { worldShown.set(skin, custom.revision); worldSpot(); }
|
|
52
|
+
}, (err) => {
|
|
53
|
+
if (!custom || disposed) throw err;
|
|
54
|
+
unloadable.set(skin, custom.revision);
|
|
55
|
+
if (skin === lastSkin) lastRevision = null;
|
|
56
|
+
worldSpot();
|
|
57
|
+
return target.setWorld(skin, theme, { progress });
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
const pieceShown = new Map();
|
|
61
|
+
const pieceKey = (skin, slot) => skin + '/' + slot;
|
|
62
|
+
const piecesOf = (skin) => controller.yardPieces?.(skin) ?? {};
|
|
63
|
+
const piecesFor = (skin) => {
|
|
64
|
+
const pieces = {};
|
|
65
|
+
for (const [slot, piece] of Object.entries(piecesOf(skin))) {
|
|
66
|
+
const shown = pieceShown.get(pieceKey(skin, slot));
|
|
67
|
+
if (piece.revision && !(shown?.revision === piece.revision && !shown.ok)) pieces[slot] = { revision: piece.revision };
|
|
68
|
+
}
|
|
69
|
+
return pieces;
|
|
70
|
+
};
|
|
71
|
+
const syncPieces = (target) => {
|
|
72
|
+
const skin = root.dataset.skin;
|
|
73
|
+
if (target && WORLDS[skin]) target.setPieces(skin, piecesFor(skin));
|
|
74
|
+
};
|
|
75
|
+
const pieceDrawn = ({ skin, slot, revision, ok }) => {
|
|
76
|
+
if (disposed || piecesOf(skin)[slot]?.revision !== revision) return;
|
|
77
|
+
const key = pieceKey(skin, slot), was = pieceShown.get(key);
|
|
78
|
+
if (was?.revision === revision && (!was.ok || was.ok === ok)) return;
|
|
79
|
+
pieceShown.set(key, { revision, ok });
|
|
80
|
+
if (!ok) for (const target of [renderer, pendingRenderer]) target?.setPieces(skin, piecesFor(skin));
|
|
81
|
+
worldSpot();
|
|
82
|
+
};
|
|
83
|
+
function worldStatus(skin) {
|
|
84
|
+
const world = controller.yardWorld(skin);
|
|
85
|
+
if (!world) return { state: 'original', text: 'Original' };
|
|
86
|
+
if (world.problem) return { state: 'failed', text: world.problem + ' Showing the original.' };
|
|
87
|
+
if (!customFor(skin)) return { state: 'failed', text: world.title + ' could not load. Showing the original.' };
|
|
88
|
+
return worldShown.get(skin) === world.revision ? { state: 'custom', text: 'Customized: ' + world.title } : { state: 'loading', text: 'Loading ' + world.title + '…' };
|
|
89
|
+
}
|
|
90
|
+
function pieceStatus(skin, slot) {
|
|
91
|
+
const piece = piecesOf(skin)[slot], kind = pieceKind(slot);
|
|
92
|
+
if (!piece) return { state: 'original', text: 'Original' };
|
|
93
|
+
if (piece.problem) return { state: 'failed', text: piece.problem + ' Showing the original ' + kind + '.' };
|
|
94
|
+
const shown = pieceShown.get(pieceKey(skin, slot));
|
|
95
|
+
if (shown?.revision !== piece.revision) return { state: 'loading', text: 'Loading ' + piece.title + '…' };
|
|
96
|
+
return shown.ok ? { state: 'custom', text: 'Customized: ' + piece.title } : { state: 'failed', text: piece.title + ' could not load. Showing the original ' + kind + '.' };
|
|
97
|
+
}
|
|
98
|
+
const slotName = (slot) => slot === 'world' ? 'World' : slot === 'companion' ? 'Companions' : snapshot.providers.find(p => p.id === slot)?.tool || CREWS[slot];
|
|
99
|
+
const customizeRows = new Map();
|
|
100
|
+
function customizeRow(slot) {
|
|
101
|
+
if (customizeRows.has(slot)) return customizeRows.get(slot);
|
|
102
|
+
const row = make('li', 'flag-row yard-customize-row'), copy = make('div', 'yard-customize-copy'), actions = make('div', 'yard-customize-actions');
|
|
103
|
+
const name = make('span', 'flag-name'), status = make('span', 'yard-customize-status'), note = make('span', 'yard-customize-note');
|
|
104
|
+
const replace = make('button', 'btn', 'Replace'), restore = make('button', 'btn', 'Restore original');
|
|
105
|
+
replace.type = restore.type = 'button';
|
|
106
|
+
note.hidden = slot === 'world';
|
|
107
|
+
const skin = () => root.dataset.skin;
|
|
108
|
+
replace.addEventListener('click', () => slot === 'world' ? controller.replaceYard(skin()) : controller.replacePiece(skin(), slot));
|
|
109
|
+
restore.addEventListener('click', () => slot === 'world' ? controller.restoreYard(skin()) : controller.restorePiece(skin(), slot));
|
|
110
|
+
copy.append(name, status, note);
|
|
111
|
+
actions.append(replace, restore);
|
|
112
|
+
row.append(copy, actions);
|
|
113
|
+
row.dataset.slot = slot;
|
|
114
|
+
const parts = { row, name, status, note, replace, restore };
|
|
115
|
+
customizeRows.set(slot, parts);
|
|
116
|
+
return parts;
|
|
117
|
+
}
|
|
118
|
+
function paintCustomize() {
|
|
119
|
+
const dialog = $('yard-customize'), skin = root.dataset.skin;
|
|
120
|
+
if (!dialog.open) return;
|
|
121
|
+
if (!WORLDS[skin]) { dialog.close(); return; }
|
|
122
|
+
$('yard-customize-sub').textContent = WORLDS[skin].title + ' only. Other Yards keep their own.';
|
|
123
|
+
const busy = Boolean(controller.yardBusy?.()) || !snapshot.connected;
|
|
124
|
+
const heading = (text) => {
|
|
125
|
+
if (!customizeRows.has(text)) { const item = make('li', 'yard-customize-heading', text); item.setAttribute('role', 'presentation'); customizeRows.set(text, item); }
|
|
126
|
+
return customizeRows.get(text);
|
|
127
|
+
};
|
|
128
|
+
const items = [];
|
|
129
|
+
for (const [title, slots] of [['Yard', ['world']], ['Characters', PROVIDER_ORDER], ['Companions', ['companion']]]) {
|
|
130
|
+
items.push(heading(title));
|
|
131
|
+
for (const slot of slots) {
|
|
132
|
+
const parts = customizeRow(slot), status = controller.yardChecking?.() === pieceKey(skin, slot) ? { state: 'loading', text: 'Checking replacement…' } : slot === 'world' ? worldStatus(skin) : pieceStatus(skin, slot);
|
|
133
|
+
const installed = slot === 'world' ? Boolean(controller.yardWorld(skin)) : Boolean(piecesOf(skin)[slot]);
|
|
134
|
+
parts.name.textContent = slotName(slot);
|
|
135
|
+
parts.status.textContent = status.text;
|
|
136
|
+
if (slot !== 'world') parts.note.textContent = slot === 'companion' ? 'Shows beside sessions with helpers in this Yard.'
|
|
137
|
+
: 'Shows on your ' + slotName(slot) + ' sessions in this Yard' + (slot === 'shell' ? ', and in gold on Terminal AI Chat’s.' : '.');
|
|
138
|
+
parts.row.dataset.state = status.state;
|
|
139
|
+
parts.replace.disabled = busy;
|
|
140
|
+
parts.restore.disabled = busy || !installed;
|
|
141
|
+
parts.replace.setAttribute('aria-label', 'Replace ' + slotName(slot));
|
|
142
|
+
parts.restore.setAttribute('aria-label', 'Restore the original ' + slotName(slot));
|
|
143
|
+
items.push(parts.row);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const list = $('yard-customize-list');
|
|
147
|
+
if (items.some((item, i) => list.children[i] !== item) || list.children.length !== items.length) {
|
|
148
|
+
const focused = list.contains(document.activeElement) ? document.activeElement : null;
|
|
149
|
+
list.replaceChildren(...items);
|
|
150
|
+
focused?.focus();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function worldSpot() {
|
|
154
|
+
const skin = root.dataset.skin;
|
|
155
|
+
if (!WORLDS[skin]) return;
|
|
156
|
+
const world = controller.yardWorld(skin);
|
|
157
|
+
$('yard-title').textContent = titleFor(skin);
|
|
158
|
+
$('yard-title').classList.toggle('yard-title-custom', Boolean(customFor(skin)));
|
|
159
|
+
const reason = world?.problem || (world && !customFor(skin) ? world.title + ' could not load.' : '');
|
|
160
|
+
const failed = !reason && Object.keys(piecesOf(skin)).map(slot => pieceStatus(skin, slot)).find(status => status.state === 'failed');
|
|
161
|
+
$('yard-customize-open').hidden = !controller.canReplaceYard();
|
|
162
|
+
$('yard-world-note').hidden = !reason && !failed;
|
|
163
|
+
$('yard-world-note').textContent = reason ? reason + ' This Yard is showing its original.' : failed ? failed.text : '';
|
|
164
|
+
paintCustomize();
|
|
165
|
+
}
|
|
32
166
|
const celebrate = () => { if (!disposed && sceneVisible()) renderer?.fireworks(); };
|
|
33
167
|
const fireworksButton = () => {
|
|
34
168
|
const button = $('yard-fireworks');
|
|
@@ -66,7 +200,7 @@ export function initYard(controller) {
|
|
|
66
200
|
if (allowed) yardChoice.parentElement.removeAttribute('title');
|
|
67
201
|
else yardChoice.parentElement.title = `${skinEntry()?.name || 'This skin'} has no yard yet.`;
|
|
68
202
|
$('yard').hidden = view !== 'yard';
|
|
69
|
-
if (view !== 'yard') closePhoto();
|
|
203
|
+
if (view !== 'yard') { closePhoto(); $('yard-customize').close(); }
|
|
70
204
|
$('providers').hidden = view === 'yard';
|
|
71
205
|
$('providers').inert = view === 'yard';
|
|
72
206
|
for (const section of document.querySelectorAll('#app > section.sessions, #app > section.news')) {
|
|
@@ -146,20 +280,24 @@ export function initYard(controller) {
|
|
|
146
280
|
select: next => select(next),
|
|
147
281
|
open: id => controller.openSession(id),
|
|
148
282
|
error: () => { if (attempt === sceneAttempt) failScene(); },
|
|
283
|
+
piece: pieceDrawn,
|
|
149
284
|
});
|
|
150
285
|
pendingRenderer = candidate;
|
|
151
286
|
// Appearance can change while the first world is loading.
|
|
152
|
-
let skin, theme;
|
|
287
|
+
let skin, theme, revision;
|
|
153
288
|
do {
|
|
154
289
|
skin = root.dataset.skin; theme = root.dataset.theme;
|
|
155
290
|
if (!WORLDS[skin]) { candidate.dispose(); return; }
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
291
|
+
revision = customFor(skin)?.revision ?? null;
|
|
292
|
+
syncPieces(candidate);
|
|
293
|
+
showLoading('Loading ' + titleFor(skin) + '…', 'scene');
|
|
294
|
+
await boundedLoad(progress => loadWorld(candidate, skin, theme, progress), loadingProgress);
|
|
295
|
+
} while (!disposed && !candidate.disposed && attempt === sceneAttempt && (skin !== root.dataset.skin || theme !== root.dataset.theme || revision !== (customFor(skin)?.revision ?? null)));
|
|
159
296
|
if (disposed || candidate.disposed || attempt !== sceneAttempt) { candidate.dispose(); return; }
|
|
297
|
+
syncPieces(candidate);
|
|
160
298
|
pendingRenderer = null;
|
|
161
299
|
renderer = candidate;
|
|
162
|
-
lastSkin = skin; lastTheme = theme;
|
|
300
|
+
lastSkin = skin; lastTheme = theme; lastRevision = revision;
|
|
163
301
|
renderer.setReducedMotion(motion.matches);
|
|
164
302
|
renderer.update(snapshot.providers, snapshot.sessions);
|
|
165
303
|
renderer.select(selected);
|
|
@@ -237,13 +375,13 @@ export function initYard(controller) {
|
|
|
237
375
|
// The current world stays up and usable while another loads, and after it
|
|
238
376
|
// fails. A swap that is ready almost at once shows no progress.
|
|
239
377
|
function swapWorld() {
|
|
240
|
-
const current = renderer, attempt = ++worldAttempt, title =
|
|
378
|
+
const current = renderer, attempt = ++worldAttempt, title = titleFor(lastSkin);
|
|
241
379
|
$('yard-swap-failure').hidden = true;
|
|
242
380
|
hideLoading();
|
|
243
381
|
showLoading('Loading ' + title + '…', 'swap');
|
|
244
382
|
swapReveal = setTimeout(() => { if (attempt === worldAttempt) $('yard-loading').hidden = false; }, 250);
|
|
245
383
|
const settle = () => renderer === current && attempt === worldAttempt && (hideLoading(), true);
|
|
246
|
-
boundedLoad(progress => current
|
|
384
|
+
boundedLoad(progress => loadWorld(current, lastSkin, lastTheme, progress), loadingProgress).then(() => {
|
|
247
385
|
if (!settle()) return;
|
|
248
386
|
current.update(snapshot.providers,snapshot.sessions); current.select(selected);
|
|
249
387
|
}).catch(() => {
|
|
@@ -267,7 +405,8 @@ export function initYard(controller) {
|
|
|
267
405
|
}
|
|
268
406
|
const world = WORLDS[root.dataset.skin];
|
|
269
407
|
if (!world) return;
|
|
270
|
-
|
|
408
|
+
const revision = customFor(root.dataset.skin)?.revision ?? null;
|
|
409
|
+
worldSpot();
|
|
271
410
|
$('yard-subtitle').textContent = world.subtitle;
|
|
272
411
|
const working = snapshot.sessions.filter(s => sessionPose(s) === 'working').length;
|
|
273
412
|
const running = snapshot.sessions.filter(s => s.status === 'running').length;
|
|
@@ -281,14 +420,15 @@ export function initYard(controller) {
|
|
|
281
420
|
$('yard-news-empty').hidden = Boolean(href);
|
|
282
421
|
if (href) { $('yard-headline').textContent = news.title; $('yard-headline').href = href; }
|
|
283
422
|
if (renderer) {
|
|
284
|
-
if (lastSkin !== root.dataset.skin || lastTheme !== root.dataset.theme) {
|
|
423
|
+
if (lastSkin !== root.dataset.skin || lastTheme !== root.dataset.theme || lastRevision !== revision) {
|
|
285
424
|
if (!WORLDS[root.dataset.skin]) return;
|
|
286
|
-
lastSkin = root.dataset.skin; lastTheme = root.dataset.theme;
|
|
425
|
+
lastSkin = root.dataset.skin; lastTheme = root.dataset.theme; lastRevision = revision;
|
|
287
426
|
swapWorld();
|
|
288
427
|
}
|
|
428
|
+
syncPieces(renderer);
|
|
289
429
|
renderer.update(snapshot.providers,snapshot.sessions);
|
|
290
430
|
renderer.setActive(sceneVisible());
|
|
291
|
-
} else ensureScene();
|
|
431
|
+
} else { syncPieces(pendingRenderer); ensureScene(); }
|
|
292
432
|
}
|
|
293
433
|
$('view-cards').addEventListener('change',() => setView('cards'));
|
|
294
434
|
$('view-yard').addEventListener('change',() => { if (skinAllowsYard()) setView('yard'); });
|
|
@@ -310,6 +450,12 @@ export function initYard(controller) {
|
|
|
310
450
|
lastSkin = ''; lastTheme = '';
|
|
311
451
|
update();
|
|
312
452
|
});
|
|
453
|
+
$('yard-customize-open').addEventListener('click',() => {
|
|
454
|
+
if (!$('yard-customize').open) $('yard-customize').showModal();
|
|
455
|
+
paintCustomize();
|
|
456
|
+
});
|
|
457
|
+
$('yard-customize-close').addEventListener('click',() => $('yard-customize').close());
|
|
458
|
+
$('yard-customize').addEventListener('click',event => { if (event.target === $('yard-customize')) $('yard-customize').close(); });
|
|
313
459
|
$('yard-filter').addEventListener('input',roster);
|
|
314
460
|
$('yard-news').addEventListener('click',controller.openNews);
|
|
315
461
|
$('yard-deselect').addEventListener('click',() => { select(null); $('yard-filter').focus(); });
|
package/web/yard/yard.css
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
.yard-heading > div:first-child::before { content:""; position:absolute; inset:-12px -22px -14px; z-index:-1; border-radius:28px; background:color-mix(in srgb,var(--bg) 72%,transparent); filter:blur(12px); }
|
|
16
16
|
.yard-eyebrow { margin:0 0 6px; font-size:9px; font-weight:650; letter-spacing:.22em; color:var(--gold); }
|
|
17
17
|
#yard-title { font-size:clamp(22px,2.2vw,34px); letter-spacing:.015em; text-shadow:0 2px 14px var(--bg); }
|
|
18
|
-
:root:is([data-skin="orbital"],[data-skin="gnomeland"],[data-skin="goblinville"]) #yard-title { font-size:min(clamp(22px,2.2vw,34px),max(22px,4.4cqi)); }
|
|
18
|
+
:root:is([data-skin="orbital"],[data-skin="gnomeland"],[data-skin="goblinville"],[data-skin="grove"],[data-skin="guild"],[data-skin="professional"]) #yard-title { font-size:min(clamp(22px,2.2vw,34px),max(22px,4.4cqi)); }
|
|
19
19
|
#yard-subtitle { margin:6px 0 0; font-size:12px; color:var(--muted); }
|
|
20
20
|
.yard-heading-side { align-self:flex-start; display:flex; flex-direction:column; align-items:flex-end; gap:10px; }
|
|
21
21
|
.yard-summary { margin-top:3px; font-size:11px; color:var(--text); padding:8px 11px; border:1px solid var(--yard-line); border-radius:30px; background:color-mix(in srgb,var(--surface) 75%,transparent); white-space:nowrap; }
|
|
@@ -46,7 +46,15 @@
|
|
|
46
46
|
.yard-crowd-pick:hover, .yard-crowd-open:hover { background:#1d3236; }
|
|
47
47
|
.yard-overlay { z-index:2; display:flex; flex-direction:column; align-items:center; gap:10px; padding:0 18px 10px; pointer-events:none; }
|
|
48
48
|
.yard-overlay > * { pointer-events:auto; max-width:100%; }
|
|
49
|
-
.yard-
|
|
49
|
+
.yard-overlay > .yard-bar { align-self:stretch; display:flex; flex-wrap:wrap-reverse; align-items:flex-start; justify-content:space-between; gap:8px; pointer-events:none; }
|
|
50
|
+
.yard-bar > * { pointer-events:auto; }
|
|
51
|
+
.yard-world { display:flex; flex-direction:column; align-items:flex-start; gap:5px; min-width:0; max-width:100%; }
|
|
52
|
+
.yard-world-actions { display:flex; flex-wrap:wrap; gap:5px; }
|
|
53
|
+
.yard-world .btn { min-height:30px; padding:5px 10px; font-size:11px; background:var(--surface); white-space:nowrap; text-decoration:none; }
|
|
54
|
+
.yard-world-note { margin:0; padding:4px 10px; max-width:340px; border-radius:8px; font-size:11px; color:var(--text); background:var(--surface); }
|
|
55
|
+
#yard-title.yard-title-custom { display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:2; overflow:hidden; overflow-wrap:anywhere; }
|
|
56
|
+
.folder-row.folder-file::before { border-radius:2px; border-style:dotted; }
|
|
57
|
+
.yard-camera { margin-left:auto; display:flex; gap:5px; flex-wrap:wrap; justify-content:flex-end; }
|
|
50
58
|
.yard-camera .btn { min-height:30px; padding:5px 10px; font-size:11px; background:var(--surface); white-space:nowrap; }
|
|
51
59
|
.yard-camera .btn svg { display:block; width:16px; height:16px; }
|
|
52
60
|
#yard-help { width:max-content; margin:6px 0 0; padding:4px 12px; border-radius:30px; font-size:10px; color:var(--muted); text-align:center; pointer-events:none; background:color-mix(in srgb,var(--surface) 80%,transparent); }
|
|
@@ -153,18 +161,27 @@
|
|
|
153
161
|
.yard-photo-footer p { flex:1 1 160px; min-width:0; margin:0; color:var(--muted); font-size:13px; }
|
|
154
162
|
|
|
155
163
|
.yard-play { --play-gold:#e8c47c; --play-ray:#e8c47c; --play-aura:#7c5cff; --play-h:46px; position:relative; display:none; isolation:isolate; border-radius:8px; }
|
|
156
|
-
:root[data-skin="orbital"] .yard-play:not(.yard-play-solo), :root:is([data-skin="gnomeland"],[data-skin="goblinville"]) .yard-play-solo { display:flex; }
|
|
164
|
+
:root[data-skin="orbital"] .yard-play:not(.yard-play-solo), :root:is([data-skin="gnomeland"],[data-skin="goblinville"]) .yard-play-solo:not(.yard-play-grove,.yard-play-arena,.yard-play-builders), :root[data-skin="grove"] .yard-play-grove:has(#yard-install:not([hidden])), :root[data-skin="guild"] .yard-play-arena, :root[data-skin="professional"] .yard-play-builders { display:flex; }
|
|
157
165
|
.yard-play-solo { --play-aura:#ff6a1f; }
|
|
166
|
+
.yard-play-grove { --play-aura:#6fae72; }
|
|
167
|
+
.yard-play-arena { --play-aura:#e8431c; }
|
|
168
|
+
.yard-play-builders { --play-aura:#2f6bed; }
|
|
158
169
|
:root[data-theme="light"] .yard-play { --play-ray:#b8893d; }
|
|
159
170
|
.yard-play:has(.yard-play-chip :focus-visible) { outline:2px solid var(--focus); outline-offset:3px; }
|
|
160
|
-
.yard-install { --play-h:46px; display:none; pointer-events:auto; padding:0; border:0; background:none; cursor:pointer; margin:calc(var(--play-h) * -42 / 128) calc(var(--play-h) * -46 / 128); }
|
|
161
|
-
:root[data-skin="grove"] .yard-install:not([hidden]) { display:block; }
|
|
162
|
-
.yard-install img { display:block; height:calc(var(--play-h) * 212 / 128); transition:filter .2s; }
|
|
163
|
-
.yard-install:hover:not(:disabled) img { filter:brightness(1.12); }
|
|
164
|
-
.yard-install:disabled { cursor:default; opacity:.6; }
|
|
165
|
-
.yard-install:focus-visible { outline:2px solid var(--focus); outline-offset:-12px; }
|
|
166
|
-
:root[data-theme="light"] .yard-install-dark, :root:not([data-theme="light"]) .yard-install-light { display:none; }
|
|
167
171
|
.yard-play-defs { position:absolute; width:0; height:0; overflow:hidden; }
|
|
172
|
+
.break-buttons { display:grid; gap:8px; padding-top:10px; border-top:1px solid var(--border); }
|
|
173
|
+
.break-buttons[hidden] { display:none; }
|
|
174
|
+
.break-label { margin:0; font-size:.8rem; color:var(--muted); }
|
|
175
|
+
.break-row { display:flex; flex-wrap:wrap; gap:8px; }
|
|
176
|
+
.break-row .yard-play { --play-h:46px; display:block; }
|
|
177
|
+
.break-row .yard-play-chip { --play-more-w:44px; }
|
|
178
|
+
.break-row .yard-play-link { padding:0 7px; }
|
|
179
|
+
.break-row .yard-play-more { padding:0; }
|
|
180
|
+
.break-row .yard-play-more::before { display:none; }
|
|
181
|
+
.break-row .yard-play-more-orb { display:block; grid-area:1 / 1; }
|
|
182
|
+
.break-row .yard-play-caret { grid-area:1 / 1; place-self:end; width:9px; height:6px; margin:0 7px 6px 0; stroke-width:2.2; }
|
|
183
|
+
.break-row .yard-play-orb { width:38px; height:38px; }
|
|
184
|
+
.break-row .armed .yard-play-chip { outline:2px solid var(--focus); outline-offset:2px; }
|
|
168
185
|
.yard-play-burst { position:absolute; left:50%; top:50%; width:calc(var(--play-h) * 7); height:calc(var(--play-h) * 2.6); translate:-50% -50%; pointer-events:none; z-index:0; opacity:.55; transition:opacity .3s;
|
|
169
186
|
background:radial-gradient(closest-side, color-mix(in srgb, var(--play-aura) 55%, transparent), color-mix(in srgb, var(--play-aura) 22%, transparent) 40%, transparent 72%);
|
|
170
187
|
-webkit-mask:radial-gradient(closest-side, #000 0, #000c 30%, #0004 55%, transparent 74%); mask:radial-gradient(closest-side, #000 0, #000c 30%, #0004 55%, transparent 74%); }
|
|
@@ -183,6 +200,23 @@
|
|
|
183
200
|
.yard-play-link { display:inline-flex; align-items:center; gap:10px; padding:0 16px 0 9px; color:#fff3cf; text-decoration:none; font-family:var(--font-display); }
|
|
184
201
|
.yard-play-link > * { position:relative; z-index:1; }
|
|
185
202
|
.yard-play-solo .yard-play-chip::before { background:radial-gradient(90px 60px at 12% 50%,#ff6a1f6b,transparent 70%),radial-gradient(90px 60px at 92% 50%,#3f9dff66,transparent 70%),linear-gradient(180deg,#171b2c,#0b0e17 55%,#05070e); }
|
|
203
|
+
.yard-play-arena .yard-play-chip::before { background:radial-gradient(90px 60px at 12% 50%,#e8431c6b,transparent 70%),radial-gradient(90px 60px at 92% 50%,#7a55e866,transparent 70%),linear-gradient(180deg,#231b14,#110d0a 55%,#080604); }
|
|
204
|
+
.yard-play-arena .yard-play-orb { width:38px; height:38px; }
|
|
205
|
+
.yard-play-arena .yard-play-sub { color:#c4b89f; }
|
|
206
|
+
.yard-play-builders .yard-play-chip::before { background:radial-gradient(120px 60px at 12% 50%,#2f6bed75,transparent 70%),linear-gradient(180deg,#1b2029,#0d1015 55%,#07090d); }
|
|
207
|
+
.yard-play-builders .yard-play-orb { width:38px; height:38px; }
|
|
208
|
+
.yard-play-builders .yard-play-sub { color:#a9b0c4; }
|
|
209
|
+
.yard-play-link > .yard-play-stamp { position:absolute; top:3px; right:13px; padding:0 4px; border:1px solid #ff4a3d; border-radius:2px; box-shadow:inset 0 0 0 1px #0d1015,inset 0 0 0 1.5px #ff4a3d; color:#ff4a3d; font:900 8.5px/12px var(--font-body,sans-serif); letter-spacing:.12em; text-transform:uppercase; rotate:-8deg; pointer-events:none; }
|
|
210
|
+
.break-row .yard-play-stamp { display:none; }
|
|
211
|
+
.yard-play-grove .yard-play-chip::before { background:radial-gradient(90px 60px at 12% 50%,#3b7550b0,transparent 70%),radial-gradient(90px 60px at 94% 50%,#7b9a3a66,transparent 70%),linear-gradient(180deg,#16261b,#0d1a12 55%,#081109); }
|
|
212
|
+
.yard-play-grove .yard-play-link { margin:0; border:0; border-radius:0; background:none; text-align:left; }
|
|
213
|
+
.yard-play-grove .yard-play-orb { position:relative; width:38px; height:38px; }
|
|
214
|
+
.yard-play-grove .yard-play-orb svg { display:block; width:100%; height:100%; overflow:visible; }
|
|
215
|
+
.yard-play-bird { position:absolute; inset:calc(50% - 10px); border-radius:50%; background:url(/skins/grove/ui/companion-bird.webp) center / 100% no-repeat; }
|
|
216
|
+
.yard-play-grove .yard-play-sub { color:#d6dcb4; }
|
|
217
|
+
.yard-play-grove .yard-play-chip:has(:disabled) { opacity:.6; translate:none; }
|
|
218
|
+
.yard-play-grove:has(:disabled) .yard-play-burst { display:none; }
|
|
219
|
+
.yard-play-grove .yard-play-link:disabled { background:none; cursor:default; }
|
|
186
220
|
.yard-play-more { display:grid; place-items:center; flex:none; width:var(--play-more-w); margin:0; padding:0 3px 0 0; border:0; border-radius:0; background:none; color:var(--play-gold); }
|
|
187
221
|
.yard-play-more::before { content:""; position:absolute; left:0; top:9px; bottom:9px; width:1px; background:linear-gradient(180deg,transparent,#f6dc9c,transparent); }
|
|
188
222
|
.yard-play-link:hover { background:#e8c47c14; }
|
|
@@ -213,12 +247,21 @@
|
|
|
213
247
|
.yard-play-chev path:nth-child(3) { animation-delay:.4s; }
|
|
214
248
|
.yard-play-solo .yard-play-chev path:nth-child(1) { stroke:#ffb45e; }
|
|
215
249
|
.yard-play-solo .yard-play-chev path:nth-child(3) { stroke:#bfe6ff; }
|
|
250
|
+
.yard-play-grove .yard-play-chev path:nth-child(n) { stroke:#d7ee6e; }
|
|
251
|
+
.yard-play-builders .yard-play-chev path:nth-child(n) { stroke:#e8c47c; }
|
|
252
|
+
.yard-play-arena .yard-play-chev path:nth-child(1) { stroke:#ff9d4d; }
|
|
253
|
+
.yard-play-arena .yard-play-chev path:nth-child(2) { stroke:#f6dc9c; }
|
|
254
|
+
.yard-play-arena .yard-play-chev path:nth-child(3) { stroke:#cfc0ff; }
|
|
216
255
|
@keyframes yard-play-spin { to { transform:rotate(360deg); } }
|
|
217
256
|
@keyframes yard-play-sweep { 0% { left:-30%; } 55%,100% { left:130%; } }
|
|
218
257
|
@keyframes yard-play-pulse { 0%,100% { opacity:.45; transform:scale(.94); } 50% { opacity:.9; transform:scale(1.06); } }
|
|
219
258
|
@keyframes yard-play-chev { 0%,100% { opacity:.35; } 40% { opacity:1; } }
|
|
220
|
-
@container (max-width:660px) { :root:is([data-skin="orbital"],[data-skin="gnomeland"],[data-skin="goblinville"]) .yard-heading { padding-inline:18px; } :root:is([data-skin="orbital"],[data-skin="gnomeland"],[data-skin="goblinville"]) .yard-summary { display:none; } .yard-play { --play-h:44px; } .yard-play-chip { --play-more-w:40px; } .yard-play-chev, .yard-play-sub-more { display:none; } }
|
|
259
|
+
@container (max-width:660px) { :root:is([data-skin="orbital"],[data-skin="gnomeland"],[data-skin="goblinville"],[data-skin="grove"],[data-skin="guild"],[data-skin="professional"]) .yard-heading { padding-inline:18px; } :root:is([data-skin="orbital"],[data-skin="gnomeland"],[data-skin="goblinville"],[data-skin="grove"],[data-skin="guild"],[data-skin="professional"]) .yard-summary { display:none; } .yard-play { --play-h:44px; } .yard-play-chip { --play-more-w:40px; } .yard-play-chev, .yard-play-sub-more { display:none; } }
|
|
260
|
+
@container (max-width:660px) { .yard-play-stamp { display:none; } }
|
|
261
|
+
@container (max-width:520px) { .yard-play-builders .yard-play-now { display:none; } }
|
|
262
|
+
@container (max-width:460px) { .yard-play-builders .yard-play-text { display:none; } .yard-play-builders .yard-play-link { padding:0 7px; } }
|
|
263
|
+
@container (max-width:360px) { :root[data-skin="professional"] #yard-title { font-size:20px; } }
|
|
221
264
|
@container (max-width:480px) { .yard-play-sub, .yard-play-now { display:none; } }
|
|
222
265
|
@container (max-width:440px) { .yard-play-text { display:none; } .yard-play-link { padding:0 7px; } }
|
|
223
266
|
@container (max-width:380px) { .yard-play:not(.yard-play-solo) .yard-play-link { display:none; } .yard-play-chip { --play-more-w:44px; } .yard-play-more { padding:0; } .yard-play-more::before { display:none; } .yard-play-more-orb { display:block; grid-area:1 / 1; } .yard-play-caret { grid-area:1 / 1; place-self:end; width:9px; height:6px; margin:0 7px 6px 0; stroke-width:2.2; } }
|
|
224
|
-
@container (max-width:340px) { :root:is([data-skin="orbital"],[data-skin="gnomeland"],[data-skin="goblinville"]) :is(.yard-eyebrow, #yard-subtitle) { display:none; } }
|
|
267
|
+
@container (max-width:340px) { :root:is([data-skin="orbital"],[data-skin="gnomeland"],[data-skin="goblinville"],[data-skin="grove"],[data-skin="guild"],[data-skin="professional"]) :is(.yard-eyebrow, #yard-subtitle) { display:none; } }
|