@kevin5251984/guild 0.2.12 → 0.2.13

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.
@@ -341,26 +341,6 @@ button.danger {
341
341
  border-color: #4a2a2a;
342
342
  }
343
343
  button:disabled { opacity: 0.45; }
344
- button.is-busy:disabled {
345
- opacity: 1;
346
- cursor: wait;
347
- pointer-events: none;
348
- }
349
- button.is-busy::after {
350
- content: "";
351
- display: inline-block;
352
- width: 0.7em;
353
- height: 0.7em;
354
- margin-left: 0.45em;
355
- border: 1.5px solid currentColor;
356
- border-right-color: transparent;
357
- border-radius: 50%;
358
- vertical-align: -0.12em;
359
- animation: btn-spin 0.7s linear infinite;
360
- }
361
- @keyframes btn-spin {
362
- to { transform: rotate(360deg); }
363
- }
364
344
 
365
345
  .grid { display: grid; gap: 1rem; }
366
346
  @media (min-width: 760px) {
@@ -1072,28 +1052,15 @@ body.app.bar-page .shell {
1072
1052
  padding: 0 0 0.4rem;
1073
1053
  }
1074
1054
  .rpg-screen {
1075
- display: grid;
1076
- grid-template-rows: auto auto;
1077
1055
  position: relative;
1056
+ aspect-ratio: 16 / 9;
1078
1057
  overflow: hidden;
1079
1058
  background: #000;
1080
1059
  border: 4px solid #0a0a12;
1081
1060
  box-shadow: 8px 8px 0 #000;
1082
1061
  image-rendering: pixelated;
1083
1062
  }
1084
- body.bar-page .rpg-screen {
1085
- background: #1a1410;
1086
- border-color: #1a1410;
1087
- box-shadow: 8px 8px 0 #1a1410;
1088
- }
1089
- .rpg-scene {
1090
- grid-row: 1;
1091
- grid-column: 1;
1092
- position: relative;
1093
- aspect-ratio: 16 / 9;
1094
- min-height: 0;
1095
- overflow: hidden;
1096
- }
1063
+ .rpg-scene { position: absolute; inset: 0; }
1097
1064
  .rpg-scene[hidden] { display: none; }
1098
1065
  .rpg-bg {
1099
1066
  display: block;
@@ -1135,216 +1102,120 @@ body.bar-page .rpg-screen {
1135
1102
  .inn-map {
1136
1103
  position: absolute;
1137
1104
  inset: 0;
1138
- background-color: #3d6b52;
1139
- background-image: repeating-conic-gradient(#3d6b52 0% 25%, #335c46 0% 50%);
1140
- background-size: 16px 16px;
1105
+ background-color: #3f3f48;
1106
+ background-image:
1107
+ linear-gradient(#2a1812 0 70px, transparent 70px),
1108
+ repeating-linear-gradient(90deg, transparent 0 15px, #35353c 15px 16px),
1109
+ repeating-linear-gradient(transparent 0 15px, #35353c 15px 16px);
1141
1110
  }
1142
1111
  .inn-wall {
1143
1112
  position: absolute;
1144
1113
  left: 0;
1145
1114
  right: 0;
1146
1115
  top: 0;
1147
- height: 56px;
1148
- display: flex;
1149
- align-items: flex-end;
1150
- justify-content: center;
1151
- gap: 28px;
1152
- padding: 0 12px 8px;
1153
- background:
1154
- linear-gradient(#1c2a44 0 14px, transparent 14px),
1155
- repeating-linear-gradient(#6b5340 0 14px, #5a4534 14px 16px);
1156
- box-shadow: inset 0 -4px 0 #1a1410;
1157
- z-index: 1;
1158
- }
1159
- .inn-window {
1160
- width: 42px;
1161
- height: 28px;
1116
+ height: 70px;
1162
1117
  background:
1163
- linear-gradient(#0b1020 0 5px, transparent 5px) 0 12px / 100% 2px no-repeat,
1164
- linear-gradient(90deg, #0b1020 0 2px, transparent 2px) 20px 0 / 2px 100% no-repeat,
1165
- linear-gradient(#2a3a6a, #12182c);
1166
- box-shadow: inset 0 0 0 3px #2a2118, 0 0 0 2px #1a1410;
1118
+ repeating-linear-gradient(90deg, #3a2218 0 40px, #2a1812 40px 44px),
1119
+ linear-gradient(#4a2c20, #2a1812);
1120
+ box-shadow: inset 0 -6px 0 #1a100c;
1167
1121
  }
1168
- .inn-nook {
1122
+ .inn-rail {
1169
1123
  position: absolute;
1170
- top: 56px;
1171
- bottom: 0;
1172
- width: 56px;
1173
- display: flex;
1174
- flex-direction: column;
1175
- align-items: center;
1176
- justify-content: space-evenly;
1177
- z-index: 1;
1178
- background:
1179
- repeating-linear-gradient(90deg, #2a4638 0 14px, #244032 14px 16px);
1180
- background-size: 16px 16px;
1181
- }
1182
- .inn-nook-l { left: 0; border-right: 2px solid #1a2a22; }
1183
- .inn-nook-r { right: 0; border-left: 2px solid #1a2a22; }
1184
- .inn-prop.plant {
1185
- width: 28px;
1186
- height: 36px;
1187
- background:
1188
- linear-gradient(#3d8c4a 0 14px, transparent 14px),
1189
- linear-gradient(#8a5a32 0 100%);
1190
- background-position: center 0, center 16px;
1191
- background-repeat: no-repeat;
1192
- background-size: 18px 16px, 8px 20px;
1124
+ left: 0;
1125
+ right: 0;
1126
+ top: 64px;
1127
+ height: 10px;
1128
+ background: #6b4228;
1129
+ box-shadow: 0 4px 0 #3a2414;
1193
1130
  }
1194
1131
  .inn-bar {
1195
- width: 36px;
1196
- height: 48%;
1132
+ position: absolute;
1133
+ right: 4%;
1134
+ top: 18%;
1135
+ width: 20%;
1136
+ height: 62%;
1197
1137
  background: #6b3e22;
1198
- box-shadow: inset 0 0 0 3px #4a2814, 4px 4px 0 #2a160e;
1138
+ box-shadow: inset 0 0 0 4px #4a2814, 6px 6px 0 #2a160e;
1199
1139
  }
1200
1140
  .inn-bottles {
1141
+ position: absolute;
1142
+ right: 6%;
1143
+ top: 12%;
1201
1144
  display: flex;
1202
- gap: 4px;
1145
+ gap: 6px;
1203
1146
  align-items: flex-end;
1204
- height: 22px;
1147
+ height: 28px;
1148
+ z-index: 1;
1205
1149
  }
1206
1150
  .inn-bottles span {
1207
- width: 6px;
1208
- height: 16px;
1209
- box-shadow: 0 -4px 0 -2px #e8e8e8;
1151
+ width: 7px;
1152
+ height: 18px;
1153
+ box-shadow: 0 -5px 0 -2px #e8e8e8;
1210
1154
  }
1211
- .inn-actors {
1155
+ .inn-table {
1212
1156
  position: absolute;
1213
- top: 56px;
1214
- left: 56px;
1215
- right: 56px;
1216
- bottom: 0;
1217
- z-index: 2;
1218
- display: grid;
1219
- grid-template-columns: repeat(4, minmax(0, 1fr));
1220
- align-content: start;
1221
- justify-items: center;
1222
- gap: 12px 6px;
1223
- padding: 22px 0 10px;
1224
- overflow: auto;
1225
- }
1226
- .inn-station {
1227
- position: relative;
1228
- display: flex;
1229
- flex-direction: column;
1230
- align-items: center;
1231
- width: 88px;
1232
- z-index: 2;
1233
- }
1234
- @media (max-width: 720px) {
1235
- .inn-actors {
1236
- left: 8px;
1237
- right: 8px;
1238
- grid-template-columns: repeat(3, minmax(0, 1fr));
1239
- }
1240
- }
1241
- @media (max-width: 480px) {
1242
- .inn-actors { grid-template-columns: repeat(2, minmax(0, 1fr)); }
1243
- }
1244
- .inn-desk {
1245
- order: 2;
1246
- position: relative;
1247
- width: 72px;
1248
- height: 20px;
1249
- margin-top: -8px;
1250
- background: #8a5a32;
1251
- box-shadow: 0 3px 0 #6a4020, 0 5px 0 #3a2414, inset 0 2px 0 #b07a48;
1252
- z-index: 1;
1157
+ width: 56px;
1158
+ height: 36px;
1159
+ background: #7a4a28;
1160
+ box-shadow: 8px 10px 0 -4px #3a2414, inset 0 0 0 3px #5a3218;
1161
+ border-radius: 40% 40% 30% 30%;
1253
1162
  }
1254
- .inn-monitor {
1163
+ .inn-table.t1 { left: 10%; top: 28%; }
1164
+ .inn-table.t2 { left: 28%; top: 22%; }
1165
+ .inn-barrel {
1255
1166
  position: absolute;
1256
- left: 50%;
1257
- bottom: 14px;
1258
1167
  width: 28px;
1259
- height: 18px;
1260
- margin-left: -14px;
1261
- background: #1a1a1a;
1262
- box-shadow: 0 0 0 2px #111;
1263
- }
1264
- .inn-monitor::after {
1265
- content: "";
1168
+ height: 32px;
1169
+ background: repeating-linear-gradient(#8a5a32 0 6px, #5a3218 6px 8px);
1170
+ border-radius: 40%;
1171
+ box-shadow: 3px 3px 0 #1a1008;
1172
+ }
1173
+ .inn-barrel.b1 { left: 6%; bottom: 28%; }
1174
+ .inn-barrel.b2 { left: 72%; top: 24%; }
1175
+ .inn-hearth {
1266
1176
  position: absolute;
1267
- inset: 3px 3px 4px;
1268
- background: repeating-linear-gradient(#7ec8e8 0 2px, #4aa3c8 2px 4px);
1177
+ left: 4%;
1178
+ top: 8%;
1179
+ width: 54px;
1180
+ height: 48px;
1181
+ background: #2a1c18;
1182
+ box-shadow: inset 0 0 0 4px #1a100c, inset 0 0 12px #e07020;
1269
1183
  }
1270
- .inn-station:has(.rpg-npc.vacant) .inn-monitor::after { background: #2a2a2a; }
1184
+ .inn-actors { position: absolute; inset: 0; z-index: 2; }
1271
1185
  .rpg-npc {
1272
- position: relative;
1186
+ position: absolute;
1273
1187
  display: flex;
1274
1188
  flex-direction: column;
1275
1189
  align-items: center;
1276
- order: 1;
1277
1190
  margin: 0;
1278
1191
  padding: 0;
1279
1192
  border: 0;
1280
1193
  background: transparent;
1281
1194
  color: inherit;
1195
+ transform: translate(-50%, -88%);
1282
1196
  cursor: pointer;
1283
1197
  z-index: 2;
1284
1198
  }
1285
- .rpg-npc .npc-bust,
1286
- .rpg-npc .npc-blank {
1287
- width: 72px;
1199
+ .rpg-npc canvas {
1200
+ width: 48px;
1288
1201
  height: 72px;
1289
- box-sizing: border-box;
1290
- border: 3px solid #1a1410;
1291
- background: #2a2118;
1292
- box-shadow: 2px 3px 0 #0006;
1293
- }
1294
- .rpg-npc .npc-bust {
1295
- object-fit: cover;
1296
- object-position: center 18%;
1297
- display: block;
1298
- }
1299
- .rpg-npc .npc-blank {
1300
- display: grid;
1301
- place-items: center;
1302
- color: #f0d9a0;
1303
- font-family: VT323, ui-monospace, monospace;
1304
- font-size: 28px;
1305
- line-height: 1;
1306
- }
1307
- .rpg-npc.drawing .npc-bust,
1308
- .rpg-npc.drawing .npc-blank {
1309
- filter: brightness(1.25) drop-shadow(0 0 6px #f0d060);
1202
+ image-rendering: pixelated;
1203
+ filter: drop-shadow(2px 3px 0 #0008);
1204
+ animation: bob 1.1s steps(2) infinite;
1310
1205
  }
1311
1206
  .rpg-npc .tag {
1312
- order: 3;
1313
- margin-top: 6px;
1207
+ margin-top: 2px;
1314
1208
  padding: 1px 5px;
1315
- background: #1a1410;
1316
- color: #f0d9a0;
1209
+ background: #000c;
1210
+ color: #f4f0e0;
1317
1211
  font-family: VT323, ui-monospace, monospace;
1318
1212
  font-size: 15px;
1319
1213
  line-height: 1.1;
1320
1214
  white-space: nowrap;
1321
- z-index: 3;
1322
1215
  }
1323
- .npc-state {
1324
- position: absolute;
1325
- top: 0;
1326
- left: 50%;
1327
- z-index: 4;
1328
- padding: 0 5px;
1329
- border: 0;
1330
- background: #f4ead7;
1331
- color: #1a1410;
1332
- font-family: VT323, ui-monospace, monospace;
1333
- font-size: 14px;
1334
- line-height: 1.2;
1335
- white-space: nowrap;
1336
- box-shadow: 2px 2px 0 #1a1410;
1337
- transform: translate(-50%, calc(-100% - 4px));
1338
- }
1339
- .npc-state.live {
1340
- background: var(--signal);
1341
- color: #1a1410;
1342
- }
1343
- .rpg-npc:hover .npc-bust,
1344
- .rpg-npc:hover .npc-blank { filter: brightness(1.18) drop-shadow(0 0 6px #f0d060); }
1345
- .rpg-npc.on .npc-bust,
1346
- .rpg-npc.on .npc-blank { outline: 2px solid #f0d060; outline-offset: 1px; }
1347
- .rpg-npc.vacant .npc-blank { opacity: 0.55; }
1216
+ .rpg-npc:hover canvas { filter: brightness(1.18) drop-shadow(0 0 6px #f0d060); }
1217
+ .rpg-npc.on canvas { outline: 2px solid #f0d060; outline-offset: 1px; }
1218
+ .rpg-npc.vacant canvas { opacity: 0.35; }
1348
1219
  .rpg-npc.vacant .tag { color: #f0d060; }
1349
1220
  .rpg-exit {
1350
1221
  position: absolute;
@@ -1361,47 +1232,21 @@ body.bar-page .rpg-screen {
1361
1232
  cursor: pointer;
1362
1233
  }
1363
1234
  .rpg-exit:hover { background: #2a3460; }
1364
- body.bar-page .rpg-exit {
1365
- border-color: #1a1410;
1366
- background: #f4ead7;
1367
- color: #1a1410;
1368
- }
1369
- body.bar-page .rpg-exit:hover { background: #e8dcc4; }
1370
1235
  .rpg-dialog {
1371
- grid-row: 2;
1372
- position: relative;
1236
+ position: absolute;
1237
+ left: 3.5%;
1238
+ right: 3.5%;
1239
+ bottom: 3%;
1373
1240
  z-index: 5;
1374
- margin: 8px 12px 10px;
1375
1241
  padding: 3px;
1376
1242
  background: #08080f;
1377
1243
  box-shadow: 0 0 0 2px #c9a227, inset 0 0 0 2px #3a4a8a;
1378
1244
  }
1379
- body.bar-page .rpg-dialog {
1380
- background: #1a1410;
1381
- box-shadow: 0 0 0 3px #1a1410, 4px 4px 0 #1a1410;
1382
- }
1383
1245
  .rpg-dialog-inner {
1384
- display: flex;
1385
- align-items: flex-start;
1386
- gap: 10px;
1387
1246
  min-height: 92px;
1388
1247
  padding: 10px 14px 8px;
1389
1248
  background: linear-gradient(#2a3668, #1a2248 55%, #141a3a);
1390
1249
  }
1391
- .rpg-face {
1392
- flex: none;
1393
- width: 56px;
1394
- height: 56px;
1395
- object-fit: cover;
1396
- object-position: center 18%;
1397
- border: 3px solid #1a1410;
1398
- background: #2a2118;
1399
- }
1400
- .rpg-face[hidden] { display: none; }
1401
- .rpg-copy { min-width: 0; flex: 1; }
1402
- body.bar-page .rpg-dialog-inner {
1403
- background: #f4ead7;
1404
- }
1405
1250
  .rpg-name {
1406
1251
  margin: 0 0 6px;
1407
1252
  color: #f0d060;
@@ -1416,44 +1261,27 @@ body.bar-page .rpg-dialog-inner {
1416
1261
  font-family: VT323, ui-monospace, monospace;
1417
1262
  font-size: 22px;
1418
1263
  line-height: 1.2;
1419
- overflow-wrap: anywhere;
1420
1264
  }
1421
- body.bar-page .rpg-name { color: #6b4228; }
1422
- body.bar-page .rpg-line { color: #1a1410; }
1423
1265
  .rpg-acts {
1424
1266
  display: flex;
1425
- flex-wrap: wrap;
1426
1267
  gap: 8px;
1427
1268
  margin-top: 8px;
1428
1269
  min-height: 22px;
1429
1270
  }
1430
1271
  .rpg-acts a,
1431
1272
  .rpg-acts button {
1432
- appearance: none;
1433
1273
  margin: 0;
1434
1274
  padding: 3px 8px;
1435
1275
  border: 2px solid #c9a227;
1436
- border-radius: 0;
1437
1276
  background: #141a3a;
1438
1277
  color: #f4f0e0;
1439
1278
  font-family: VT323, ui-monospace, monospace;
1440
1279
  font-size: 18px;
1441
- font-weight: 400;
1442
- line-height: 1.2;
1443
1280
  text-decoration: none;
1444
- box-shadow: none;
1445
1281
  cursor: pointer;
1446
1282
  }
1447
1283
  .rpg-acts a:hover,
1448
1284
  .rpg-acts button:hover { background: #2a3460; text-decoration: none; }
1449
- body.bar-page .rpg-acts a,
1450
- body.bar-page .rpg-acts button {
1451
- border-color: #1a1410;
1452
- background: #f4ead7;
1453
- color: #1a1410;
1454
- }
1455
- body.bar-page .rpg-acts a:hover,
1456
- body.bar-page .rpg-acts button:hover { background: #e8dcc4; }
1457
1285
 
1458
1286
  body.office-page {
1459
1287
  background: #1a1714;
@@ -1575,7 +1403,7 @@ body.office-page {
1575
1403
  inset 0 2px 0 #b07a48;
1576
1404
  position: relative;
1577
1405
  z-index: 2;
1578
- margin-top: -40px;
1406
+ margin-top: -28px;
1579
1407
  }
1580
1408
  .monitor {
1581
1409
  position: absolute;
@@ -1594,8 +1422,8 @@ body.office-page {
1594
1422
  background: repeating-linear-gradient(#7ec8e8 0 2px, #4aa3c8 2px 4px);
1595
1423
  }
1596
1424
  .buddy {
1597
- width: 72px;
1598
- height: 128px;
1425
+ width: 64px;
1426
+ height: 96px;
1599
1427
  position: relative;
1600
1428
  z-index: 1;
1601
1429
  image-rendering: pixelated;
@@ -91,12 +91,7 @@
91
91
  return;
92
92
  }
93
93
  const button = document.getElementById("ai-generate");
94
- if (button.disabled || button.getAttribute("aria-busy") === "true") return;
95
94
  button.disabled = true;
96
- button.setAttribute("aria-busy", "true");
97
- button.classList.add("is-busy");
98
- const idle = button.textContent;
99
- button.textContent = t("studio.generating");
100
95
  try {
101
96
  const response = await fetch("/generate", {
102
97
  method: "POST",
@@ -120,9 +115,6 @@
120
115
  setFlash("error", err.message);
121
116
  } finally {
122
117
  button.disabled = false;
123
- button.removeAttribute("aria-busy");
124
- button.classList.remove("is-busy");
125
- button.textContent = idle;
126
118
  }
127
119
  });
128
120
  document.getElementById("ai-save").addEventListener("click", async () => {
package/src/router.ts CHANGED
@@ -18,7 +18,6 @@ import {
18
18
  setChannelMemory,
19
19
  generateKind,
20
20
  pickBotSkills,
21
- generateBotLook,
22
21
  getBotDetail,
23
22
  getLiveTurn,
24
23
  abortLiveTurn,
@@ -78,7 +77,6 @@ const PAGES: Record<string, { file: string; type: string }> = {
78
77
  "/chat.css": { file: "chat.css", type: "text/css; charset=utf-8" },
79
78
  "/md.js": { file: "md.js", type: "text/javascript; charset=utf-8" },
80
79
  "/i18n.js": { file: "i18n.js", type: "text/javascript; charset=utf-8" },
81
- "/buddy.js": { file: "buddy.js", type: "text/javascript; charset=utf-8" },
82
80
  "/favicon.ico": { file: "favicon.ico", type: "image/x-icon" },
83
81
  "/favicon.svg": { file: "favicon.svg", type: "image/svg+xml" },
84
82
  "/favicon-16.svg": { file: "favicon-16.svg", type: "image/svg+xml" },
@@ -893,12 +891,6 @@ export async function handleRequest(
893
891
  return;
894
892
  }
895
893
 
896
- const lookId = path.match(/^\/bots\/([^/]+)\/look$/)?.[1];
897
- if (lookId && method === "POST") {
898
- json(res, 200, await generateBotLook(store, decodeURIComponent(lookId), env));
899
- return;
900
- }
901
-
902
894
  const botId = path.match(/^\/bots\/([^/]+)$/)?.[1];
903
895
  if (botId && method === "GET") {
904
896
  json(res, 200, getBotDetail(store, botId));
@@ -914,9 +906,6 @@ export async function handleRequest(
914
906
  name: str(body, "name") || undefined,
915
907
  handle: str(body, "handle") || undefined,
916
908
  oneLiner: str(body, "oneLiner") || undefined,
917
- ...(Object.hasOwn(body, "portrait")
918
- ? { portrait: body.portrait == null ? null : str(body, "portrait") }
919
- : {}),
920
909
  skillIds: Object.hasOwn(body, "skillIds")
921
910
  ? strList(body, "skillIds")
922
911
  : undefined,
package/src/store.ts CHANGED
@@ -605,7 +605,6 @@ export class GuildStore {
605
605
  name?: string;
606
606
  handle?: string;
607
607
  oneLiner?: string;
608
- portrait?: string | null;
609
608
  skillIds?: string[];
610
609
  soul?: { name: string; body: string };
611
610
  agent?: { name: string; body: string };
@@ -647,9 +646,6 @@ export class GuildStore {
647
646
  handle,
648
647
  skillIds,
649
648
  oneLiner: input.oneLiner?.trim() || bot.oneLiner,
650
- portrait: Object.hasOwn(input, "portrait")
651
- ? normalizePortrait(input.portrait)
652
- : bot.portrait,
653
649
  model: Object.hasOwn(input, "model") ? input.model ?? null : bot.model,
654
650
  };
655
651
  this.writeBot(next);
@@ -1173,16 +1169,6 @@ export class GuildStore {
1173
1169
  }
1174
1170
  }
1175
1171
 
1176
- function normalizePortrait(raw: string | null | undefined): string | undefined {
1177
- if (raw == null) return undefined;
1178
- const value = raw.trim();
1179
- if (!value) return undefined;
1180
- if (!/^\/generated\/[A-Za-z0-9._-]+$/.test(value)) {
1181
- throw new StoreError(400, "invalid portrait");
1182
- }
1183
- return value;
1184
- }
1185
-
1186
1172
  export class StoreError extends Error {
1187
1173
  constructor(
1188
1174
  readonly status: number,