@khorsheed/dsh-game 0.1.0 → 0.1.1
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/CHANGELOG.md +8 -0
- package/lib/client.js +637 -295
- package/lib/index.js +144 -1
- package/lib/typert.host.js +142 -35
- package/lib/typert.remote-client.d.ts +4 -1
- package/lib/typert.remote-client.js +81 -25
- package/lib/types/agent.js +2 -1
- package/lib/types/client/DesignView.js +3 -3
- package/lib/types/client/ElementsView.js +13 -5
- package/lib/types/client/GameTab.js +11 -6
- package/lib/types/client/PlayView.js +3 -1
- package/lib/types/client/Preview3D.d.ts +3 -1
- package/lib/types/client/Preview3D.js +4 -2
- package/lib/types/client/ProjectSwitcher.js +2 -2
- package/lib/types/client/contract.d.ts +7 -1
- package/lib/types/client/index.js +34 -0
- package/lib/types/client/locales.d.ts +3 -0
- package/lib/types/client/locales.js +6 -0
- package/lib/types/client/preview-entry.d.ts +1 -1
- package/lib/types/client/preview-entry.js +4 -1
- package/lib/types/client/reveal.d.ts +43 -0
- package/lib/types/client/reveal.js +73 -0
- package/lib/types/project.d.ts +6 -0
- package/lib/types/project.js +10 -0
- package/lib/types/remote.d.ts +3 -1
- package/lib/types/remote.js +7 -0
- package/lib/types/skills.js +1 -0
- package/lib/types/store.d.ts +22 -1
- package/lib/types/store.js +99 -1
- package/lib/types/tools.js +15 -7
- package/lib/types/types.d.ts +26 -0
- package/lib/types/vfs.d.ts +2 -0
- package/package.json +1 -1
|
@@ -197,6 +197,26 @@ const _khorsheed_dsh_game_game_finalizeParams_result$schema = () => (_khorsheed_
|
|
|
197
197
|
}), z.object({
|
|
198
198
|
'ok': z.literal(true).readonly(),
|
|
199
199
|
})]))
|
|
200
|
+
let _khorsheed_dsh_game_game_liveVersion_parameter_0$schema$value
|
|
201
|
+
const _khorsheed_dsh_game_game_liveVersion_parameter_0$schema = () => (_khorsheed_dsh_game_game_liveVersion_parameter_0$schema$value ??= z.string())
|
|
202
|
+
let _khorsheed_dsh_game_game_liveVersion_result$schema$value
|
|
203
|
+
const _khorsheed_dsh_game_game_liveVersion_result$schema = () => (_khorsheed_dsh_game_game_liveVersion_result$schema$value ??= z.union([z.literal(null), z.object({
|
|
204
|
+
'projectId': z.string().readonly(),
|
|
205
|
+
'version': z.number().readonly(),
|
|
206
|
+
'kind': z.union([z.literal("none"), z.literal("candidate"), z.literal("deployed")]).readonly(),
|
|
207
|
+
'at': z.union([z.literal(null), z.string()]).readonly(),
|
|
208
|
+
'by': z.union([z.literal("user"), z.literal("agent"), z.literal("turn")]).readonly().optional(),
|
|
209
|
+
'show': z.object({
|
|
210
|
+
'seq': z.number().readonly(),
|
|
211
|
+
'target': z.object({
|
|
212
|
+
'view': z.union([z.literal("versions"), z.literal("play"), z.literal("elements"), z.literal("design")]).readonly(),
|
|
213
|
+
'elementId': z.string().readonly().optional(),
|
|
214
|
+
'chapterId': z.string().readonly().optional(),
|
|
215
|
+
}).readonly(),
|
|
216
|
+
'note': z.string().readonly().describe('What to look at, in the agent\'s words (shown with the notice).'),
|
|
217
|
+
'at': z.string().readonly(),
|
|
218
|
+
}).readonly().optional().describe('The agent\'s latest request to show the user something, if any since the host started.'),
|
|
219
|
+
})]))
|
|
200
220
|
let _khorsheed_dsh_game_game_logPlay_parameter_0$schema$value
|
|
201
221
|
const _khorsheed_dsh_game_game_logPlay_parameter_0$schema = () => (_khorsheed_dsh_game_game_logPlay_parameter_0$schema$value ??= z.string())
|
|
202
222
|
let _khorsheed_dsh_game_game_logPlay_parameter_1$schema$value
|
|
@@ -490,6 +510,7 @@ const _khorsheed_dsh_game_game_state_result$schema = () => (_khorsheed_dsh_game_
|
|
|
490
510
|
}).readonly().optional(),
|
|
491
511
|
})]).readonly().describe('The 3D look, if the element has one (3d-three projects).'),
|
|
492
512
|
'lore': z.string().readonly().describe('The 设定 text (the element\'s `lore` field): who it is, its temper, how it meets the player. \'\' when unwritten.'),
|
|
513
|
+
'updatedAt': z.number().readonly().optional().describe('When its file last changed (ms), for listing the newest first.'),
|
|
493
514
|
})).readonly(),
|
|
494
515
|
'elementErrors': z.array(z.object({
|
|
495
516
|
'where': z.string().readonly().describe('`smoke`, `data`, or the test file\'s project-relative path.'),
|
|
@@ -813,6 +834,8 @@ let _khorsheed_dsh_game_game_finalizeParams_parameter_1_strict$schema$value
|
|
|
813
834
|
const _khorsheed_dsh_game_game_finalizeParams_parameter_1_strict$schema = () => (_khorsheed_dsh_game_game_finalizeParams_parameter_1_strict$schema$value ??= z.strictObject({
|
|
814
835
|
'projectId': z.string(),
|
|
815
836
|
}))
|
|
837
|
+
let _khorsheed_dsh_game_game_liveVersion_parameter_0_strict$schema$value
|
|
838
|
+
const _khorsheed_dsh_game_game_liveVersion_parameter_0_strict$schema = () => (_khorsheed_dsh_game_game_liveVersion_parameter_0_strict$schema$value ??= z.string())
|
|
816
839
|
let _khorsheed_dsh_game_game_logPlay_parameter_0_strict$schema$value
|
|
817
840
|
const _khorsheed_dsh_game_game_logPlay_parameter_0_strict$schema = () => (_khorsheed_dsh_game_game_logPlay_parameter_0_strict$schema$value ??= z.string())
|
|
818
841
|
let _khorsheed_dsh_game_game_logPlay_parameter_1_strict$schema$value
|
|
@@ -961,7 +984,7 @@ export const TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
961
984
|
schema: _khorsheed_dsh_game_game_bind_result$schema(),
|
|
962
985
|
jsonSchema: {"oneOf":[{"type":"object","properties":{"ok":{"type":"boolean","const":false},"error":{"type":"string","enum":["not-found","denied","io","unbound","invalid","no-version","not-a-project","is-workspace","trash-failed"]}},"required":["ok","error"],"additionalProperties":true},{"type":"object","properties":{"ok":{"type":"boolean","const":true}},"required":["ok"],"additionalProperties":true}]},
|
|
963
986
|
},
|
|
964
|
-
sourceLocation: {"file":"packages/game/src/remote.ts","line":
|
|
987
|
+
sourceLocation: {"file":"packages/game/src/remote.ts","line":73,"column":3},
|
|
965
988
|
},
|
|
966
989
|
'game/bundle': {
|
|
967
990
|
service: 'gameRemote',
|
|
@@ -994,7 +1017,7 @@ export const TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
994
1017
|
schema: _khorsheed_dsh_game_game_bundle_result$schema(),
|
|
995
1018
|
jsonSchemaError: 'typert tool schema: selected union branches overlap or have no required discriminator',
|
|
996
1019
|
},
|
|
997
|
-
sourceLocation: {"file":"packages/game/src/remote.ts","line":
|
|
1020
|
+
sourceLocation: {"file":"packages/game/src/remote.ts","line":85,"column":3},
|
|
998
1021
|
},
|
|
999
1022
|
'game/changes': {
|
|
1000
1023
|
service: 'gameRemote',
|
|
@@ -1027,7 +1050,7 @@ export const TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
1027
1050
|
schema: _khorsheed_dsh_game_game_changes_result$schema(),
|
|
1028
1051
|
jsonSchema: {"oneOf":[{"type":"object","properties":{"ok":{"type":"boolean","const":false},"error":{"type":"string","enum":["not-found","denied","io","unbound","invalid","no-version","not-a-project","is-workspace","trash-failed"]}},"required":["ok","error"],"additionalProperties":true},{"type":"object","properties":{"against":{"oneOf":[{"type":"null","const":null},{"type":"number"}],"description":"The version compared against (the waiting candidate, else the live one); null before any."},"hasEntry":{"type":"boolean"},"count":{"type":"number","description":"Build files added, changed or removed (first 30 of \\`count\\`)."},"files":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"kind":{"type":"string","enum":["changed","added","removed"]}},"required":["path","kind"],"additionalProperties":true}},"lastAt":{"oneOf":[{"type":"null","const":null},{"type":"string"}],"description":"The newest change's time."},"busy":{"oneOf":[{"type":"null","const":null},{"type":"string","enum":["turn","recent"]}],"description":"Someone is still writing: a bound session's turn is running, or a file changed in the last 20 s."},"edits":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Stable key so repeated edits of one thing collapse into one entry (`param:speed`, `look:fog`, `design:core-loop`)."},"text":{"type":"string","description":"Short label for the dock and the model (`参数 移动速度 1.4→1.8`)."}},"required":["key","text"],"additionalProperties":true},"description":"The panel edits among them."},"failed":{"oneOf":[{"type":"null","const":null},{"type":"array","items":{"type":"object","properties":{"where":{"type":"string"},"message":{"type":"string"}},"required":["where","message"],"additionalProperties":true}}],"description":"The last check ran after the newest change and failed: its findings."},"ok":{"type":"boolean","const":true}},"required":["against","hasEntry","count","files","lastAt","busy","edits","failed","ok"],"additionalProperties":true}]},
|
|
1029
1052
|
},
|
|
1030
|
-
sourceLocation: {"file":"packages/game/src/remote.ts","line":
|
|
1053
|
+
sourceLocation: {"file":"packages/game/src/remote.ts","line":97,"column":3},
|
|
1031
1054
|
},
|
|
1032
1055
|
'game/checkShot': {
|
|
1033
1056
|
service: 'gameRemote',
|
|
@@ -1060,7 +1083,7 @@ export const TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
1060
1083
|
schema: _khorsheed_dsh_game_game_checkShot_result$schema(),
|
|
1061
1084
|
jsonSchema: {"oneOf":[{"type":"object","properties":{"ok":{"type":"boolean","const":false},"error":{"type":"string","enum":["not-found","denied","io","unbound","invalid","no-version","not-a-project","is-workspace","trash-failed"]}},"required":["ok","error"],"additionalProperties":true},{"type":"object","properties":{"ok":{"type":"boolean","const":true},"webp":{"type":"string"}},"required":["ok","webp"],"additionalProperties":true}]},
|
|
1062
1085
|
},
|
|
1063
|
-
sourceLocation: {"file":"packages/game/src/remote.ts","line":
|
|
1086
|
+
sourceLocation: {"file":"packages/game/src/remote.ts","line":204,"column":3},
|
|
1064
1087
|
},
|
|
1065
1088
|
'game/commit': {
|
|
1066
1089
|
service: 'gameRemote',
|
|
@@ -1111,7 +1134,7 @@ export const TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
1111
1134
|
schema: _khorsheed_dsh_game_game_commit_result$schema(),
|
|
1112
1135
|
jsonSchema: {"oneOf":[{"type":"object","properties":{"ok":{"type":"boolean","const":false},"error":{"type":"string","enum":["not-found","denied","io","unbound","invalid","no-version","not-a-project","is-workspace","trash-failed"]}},"required":["ok","error"],"additionalProperties":true},{"type":"object","properties":{"ok":{"type":"boolean","const":true},"kind":{"type":"string","enum":["candidate","deployed"]},"version":{"type":"number"}},"required":["ok","kind","version"],"additionalProperties":true},{"type":"object","properties":{"ok":{"type":"boolean","const":true},"kind":{"type":"string","const":"failed"},"failures":{"type":"array","items":{"type":"object","properties":{"where":{"type":"string"},"message":{"type":"string"}},"required":["where","message"],"additionalProperties":true}}},"required":["ok","kind","failures"],"additionalProperties":true},{"type":"object","properties":{"ok":{"type":"boolean","const":true},"kind":{"type":"string","enum":["unchanged","no-entry"]}},"required":["ok","kind"],"additionalProperties":true}]},
|
|
1113
1136
|
},
|
|
1114
|
-
sourceLocation: {"file":"packages/game/src/remote.ts","line":
|
|
1137
|
+
sourceLocation: {"file":"packages/game/src/remote.ts","line":103,"column":9},
|
|
1115
1138
|
},
|
|
1116
1139
|
'game/confirm': {
|
|
1117
1140
|
service: 'gameRemote',
|
|
@@ -1162,7 +1185,7 @@ export const TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
1162
1185
|
schema: _khorsheed_dsh_game_game_confirm_result$schema(),
|
|
1163
1186
|
jsonSchema: {"oneOf":[{"type":"object","properties":{"ok":{"type":"boolean","const":false},"error":{"type":"string","enum":["not-found","denied","io","unbound","invalid","no-version","not-a-project","is-workspace","trash-failed"]}},"required":["ok","error"],"additionalProperties":true},{"type":"object","properties":{"ok":{"type":"boolean","const":true},"version":{"type":"number"}},"required":["ok","version"],"additionalProperties":true}]},
|
|
1164
1187
|
},
|
|
1165
|
-
sourceLocation: {"file":"packages/game/src/remote.ts","line":
|
|
1188
|
+
sourceLocation: {"file":"packages/game/src/remote.ts","line":91,"column":9},
|
|
1166
1189
|
},
|
|
1167
1190
|
'game/deleteProject': {
|
|
1168
1191
|
service: 'gameRemote',
|
|
@@ -1213,7 +1236,7 @@ export const TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
1213
1236
|
schema: _khorsheed_dsh_game_game_deleteProject_result$schema(),
|
|
1214
1237
|
jsonSchema: {"oneOf":[{"type":"object","properties":{"ok":{"type":"boolean","const":true},"trashedTo":{"type":"string"}},"required":["ok"],"additionalProperties":true},{"type":"object","properties":{"ok":{"type":"boolean","const":false},"error":{"type":"string","enum":["not-found","denied","io","unbound","invalid","no-version","not-a-project","is-workspace","trash-failed"]},"reason":{"type":"string"}},"required":["ok","error"],"additionalProperties":true}]},
|
|
1215
1238
|
},
|
|
1216
|
-
sourceLocation: {"file":"packages/game/src/remote.ts","line":
|
|
1239
|
+
sourceLocation: {"file":"packages/game/src/remote.ts","line":67,"column":9},
|
|
1217
1240
|
},
|
|
1218
1241
|
'game/diff': {
|
|
1219
1242
|
service: 'gameRemote',
|
|
@@ -1246,7 +1269,7 @@ export const TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
1246
1269
|
schema: _khorsheed_dsh_game_game_diff_result$schema(),
|
|
1247
1270
|
jsonSchema: {"oneOf":[{"type":"object","properties":{"ok":{"type":"boolean","const":false},"error":{"type":"string","enum":["not-found","denied","io","unbound","invalid","no-version","not-a-project","is-workspace","trash-failed"]}},"required":["ok","error"],"additionalProperties":true},{"type":"object","properties":{"ok":{"type":"boolean","const":true},"diff":{"type":"object","properties":{"added":{"type":"array","items":{"type":"string"}},"removed":{"type":"array","items":{"type":"string"}},"changed":{"type":"array","items":{"type":"string"}}},"required":["added","removed","changed"],"additionalProperties":true}},"required":["ok","diff"],"additionalProperties":true}]},
|
|
1248
1271
|
},
|
|
1249
|
-
sourceLocation: {"file":"packages/game/src/remote.ts","line":
|
|
1272
|
+
sourceLocation: {"file":"packages/game/src/remote.ts","line":198,"column":3},
|
|
1250
1273
|
},
|
|
1251
1274
|
'game/dropPending': {
|
|
1252
1275
|
service: 'gameRemote',
|
|
@@ -1297,7 +1320,7 @@ export const TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
1297
1320
|
schema: _khorsheed_dsh_game_game_dropPending_result$schema(),
|
|
1298
1321
|
jsonSchema: {"oneOf":[{"type":"object","properties":{"ok":{"type":"boolean","const":false},"error":{"type":"string","enum":["not-found","denied","io","unbound","invalid","no-version","not-a-project","is-workspace","trash-failed"]}},"required":["ok","error"],"additionalProperties":true},{"type":"object","properties":{"ok":{"type":"boolean","const":true}},"required":["ok"],"additionalProperties":true}]},
|
|
1299
1322
|
},
|
|
1300
|
-
sourceLocation: {"file":"packages/game/src/remote.ts","line":
|
|
1323
|
+
sourceLocation: {"file":"packages/game/src/remote.ts","line":121,"column":9},
|
|
1301
1324
|
},
|
|
1302
1325
|
'game/editElement': {
|
|
1303
1326
|
service: 'gameRemote',
|
|
@@ -1348,7 +1371,7 @@ export const TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
1348
1371
|
schema: _khorsheed_dsh_game_game_editElement_result$schema(),
|
|
1349
1372
|
jsonSchema: {"oneOf":[{"type":"object","properties":{"ok":{"type":"boolean","const":false},"error":{"type":"string","enum":["not-found","denied","io","unbound","invalid","no-version","not-a-project","is-workspace","trash-failed"]}},"required":["ok","error"],"additionalProperties":true},{"type":"object","properties":{"ok":{"type":"boolean","const":true},"elementJson":{"type":"string"}},"required":["ok","elementJson"],"additionalProperties":true}]},
|
|
1350
1373
|
},
|
|
1351
|
-
sourceLocation: {"file":"packages/game/src/remote.ts","line":
|
|
1374
|
+
sourceLocation: {"file":"packages/game/src/remote.ts","line":145,"column":9},
|
|
1352
1375
|
},
|
|
1353
1376
|
'game/finalizeParams': {
|
|
1354
1377
|
service: 'gameRemote',
|
|
@@ -1399,7 +1422,40 @@ export const TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
1399
1422
|
schema: _khorsheed_dsh_game_game_finalizeParams_result$schema(),
|
|
1400
1423
|
jsonSchema: {"oneOf":[{"type":"object","properties":{"ok":{"type":"boolean","const":false},"error":{"type":"string","enum":["not-found","denied","io","unbound","invalid","no-version","not-a-project","is-workspace","trash-failed"]}},"required":["ok","error"],"additionalProperties":true},{"type":"object","properties":{"ok":{"type":"boolean","const":true}},"required":["ok"],"additionalProperties":true}]},
|
|
1401
1424
|
},
|
|
1402
|
-
sourceLocation: {"file":"packages/game/src/remote.ts","line":
|
|
1425
|
+
sourceLocation: {"file":"packages/game/src/remote.ts","line":133,"column":9},
|
|
1426
|
+
},
|
|
1427
|
+
'game/liveVersion': {
|
|
1428
|
+
service: 'gameRemote',
|
|
1429
|
+
description: 'The bound project\'s newest version (cheap; the page polls it).',
|
|
1430
|
+
invocation: { kind: 'direct' },
|
|
1431
|
+
parameters: [
|
|
1432
|
+
{
|
|
1433
|
+
name: 'sessionId',
|
|
1434
|
+
source: 'json',
|
|
1435
|
+
codec: {
|
|
1436
|
+
mode: 'strict',
|
|
1437
|
+
typeSymbol: '@deepseek-ai/dsh-session/types#SessionId',
|
|
1438
|
+
create: _khorsheed_dsh_game_game_liveVersion_parameter_0$schema,
|
|
1439
|
+
schema: _khorsheed_dsh_game_game_liveVersion_parameter_0$schema(),
|
|
1440
|
+
jsonSchema: {"type":"string"},
|
|
1441
|
+
},
|
|
1442
|
+
strictCodec: {
|
|
1443
|
+
mode: 'strict',
|
|
1444
|
+
typeSymbol: '@deepseek-ai/dsh-session/types#SessionId',
|
|
1445
|
+
create: _khorsheed_dsh_game_game_liveVersion_parameter_0_strict$schema,
|
|
1446
|
+
schema: _khorsheed_dsh_game_game_liveVersion_parameter_0_strict$schema(),
|
|
1447
|
+
jsonSchema: {"type":"string"},
|
|
1448
|
+
},
|
|
1449
|
+
},
|
|
1450
|
+
],
|
|
1451
|
+
result: {
|
|
1452
|
+
mode: 'strict',
|
|
1453
|
+
typeSymbol: '@khorsheed/dsh-game#game/liveVersion:result',
|
|
1454
|
+
create: _khorsheed_dsh_game_game_liveVersion_result$schema,
|
|
1455
|
+
schema: _khorsheed_dsh_game_game_liveVersion_result$schema(),
|
|
1456
|
+
jsonSchema: {"oneOf":[{"type":"null","const":null},{"type":"object","properties":{"projectId":{"type":"string"},"version":{"type":"number"},"kind":{"type":"string","enum":["none","candidate","deployed"]},"at":{"oneOf":[{"type":"null","const":null},{"type":"string"}]},"by":{"type":"string","enum":["user","agent","turn"]},"show":{"type":"object","properties":{"seq":{"type":"number"},"target":{"type":"object","properties":{"view":{"type":"string","enum":["versions","play","elements","design"]},"elementId":{"type":"string"},"chapterId":{"type":"string"}},"required":["view"],"additionalProperties":true},"note":{"type":"string","description":"What to look at, in the agent's words (shown with the notice)."},"at":{"type":"string"}},"required":["seq","target","note","at"],"additionalProperties":true,"description":"The agent's latest request to show the user something, if any since the host started."}},"required":["projectId","version","kind","at"],"additionalProperties":true}]},
|
|
1457
|
+
},
|
|
1458
|
+
sourceLocation: {"file":"packages/game/src/remote.ts","line":49,"column":3},
|
|
1403
1459
|
},
|
|
1404
1460
|
'game/logPlay': {
|
|
1405
1461
|
service: 'gameRemote',
|
|
@@ -1450,7 +1506,7 @@ export const TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
1450
1506
|
schema: _khorsheed_dsh_game_game_logPlay_result$schema(),
|
|
1451
1507
|
jsonSchema: {"oneOf":[{"type":"object","properties":{"ok":{"type":"boolean","const":false},"error":{"type":"string","enum":["not-found","denied","io","unbound","invalid","no-version","not-a-project","is-workspace","trash-failed"]}},"required":["ok","error"],"additionalProperties":true},{"type":"object","properties":{"ok":{"type":"boolean","const":true}},"required":["ok"],"additionalProperties":true}]},
|
|
1452
1508
|
},
|
|
1453
|
-
sourceLocation: {"file":"packages/game/src/remote.ts","line":
|
|
1509
|
+
sourceLocation: {"file":"packages/game/src/remote.ts","line":115,"column":9},
|
|
1454
1510
|
},
|
|
1455
1511
|
'game/pickProposal': {
|
|
1456
1512
|
service: 'gameRemote',
|
|
@@ -1501,7 +1557,7 @@ export const TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
1501
1557
|
schema: _khorsheed_dsh_game_game_pickProposal_result$schema(),
|
|
1502
1558
|
jsonSchema: {"oneOf":[{"type":"object","properties":{"ok":{"type":"boolean","const":false},"error":{"type":"string","enum":["not-found","denied","io","unbound","invalid","no-version","not-a-project","is-workspace","trash-failed"]}},"required":["ok","error"],"additionalProperties":true},{"type":"object","properties":{"ok":{"type":"boolean","const":true}},"required":["ok"],"additionalProperties":true}]},
|
|
1503
1559
|
},
|
|
1504
|
-
sourceLocation: {"file":"packages/game/src/remote.ts","line":
|
|
1560
|
+
sourceLocation: {"file":"packages/game/src/remote.ts","line":162,"column":9},
|
|
1505
1561
|
},
|
|
1506
1562
|
'game/projectCards': {
|
|
1507
1563
|
service: 'gameRemote',
|
|
@@ -1516,7 +1572,7 @@ export const TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
1516
1572
|
schema: _khorsheed_dsh_game_game_projectCards_result$schema(),
|
|
1517
1573
|
jsonSchema: {"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"root":{"type":"string"},"updatedAt":{"type":"string"},"pitch":{"type":"string"},"artStyle":{"type":"string"},"version":{"oneOf":[{"type":"null","const":null},{"type":"number"}]},"elements":{"type":"number"},"thumb":{"type":"string","description":"The last check's screenshot (webp, base64), when there is one."}},"required":["id","title","root","updatedAt","pitch","artStyle","version","elements"],"additionalProperties":true}},
|
|
1518
1574
|
},
|
|
1519
|
-
sourceLocation: {"file":"packages/game/src/remote.ts","line":
|
|
1575
|
+
sourceLocation: {"file":"packages/game/src/remote.ts","line":61,"column":3},
|
|
1520
1576
|
},
|
|
1521
1577
|
'game/reject': {
|
|
1522
1578
|
service: 'gameRemote',
|
|
@@ -1567,7 +1623,7 @@ export const TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
1567
1623
|
schema: _khorsheed_dsh_game_game_reject_result$schema(),
|
|
1568
1624
|
jsonSchema: {"oneOf":[{"type":"object","properties":{"ok":{"type":"boolean","const":false},"error":{"type":"string","enum":["not-found","denied","io","unbound","invalid","no-version","not-a-project","is-workspace","trash-failed"]}},"required":["ok","error"],"additionalProperties":true},{"type":"object","properties":{"ok":{"type":"boolean","const":true}},"required":["ok"],"additionalProperties":true}]},
|
|
1569
1625
|
},
|
|
1570
|
-
sourceLocation: {"file":"packages/game/src/remote.ts","line":
|
|
1626
|
+
sourceLocation: {"file":"packages/game/src/remote.ts","line":186,"column":9},
|
|
1571
1627
|
},
|
|
1572
1628
|
'game/requestRestyle': {
|
|
1573
1629
|
service: 'gameRemote',
|
|
@@ -1618,7 +1674,7 @@ export const TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
1618
1674
|
schema: _khorsheed_dsh_game_game_requestRestyle_result$schema(),
|
|
1619
1675
|
jsonSchema: {"oneOf":[{"type":"object","properties":{"ok":{"type":"boolean","const":false},"error":{"type":"string","enum":["not-found","denied","io","unbound","invalid","no-version","not-a-project","is-workspace","trash-failed"]}},"required":["ok","error"],"additionalProperties":true},{"type":"object","properties":{"ok":{"type":"boolean","const":true}},"required":["ok"],"additionalProperties":true}]},
|
|
1620
1676
|
},
|
|
1621
|
-
sourceLocation: {"file":"packages/game/src/remote.ts","line":
|
|
1677
|
+
sourceLocation: {"file":"packages/game/src/remote.ts","line":180,"column":9},
|
|
1622
1678
|
},
|
|
1623
1679
|
'game/resetParams': {
|
|
1624
1680
|
service: 'gameRemote',
|
|
@@ -1669,7 +1725,7 @@ export const TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
1669
1725
|
schema: _khorsheed_dsh_game_game_resetParams_result$schema(),
|
|
1670
1726
|
jsonSchema: {"oneOf":[{"type":"object","properties":{"ok":{"type":"boolean","const":false},"error":{"type":"string","enum":["not-found","denied","io","unbound","invalid","no-version","not-a-project","is-workspace","trash-failed"]}},"required":["ok","error"],"additionalProperties":true},{"type":"object","properties":{"ok":{"type":"boolean","const":true}},"required":["ok"],"additionalProperties":true}]},
|
|
1671
1727
|
},
|
|
1672
|
-
sourceLocation: {"file":"packages/game/src/remote.ts","line":
|
|
1728
|
+
sourceLocation: {"file":"packages/game/src/remote.ts","line":139,"column":9},
|
|
1673
1729
|
},
|
|
1674
1730
|
'game/rollback': {
|
|
1675
1731
|
service: 'gameRemote',
|
|
@@ -1720,7 +1776,7 @@ export const TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
1720
1776
|
schema: _khorsheed_dsh_game_game_rollback_result$schema(),
|
|
1721
1777
|
jsonSchema: {"oneOf":[{"type":"object","properties":{"ok":{"type":"boolean","const":false},"error":{"type":"string","enum":["not-found","denied","io","unbound","invalid","no-version","not-a-project","is-workspace","trash-failed"]}},"required":["ok","error"],"additionalProperties":true},{"type":"object","properties":{"ok":{"type":"boolean","const":true}},"required":["ok"],"additionalProperties":true}]},
|
|
1722
1778
|
},
|
|
1723
|
-
sourceLocation: {"file":"packages/game/src/remote.ts","line":
|
|
1779
|
+
sourceLocation: {"file":"packages/game/src/remote.ts","line":192,"column":9},
|
|
1724
1780
|
},
|
|
1725
1781
|
'game/setAutoConfirm': {
|
|
1726
1782
|
service: 'gameRemote',
|
|
@@ -1771,7 +1827,7 @@ export const TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
1771
1827
|
schema: _khorsheed_dsh_game_game_setAutoConfirm_result$schema(),
|
|
1772
1828
|
jsonSchema: {"oneOf":[{"type":"object","properties":{"ok":{"type":"boolean","const":false},"error":{"type":"string","enum":["not-found","denied","io","unbound","invalid","no-version","not-a-project","is-workspace","trash-failed"]}},"required":["ok","error"],"additionalProperties":true},{"type":"object","properties":{"ok":{"type":"boolean","const":true}},"required":["ok"],"additionalProperties":true}]},
|
|
1773
1829
|
},
|
|
1774
|
-
sourceLocation: {"file":"packages/game/src/remote.ts","line":
|
|
1830
|
+
sourceLocation: {"file":"packages/game/src/remote.ts","line":109,"column":9},
|
|
1775
1831
|
},
|
|
1776
1832
|
'game/setOnePager': {
|
|
1777
1833
|
service: 'gameRemote',
|
|
@@ -1822,7 +1878,7 @@ export const TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
1822
1878
|
schema: _khorsheed_dsh_game_game_setOnePager_result$schema(),
|
|
1823
1879
|
jsonSchema: {"oneOf":[{"type":"object","properties":{"ok":{"type":"boolean","const":false},"error":{"type":"string","enum":["not-found","denied","io","unbound","invalid","no-version","not-a-project","is-workspace","trash-failed"]}},"required":["ok","error"],"additionalProperties":true},{"type":"object","properties":{"ok":{"type":"boolean","const":true}},"required":["ok"],"additionalProperties":true}]},
|
|
1824
1880
|
},
|
|
1825
|
-
sourceLocation: {"file":"packages/game/src/remote.ts","line":
|
|
1881
|
+
sourceLocation: {"file":"packages/game/src/remote.ts","line":174,"column":9},
|
|
1826
1882
|
},
|
|
1827
1883
|
'game/setParam': {
|
|
1828
1884
|
service: 'gameRemote',
|
|
@@ -1873,7 +1929,7 @@ export const TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
1873
1929
|
schema: _khorsheed_dsh_game_game_setParam_result$schema(),
|
|
1874
1930
|
jsonSchema: {"oneOf":[{"type":"object","properties":{"ok":{"type":"boolean","const":false},"error":{"type":"string","enum":["not-found","denied","io","unbound","invalid","no-version","not-a-project","is-workspace","trash-failed"]}},"required":["ok","error"],"additionalProperties":true},{"type":"object","properties":{"ok":{"type":"boolean","const":true}},"required":["ok"],"additionalProperties":true}]},
|
|
1875
1931
|
},
|
|
1876
|
-
sourceLocation: {"file":"packages/game/src/remote.ts","line":
|
|
1932
|
+
sourceLocation: {"file":"packages/game/src/remote.ts","line":127,"column":9},
|
|
1877
1933
|
},
|
|
1878
1934
|
'game/state': {
|
|
1879
1935
|
service: 'gameRemote',
|
|
@@ -1957,7 +2013,7 @@ export const TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
1957
2013
|
schema: _khorsheed_dsh_game_game_turnReport_result$schema(),
|
|
1958
2014
|
jsonSchema: {"oneOf":[{"type":"null","const":null},{"type":"object","properties":{"turn":{"type":"number"},"projectId":{"type":"string"},"title":{"type":"string"},"at":{"type":"string"},"version":{"oneOf":[{"type":"null","const":null},{"type":"object","properties":{"kind":{"type":"string","enum":["candidate","deployed"]},"version":{"type":"number"}},"required":["kind","version"],"additionalProperties":true}],"description":"A version that became live (or a candidate) during the turn."},"check":{"oneOf":[{"type":"null","const":null},{"type":"object","properties":{"ok":{"type":"boolean"},"fixes":{"type":"number"},"gaveUp":{"type":"boolean"},"passed":{"type":"number"},"failures":{"type":"number"}},"required":["ok","fixes","gaveUp","passed","failures"],"additionalProperties":true}],"description":"The turn's end-of-turn check, when one ran."},"elements":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"what":{"type":"string","enum":["removed","new","look","fields"]},"fields":{"type":"array","items":{"type":"string"}},"looks":{"type":"object","properties":{"before":{"oneOf":[{"type":"null","const":null},{"type":"string"}]},"after":{"type":"string"}},"required":["before","after"],"additionalProperties":true,"description":"3D looks before and after the turn (JSON), for the card's side-by-side previews."}},"required":["id","name","what"],"additionalProperties":true}},"chapters":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"}},"required":["id","title"],"additionalProperties":true}},"params":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"from":{"type":"number"},"to":{"type":"number"}},"required":["key","label","to"],"additionalProperties":true}},"code":{"type":"array","items":{"type":"string"},"description":"Other changed source files (code, assets, index.html)."},"tests":{"type":"array","items":{"type":"string"}}},"required":["turn","projectId","title","at","version","check","elements","chapters","params","code","tests"],"additionalProperties":true}]},
|
|
1959
2015
|
},
|
|
1960
|
-
sourceLocation: {"file":"packages/game/src/remote.ts","line":
|
|
2016
|
+
sourceLocation: {"file":"packages/game/src/remote.ts","line":55,"column":3},
|
|
1961
2017
|
},
|
|
1962
2018
|
'game/versionBundle': {
|
|
1963
2019
|
service: 'gameRemote',
|
|
@@ -1990,7 +2046,7 @@ export const TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
1990
2046
|
schema: _khorsheed_dsh_game_game_versionBundle_result$schema(),
|
|
1991
2047
|
jsonSchemaError: 'typert tool schema: selected union branches overlap or have no required discriminator',
|
|
1992
2048
|
},
|
|
1993
|
-
sourceLocation: {"file":"packages/game/src/remote.ts","line":
|
|
2049
|
+
sourceLocation: {"file":"packages/game/src/remote.ts","line":210,"column":3},
|
|
1994
2050
|
},
|
|
1995
2051
|
'game/workingFile': {
|
|
1996
2052
|
service: 'gameRemote',
|
|
@@ -2023,7 +2079,7 @@ export const TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
2023
2079
|
schema: _khorsheed_dsh_game_game_workingFile_result$schema(),
|
|
2024
2080
|
jsonSchemaError: 'typert tool schema: selected union branches overlap or have no required discriminator',
|
|
2025
2081
|
},
|
|
2026
|
-
sourceLocation: {"file":"packages/game/src/remote.ts","line":
|
|
2082
|
+
sourceLocation: {"file":"packages/game/src/remote.ts","line":79,"column":3},
|
|
2027
2083
|
},
|
|
2028
2084
|
'game/writeChapter': {
|
|
2029
2085
|
service: 'gameRemote',
|
|
@@ -2074,7 +2130,7 @@ export const TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
2074
2130
|
schema: _khorsheed_dsh_game_game_writeChapter_result$schema(),
|
|
2075
2131
|
jsonSchema: {"oneOf":[{"type":"object","properties":{"ok":{"type":"boolean","const":false},"error":{"type":"string","enum":["not-found","denied","io","unbound","invalid","no-version","not-a-project","is-workspace","trash-failed"]}},"required":["ok","error"],"additionalProperties":true},{"type":"object","properties":{"ok":{"type":"boolean","const":true}},"required":["ok"],"additionalProperties":true}]},
|
|
2076
2132
|
},
|
|
2077
|
-
sourceLocation: {"file":"packages/game/src/remote.ts","line":
|
|
2133
|
+
sourceLocation: {"file":"packages/game/src/remote.ts","line":168,"column":9},
|
|
2078
2134
|
},
|
|
2079
2135
|
},
|
|
2080
2136
|
}, z)
|
package/lib/types/agent.js
CHANGED
|
@@ -10,7 +10,8 @@ const GUIDANCE = 'This session is the game-development mode. The user designs an
|
|
|
10
10
|
+ 'version that passed the checks. Use game_open / game_read for the project; write its files with the '
|
|
11
11
|
+ 'ordinary file tools. Whenever you changed something playable, call game_publish before you report or ask anything, '
|
|
12
12
|
+ 'without waiting to be asked — a question does not end the turn, so the play area would still show the old version. '
|
|
13
|
-
+ 'When a CLI member reports its changes, publish them for it (members have no publish tool).
|
|
13
|
+
+ 'When a CLI member reports its changes, publish them for it (members have no publish tool). A publish also takes the '
|
|
14
|
+
+ 'user\'s game tab to the result; pass show/note to choose where and say what to look at. Load the game-design skill when shaping the game with the user, and the gamedev skill before '
|
|
14
15
|
+ 'writing game code. Answer in the user\'s language.';
|
|
15
16
|
/**
|
|
16
17
|
* Register the tools, the guidance and the skills, or nothing when the core is absent.
|
|
@@ -8,7 +8,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
8
8
|
* number; 试玩记录 is the log the plugin keeps.
|
|
9
9
|
*/
|
|
10
10
|
import { useEffect, useMemo, useState } from 'react';
|
|
11
|
-
import { artStyleLabel } from "../project.js";
|
|
11
|
+
import { artStyleLabel, artStyleName } from "../project.js";
|
|
12
12
|
import { failureOf } from "./contract.js";
|
|
13
13
|
import { Markdown } from "./markdown.js";
|
|
14
14
|
import css from './GameTab.module.css';
|
|
@@ -76,7 +76,7 @@ function OnePager(props) {
|
|
|
76
76
|
setError(null);
|
|
77
77
|
setEditing(true);
|
|
78
78
|
};
|
|
79
|
-
return _jsxs("section", { className: css.onePager, children: [_jsxs("div", { className: css.onePagerHead, children: [_jsx("span", { className: css.eyebrow, children: t('design.onePager') }), _jsx("span", { className: css.metaLine, children: "game.json" }), _jsx("span", { className: css.spacer }), _jsx("button", { type: "button", className: css.styleChip, onClick: onStyle, title: t('style.change')
|
|
79
|
+
return _jsxs("section", { className: css.onePager, children: [_jsxs("div", { className: css.onePagerHead, children: [_jsx("span", { className: css.eyebrow, children: t('design.onePager') }), _jsx("span", { className: css.metaLine, children: "game.json" }), _jsx("span", { className: css.spacer }), _jsx("button", { type: "button", className: css.styleChip, onClick: onStyle, title: manifest === null ? t('style.change') : `${artStyleLabel(manifest.artStyle)}\n${t('style.change')}`, children: t('design.style', { style: manifest === null ? '—' : artStyleName(manifest.artStyle) }) }), !editing && manifest !== null && _jsx("button", { type: "button", className: css.ghost, onClick: begin, children: t('design.editOnePager') })] }), editing
|
|
80
80
|
? _jsxs("div", { className: css.onePagerForm, children: [_jsxs("label", { className: css.field, children: [_jsx("span", { className: css.fieldKey, children: t('design.pitchLabel') }), _jsx("textarea", { className: css.textarea, rows: 2, value: pitch, onChange: e => { setPitch(e.target.value); } })] }), _jsxs("label", { className: css.field, children: [_jsx("span", { className: css.fieldKey, children: t('design.typesLabel') }), _jsx("input", { className: css.input, value: types, onChange: e => { setTypes(e.target.value); } })] }), _jsxs("label", { className: css.field, children: [_jsx("span", { className: css.fieldKey, children: t('design.pillarsLabel') }), _jsx("textarea", { className: css.textarea, rows: 4, value: pillars, onChange: e => { setPillars(e.target.value); } })] }), error !== null && _jsx("p", { className: css.warnText, children: error }), _jsxs("div", { className: css.rowEnd, children: [_jsx("button", { type: "button", className: css.ghost, onClick: () => { setEditing(false); }, children: t('common.cancel') }), _jsx("button", { type: "button", className: css.primary, onClick: () => {
|
|
81
81
|
void api.setOnePager(sessionId, project.id, { pitch, elementTypes: types, pillars }).then(r => {
|
|
82
82
|
if (failureOf(r) !== undefined) {
|
|
@@ -87,7 +87,7 @@ function OnePager(props) {
|
|
|
87
87
|
refresh();
|
|
88
88
|
});
|
|
89
89
|
}, children: t('common.save') })] })] })
|
|
90
|
-
: _jsxs(_Fragment, { children: [_jsx("p", { className: css.pitch, children: manifest?.pitch || t('design.noPitch') }), _jsx("div", { className: css.typeRow, children: (manifest?.elementTypes ?? []).map(type => _jsx("span", { className: css.typeTag, children: type }, type)) }), _jsxs("div", { className: css.pillars, children: [_jsx("span", { className: css.eyebrow, children: t('design.pillars') }), (manifest?.pillars.length ?? 0) > 0
|
|
90
|
+
: _jsxs(_Fragment, { children: [_jsx("p", { className: css.pitch, children: manifest?.pitch || t('design.noPitch') }), manifest !== null && artStyleName(manifest.artStyle) !== artStyleLabel(manifest.artStyle) && _jsx("p", { className: css.metaLine, children: t('design.styleFull', { style: artStyleLabel(manifest.artStyle) }) }), _jsx("div", { className: css.typeRow, children: (manifest?.elementTypes ?? []).map(type => _jsx("span", { className: css.typeTag, children: type }, type)) }), _jsxs("div", { className: css.pillars, children: [_jsx("span", { className: css.eyebrow, children: t('design.pillars') }), (manifest?.pillars.length ?? 0) > 0
|
|
91
91
|
? _jsx("ol", { className: css.pillarList, children: manifest.pillars.map((p, i) => _jsx("li", { children: p }, i)) })
|
|
92
92
|
: _jsx("p", { className: css.metaLine, children: t('design.noPillars') })] })] })] });
|
|
93
93
|
}
|
|
@@ -34,7 +34,9 @@ export function ElementsView(props) {
|
|
|
34
34
|
const open = project.elements.find(e => e.id === openId);
|
|
35
35
|
if (open !== undefined)
|
|
36
36
|
return _jsx(ElementDetail, { ...props, element: open, onBack: () => { onOpen(null); }, types: types });
|
|
37
|
-
|
|
37
|
+
// Newest change first (stable: elements of one file keep their order).
|
|
38
|
+
const shown = project.elements.filter(e => filter === 'all' || e.type === filter)
|
|
39
|
+
.map((e, i) => ({ e, i })).sort((a, b) => (b.e.updatedAt ?? 0) - (a.e.updatedAt ?? 0) || a.i - b.i).map(x => x.e);
|
|
38
40
|
const openProposals = new Set(project.proposals.filter(p => p.picked === undefined).map(p => p.elementId));
|
|
39
41
|
const toggle = (id) => { setSelected(s => (s.includes(id) ? s.filter(x => x !== id) : [...s, id])); };
|
|
40
42
|
return _jsxs("div", { className: css.scroll, children: [project.elementErrors.length > 0 && _jsxs("div", { className: css.notice, "data-tone": "error", children: [_jsx("strong", { children: t('elements.errors', { count: project.elementErrors.length }) }), _jsx("ul", { className: css.plainList, children: project.elementErrors.slice(0, 6).map((f, i) => _jsxs("li", { children: [_jsx("code", { children: f.where }), " ", f.message] }, i)) })] }), project.elements.length === 0
|
|
@@ -71,7 +73,8 @@ function ElementDetail({ t, sessionId, api, project, element, onBack, insertDraf
|
|
|
71
73
|
const [parts, setParts] = useState(null);
|
|
72
74
|
const [clip, setClip] = useState(null);
|
|
73
75
|
const [view, setView] = useState(null);
|
|
74
|
-
const
|
|
76
|
+
const viewN = useRef(0);
|
|
77
|
+
const turnTo = (yaw) => { viewN.current++; setView({ yaw, n: viewN.current }); };
|
|
75
78
|
useEffect(() => { setClips([]); setClip(null); setParts(null); }, [element.id]);
|
|
76
79
|
useEffect(() => { setLook3d(element.look3d); }, [element.id, element.look3d]);
|
|
77
80
|
const save = (next) => {
|
|
@@ -115,9 +118,9 @@ function ElementDetail({ t, sessionId, api, project, element, onBack, insertDraf
|
|
|
115
118
|
const history = proposals.filter(p => p.picked !== undefined);
|
|
116
119
|
const states = look === null ? [] : Object.keys(look.states);
|
|
117
120
|
const fields = Object.entries(element.stats);
|
|
118
|
-
return _jsxs("div", { className: css.scroll, children: [_jsx(PanelHeader, { className: css.detailHead, title: element.name, meta: _jsx("span", { title: `${element.id} · ${element.file}`, children: element.type }), onBack: onBack, backLabel: t('elements.back'), moreLabel: t('more') }), look3d !== null ? _jsxs("section", { className: css.lookPanel, children: [_jsx(Preview3D, { api: api, projectId: project.id, version: project.current?.version, look: look3d, mode: "spin", className: css.turntable, emptyLabel: t('look.preview3dEmpty'), onClips: (names, found) => { setClips(names); setParts(found); }, clip: clip, view: view }), clips.length > 0 && _jsx(ChipRow, { label: t('gltf.clips'), value: clip?.name ??
|
|
121
|
+
return _jsxs("div", { className: css.scroll, children: [_jsx(PanelHeader, { className: css.detailHead, title: element.name, meta: _jsx("span", { title: `${element.id} · ${element.file}`, children: element.type }), onBack: onBack, backLabel: t('elements.back'), moreLabel: t('more') }), look3d !== null ? _jsxs("section", { className: css.lookPanel, children: [_jsx(Preview3D, { api: api, projectId: project.id, version: project.current?.version, look: look3d, mode: "spin", className: css.turntable, emptyLabel: t('look.preview3dEmpty'), onClips: (names, found) => { setClips(names); setParts(found); }, onTurned: () => { setView(null); }, clip: clip, view: view }), clips.length > 0 && _jsx(ChipRow, { label: t('gltf.clips'), value: clip?.name ?? autoClip(look3d, clips), onSelect: name => { setClip(c => ({ name, n: (c?.n ?? 0) + 1 })); }, chips: clips.map(name => ({ id: name, label: name })) }), _jsxs("div", { className: `${css.toolRow} ${css.tight}`, children: [_jsx("span", { className: css.metaLine, children: t('look.drag3d') }), _jsx("span", { className: css.spacer }), _jsx("span", { role: "group", "aria-label": t('look.views'), className: css.segGroup, children: [[0, 'look.front'], [90, 'look.side'], [180, 'look.back']].map(([yaw, key]) => _jsx("button", { type: "button", className: css.seg, "aria-pressed": view?.yaw === yaw, onClick: () => { turnTo(yaw); }, children: t(key) }, yaw)) }), _jsx("span", { className: css.saveState, "data-state": saving, children: saving === 'idle' ? '' : t(`look.${saving}`) })] }), look3d.kind === 'gltf' && _jsx(GltfControls, { t: t, look: look3d, onChange: save })] }) : _jsxs("section", { className: css.lookPanel, children: [_jsxs("div", { className: css.lookMain, children: [look !== null
|
|
119
122
|
? _jsx(LookCanvas, { look: look, state: state, box: 208, grid: true, onPaint: paint, className: css.lookEditor })
|
|
120
|
-
: _jsxs("div", { className: css.lookEmpty, "data-tone": typeTone(types, element.type), children: [_jsx("p", { children: t('look.none') }), _jsx("button", { type: "button", className: css.ghost, onClick: () => { save(blankLook(stylePalette.length > 0 ? stylePalette : ['#000000', '#ffffff'])); }, children: t('look.start') })] }), look !== null && _jsxs("div", { className: css.lookSide, children: [_jsx("div", { className: css.lookPreview, children: _jsx(LookCanvas, { look: look, state: state, box: 64 }) }), _jsx("span", { className: css.metaLine, children: t('look.inGame') }), _jsx("span", { className: css.saveState, "data-state": saving, children: saving === 'idle' ? '' : t(`look.${saving}`) })] })] }), states.length > 0 && _jsx(ChipRow, { label: t('look.states'), value: state, onSelect: setState, chips: states.map(s => ({ id: s, label: s })) }), look !== null && _jsxs(_Fragment, { children: [_jsxs("div", { className: css.toolRow, role: "group", "aria-label": t('look.tools'), children: [_jsx("button", { type: "button", className: css.seg, "aria-pressed": tool === 'pen', onClick: () => { setTool('pen'); setRecolorFrom(null); }, children: t('look.pen') }), _jsx("button", { type: "button", className: css.seg, "aria-pressed": tool === 'recolor', onClick: () => { setTool('recolor'); }, children: t('look.recolor') }), _jsx("span", { className: css.spacer }), _jsx("span", { className: css.metaLine, children: tool === 'pen' ? t('look.penHint') : recolorFrom === null ? t('look.recolorPick') : t('look.recolorTo') })] }), tool === 'recolor' && _jsx("div", { className: css.swatches, "aria-label": t('look.ownColors'), children: look.palette.map((c, i) => _jsx("button", { type: "button", className: css.swatchBtn, "aria-pressed": recolorFrom === i, style: { background: c }, title: `${LOOK_CHARS[i]} ${c}`, onClick: () => { setRecolorFrom(i); } }, i)) }), _jsxs("div", { className: css.swatches, "aria-label": t('look.styleColors'), children: [tool === 'pen' && _jsx("button", { type: "button", className: css.swatchBtn, "data-erase": "true", "aria-pressed": color === null, title: t('look.erase'), onClick: () => { setColor(null); } }), stylePalette.map(c => _jsx("button", { type: "button", className: css.swatchBtn, style: { background: c }, title: c, "aria-pressed": tool === 'pen' && color === c, onClick: () => {
|
|
123
|
+
: _jsxs("div", { className: css.lookEmpty, "data-tone": typeTone(types, element.type), children: [_jsx("p", { children: t('look.none') }), _jsx("button", { type: "button", className: css.ghost, onClick: () => { save(blankLook(stylePalette.length > 0 ? stylePalette : ['#000000', '#ffffff'])); }, children: t('look.start') })] }), look !== null && _jsxs("div", { className: css.lookSide, children: [_jsx("div", { className: css.lookPreview, children: _jsx(LookCanvas, { look: look, state: state, box: 64 }) }), _jsx("span", { className: css.metaLine, children: t('look.inGame') }), _jsx("span", { className: css.saveState, "data-state": saving, children: saving === 'idle' ? '' : t(`look.${saving}`) })] })] }), states.length > 0 && _jsx(ChipRow, { label: t('look.states'), value: state, onSelect: setState, chips: states.map(s => ({ id: s, label: s })) }), look !== null && _jsxs(_Fragment, { children: [_jsxs("div", { className: `${css.toolRow} ${css.tight}`, children: [_jsxs("span", { className: css.segGroup, role: "group", "aria-label": t('look.tools'), children: [_jsx("button", { type: "button", className: css.seg, "aria-pressed": tool === 'pen', onClick: () => { setTool('pen'); setRecolorFrom(null); }, children: t('look.pen') }), _jsx("button", { type: "button", className: css.seg, "aria-pressed": tool === 'recolor', onClick: () => { setTool('recolor'); }, children: t('look.recolor') })] }), _jsx("span", { className: css.spacer }), _jsx("span", { className: css.metaLine, children: tool === 'pen' ? t('look.penHint') : recolorFrom === null ? t('look.recolorPick') : t('look.recolorTo') })] }), tool === 'recolor' && _jsx("div", { className: css.swatches, "aria-label": t('look.ownColors'), children: look.palette.map((c, i) => _jsx("button", { type: "button", className: css.swatchBtn, "aria-pressed": recolorFrom === i, style: { background: c }, title: `${LOOK_CHARS[i]} ${c}`, onClick: () => { setRecolorFrom(i); } }, i)) }), _jsxs("div", { className: css.swatches, "aria-label": t('look.styleColors'), children: [tool === 'pen' && _jsx("button", { type: "button", className: css.swatchBtn, "data-erase": "true", "aria-pressed": color === null, title: t('look.erase'), onClick: () => { setColor(null); } }), stylePalette.map(c => _jsx("button", { type: "button", className: css.swatchBtn, style: { background: c }, title: c, "aria-pressed": tool === 'pen' && color === c, onClick: () => {
|
|
121
124
|
if (tool === 'pen')
|
|
122
125
|
setColor(c);
|
|
123
126
|
else if (recolorFrom !== null) {
|
|
@@ -155,7 +158,7 @@ function GltfControls({ t, look, onChange }) {
|
|
|
155
158
|
const material = look.material ?? 'toon';
|
|
156
159
|
const [scale, setScale] = useState(String(look.scale ?? 1));
|
|
157
160
|
useEffect(() => { setScale(String(look.scale ?? 1)); }, [look.scale]);
|
|
158
|
-
return _jsxs("div", { className: css.gltfRow, children: [_jsx("span", { className: css.metaLine, children: t('gltf.file', { src: look.src }) }), _jsx("span", { className: css.spacer }), _jsxs("span", { role: "group", "aria-label": t('gltf.material'), className: css.
|
|
161
|
+
return _jsxs("div", { className: css.gltfRow, children: [_jsx("span", { className: css.metaLine, children: t('gltf.file', { src: look.src }) }), _jsx("span", { className: css.spacer }), _jsxs("span", { role: "group", "aria-label": t('gltf.material'), className: css.segGroup, children: [_jsx("button", { type: "button", className: css.seg, "aria-pressed": material === 'toon', onClick: () => { onChange({ ...look, material: 'toon' }); }, children: t('gltf.toon') }), _jsx("button", { type: "button", className: css.seg, "aria-pressed": material === 'original', onClick: () => { onChange({ ...look, material: 'original' }); }, children: t('gltf.original') })] }), _jsxs("label", { className: css.gltfScale, children: [_jsx("span", { className: css.metaLine, children: t('gltf.scale') }), _jsx("input", { className: css.input, inputMode: "decimal", value: scale, onChange: e => { setScale(e.target.value); }, onBlur: () => { const v = Number(scale); if (Number.isFinite(v) && v > 0 && v !== (look.scale ?? 1))
|
|
159
162
|
onChange({ ...look, scale: v }); }, onKeyDown: e => { if (e.key === 'Enter')
|
|
160
163
|
e.target.blur(); } })] })] });
|
|
161
164
|
}
|
|
@@ -185,3 +188,8 @@ function GltfTweaks({ t, look, parts, onChange }) {
|
|
|
185
188
|
setBone(name, { rotate: next });
|
|
186
189
|
} }), _jsxs("span", { className: css.paramValue, children: [rot(name)[i], "\u00B0"] })] }, axis))] })] }, name)), shown.length > 40 && _jsx("span", { className: css.metaLine, children: t('gltf.moreBones', { count: shown.length - 40 }) })] })] });
|
|
187
190
|
}
|
|
191
|
+
/** The clip a model plays on its own (dsh3d's rule): the look's choice, else an idle-like name, else the first. */
|
|
192
|
+
function autoClip(look, clips) {
|
|
193
|
+
const chosen = look.kind === 'gltf' ? look.animation : undefined;
|
|
194
|
+
return chosen !== undefined && clips.includes(chosen) ? chosen : clips.find(c => /idle|待机|stand/i.test(c)) ?? clips[0] ?? '';
|
|
195
|
+
}
|
|
@@ -11,7 +11,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
11
11
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
12
12
|
import { PanelHeader, PanelRoot, UnderlineTabs, } from '@khorsheed/dsh-client-ui-panel-kit/src/client/index.ts';
|
|
13
13
|
import { Switch, Tag } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
14
|
-
import { artStyleLabel } from "../project.js";
|
|
14
|
+
import { artStyleLabel, artStyleName } from "../project.js";
|
|
15
15
|
import { exportHtml } from "../vfs.js";
|
|
16
16
|
import { failureOf } from "./contract.js";
|
|
17
17
|
import { DesignView } from "./DesignView.js";
|
|
@@ -28,7 +28,7 @@ const PlusIcon = _jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16",
|
|
|
28
28
|
const ExportIcon = _jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: _jsx("path", { d: "M8 2.5v7M5 6.5l3 3 3-3M3 11v2.5h10V11", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round" }) });
|
|
29
29
|
/** The game tab body. */
|
|
30
30
|
export function GameTab(props) {
|
|
31
|
-
const { sessionId, t, api, insertDraft, subscribeSessionEvents, touch, subscribeNav, takeNav } = props;
|
|
31
|
+
const { sessionId, t, api, insertDraft, subscribeSessionEvents, touch, subscribeNav, takeNav, reveal } = props;
|
|
32
32
|
const [state, setState] = useState(null);
|
|
33
33
|
const [error, setError] = useState(null);
|
|
34
34
|
const [rev, setRev] = useState(0);
|
|
@@ -38,6 +38,7 @@ export function GameTab(props) {
|
|
|
38
38
|
const [openElement, setOpenElement] = useState(null);
|
|
39
39
|
const [toastText, setToastText] = useState(null);
|
|
40
40
|
const [openChapter, setOpenChapter] = useState(null);
|
|
41
|
+
useEffect(() => reveal.mount(), [reveal]);
|
|
41
42
|
const toastTimer = useRef();
|
|
42
43
|
const refresh = useCallback(() => { touch(sessionId); }, [touch, sessionId]);
|
|
43
44
|
const toast = useCallback((text) => {
|
|
@@ -78,7 +79,7 @@ export function GameTab(props) {
|
|
|
78
79
|
return () => { live = false; };
|
|
79
80
|
}, [api, sessionId, rev]);
|
|
80
81
|
const viewProps = {
|
|
81
|
-
t, sessionId, api, refresh, toast, insertDraft: text => insertDraft(sessionId, text), insertRef: ref => props.insertRef(sessionId, ref),
|
|
82
|
+
t, sessionId, api, refresh, toast, insertDraft: text => insertDraft(sessionId, text), insertRef: ref => props.insertRef(sessionId, ref), reveal,
|
|
82
83
|
};
|
|
83
84
|
const project = state?.bound ?? null;
|
|
84
85
|
const choose = (projectId) => {
|
|
@@ -114,7 +115,10 @@ export function GameTab(props) {
|
|
|
114
115
|
}
|
|
115
116
|
/** The bound-project workbench. */
|
|
116
117
|
function ProjectWorkbench(p) {
|
|
117
|
-
const { t, sessionId, api, project, view, setView, styling, setStyling, refresh, toast, insertDraft } = p;
|
|
118
|
+
const { t, sessionId, api, project, view, setView, styling, setStyling, refresh, toast, insertDraft, reveal } = p;
|
|
119
|
+
const [, rerender] = useState(0);
|
|
120
|
+
useEffect(() => reveal.subscribe(() => { rerender(n => n + 1); }), [reveal]);
|
|
121
|
+
const notice = reveal.notice;
|
|
118
122
|
const autoConfirm = project.manifest?.autoConfirm ?? true;
|
|
119
123
|
const style = project.manifest?.artStyle;
|
|
120
124
|
const exportCurrent = () => {
|
|
@@ -145,7 +149,8 @@ function ProjectWorkbench(p) {
|
|
|
145
149
|
];
|
|
146
150
|
const failing = project.lastCheck !== null && !project.lastCheck.ok;
|
|
147
151
|
const openProposals = project.proposals.filter(x => x.picked === undefined).length;
|
|
148
|
-
|
|
152
|
+
// Any touch in the panel means the user is busy here: the agent's request waits as a notice.
|
|
153
|
+
return _jsxs(PanelRoot, { className: css.root, onPointerDownCapture: () => { reveal.touched(); }, onKeyDownCapture: () => { reveal.touched(); }, children: [_jsx(PanelHeader, { title: _jsxs("button", { type: "button", className: css.titleSwitch, onClick: p.onPickProject, title: t('switch'), "aria-haspopup": "dialog", children: [_jsx("span", { children: project.title }), _jsx("span", { className: css.titleCaret, "aria-hidden": "true", children: "\u25BE" })] }), meta: _jsxs("span", { className: css.headMeta, children: [style !== undefined && _jsx("span", { title: artStyleLabel(style), children: _jsx(Tag, { tone: "quiet", children: artStyleName(style) }) }), _jsx(Tag, { tone: "quiet", children: project.current === null ? t('meta.noVersion') : t('meta.version', { version: project.current.version }) })] }), extra: _jsx("span", { className: css.switches, children: _jsxs("span", { className: css.switch, title: autoConfirm ? t('autoConfirm.onHint') : t('autoConfirm.offHint'), children: [_jsx(Switch, { checked: autoConfirm, label: t('autoConfirm.label'), onChange: next => { void api.setAutoConfirm(sessionId, project.id, next).then(() => { toast(next ? t('toast.autoOn') : t('toast.autoOff')); refresh(); }); } }), _jsx("span", { className: css.switchLabel, children: t('autoConfirm.label') })] }) }), actions: actions, moreLabel: t('more') }), _jsx(UnderlineTabs, { label: t('tabs.label'), value: view, onChange: setView, tabs: [
|
|
149
154
|
{ id: 'play', label: t('tabs.play'), badge: project.candidate !== null ? '●' : undefined },
|
|
150
155
|
{ id: 'elements', label: t('tabs.elements'), badge: project.elementErrors.length > 0 ? '!' : openProposals > 0 ? '●' : project.elements.length || undefined },
|
|
151
156
|
{ id: 'design', label: t('tabs.design') },
|
|
@@ -159,7 +164,7 @@ function ProjectWorkbench(p) {
|
|
|
159
164
|
setStyling(false);
|
|
160
165
|
refresh();
|
|
161
166
|
});
|
|
162
|
-
} })] }), _jsx(CommitBar, { ...p, project: project, onOpenVersions: () => { setView('versions'); } }), view === 'play' && _jsx(PlayView, { ...p, onOpenElement: id => { p.setOpenElement(id); setView('elements'); }, onOpenVersions: () => { setView('versions'); } }), view === 'elements' && _jsx(ElementsView, { ...p, openId: p.openElement, onOpen: p.setOpenElement }), view === 'design' && _jsx(DesignView, { ...p, openChapter: p.openChapter, onOpenChapter: p.setOpenChapter, onStyle: () => { setStyling(true); } }), view === 'versions' && _jsx(VersionsView, { ...p }), p.foot] });
|
|
167
|
+
} })] }), _jsx(CommitBar, { ...p, project: project, onOpenVersions: () => { setView('versions'); } }), notice !== null && _jsxs("div", { className: css.navNotice, role: "status", children: [_jsx("span", { className: css.navNoticeText, children: notice.text }), _jsx("button", { type: "button", className: css.primary, onClick: () => { reveal.follow(); }, children: t('nav.go') }), _jsx("button", { type: "button", className: css.link, onClick: () => { reveal.dismiss(); }, children: t('nav.dismiss') })] }), view === 'play' && _jsx(PlayView, { ...p, onOpenElement: id => { p.setOpenElement(id); setView('elements'); }, onOpenVersions: () => { setView('versions'); } }), view === 'elements' && _jsx(ElementsView, { ...p, openId: p.openElement, onOpen: p.setOpenElement }), view === 'design' && _jsx(DesignView, { ...p, openChapter: p.openChapter, onOpenChapter: p.setOpenChapter, onStyle: () => { setStyling(true); } }), view === 'versions' && _jsx(VersionsView, { ...p }), p.foot] });
|
|
163
168
|
}
|
|
164
169
|
/**
|
|
165
170
|
* 有新改动还没进游戏: whatever the working files hold that the play area
|
|
@@ -25,7 +25,7 @@ function fmt(value, step) {
|
|
|
25
25
|
}
|
|
26
26
|
/** The play view. */
|
|
27
27
|
export function PlayView(props) {
|
|
28
|
-
const { t, sessionId, api, project, refresh, toast, insertDraft, insertRef, onOpenElement, onOpenVersions } = props;
|
|
28
|
+
const { t, sessionId, api, project, refresh, toast, insertDraft, insertRef, onOpenElement, onOpenVersions, reveal } = props;
|
|
29
29
|
const [which, setWhich] = useState('current');
|
|
30
30
|
const [bundle, setBundle] = useState(null);
|
|
31
31
|
const [error, setError] = useState(null);
|
|
@@ -42,6 +42,8 @@ export function PlayView(props) {
|
|
|
42
42
|
// Playing is opt-in (2026-10-10): a big game should not start, and cost, on
|
|
43
43
|
// every visit. A new version stops the old run and shows its poster.
|
|
44
44
|
const [playing, setPlaying] = useState(false);
|
|
45
|
+
// A running game is never navigated away from (the agent's request waits as a notice).
|
|
46
|
+
useEffect(() => { reveal.setPlaying(playing); return () => { reveal.setPlaying(false); }; }, [reveal, playing]);
|
|
45
47
|
const [poster, setPoster] = useState(null);
|
|
46
48
|
useEffect(() => { setPlaying(false); setPicking(false); setPicked(null); }, [version, which]);
|
|
47
49
|
useEffect(() => {
|
|
@@ -39,6 +39,8 @@ export interface Preview3DProps {
|
|
|
39
39
|
readonly name: string;
|
|
40
40
|
readonly n: number;
|
|
41
41
|
} | null;
|
|
42
|
+
/** The user turned a turntable by hand (a named view no longer applies). */
|
|
43
|
+
readonly onTurned?: () => void;
|
|
42
44
|
/** A turntable turns to this side (yaw in degrees: 0 front, 90 side, 180 back; bump `n` to repeat). */
|
|
43
45
|
readonly view?: {
|
|
44
46
|
readonly yaw: number;
|
|
@@ -46,5 +48,5 @@ export interface Preview3DProps {
|
|
|
46
48
|
} | null;
|
|
47
49
|
}
|
|
48
50
|
/** One 3D look preview. */
|
|
49
|
-
export declare function Preview3D({ api, projectId, version, look, mode, className, emptyLabel, placeholder, onClips, clip, view }: Preview3DProps): ReactNode;
|
|
51
|
+
export declare function Preview3D({ api, projectId, version, look, mode, className, emptyLabel, placeholder, onClips, onTurned, clip, view }: Preview3DProps): ReactNode;
|
|
50
52
|
//# sourceMappingURL=Preview3D.d.ts.map
|
|
@@ -73,7 +73,7 @@ function stillSlot() {
|
|
|
73
73
|
return { ready, release };
|
|
74
74
|
}
|
|
75
75
|
/** One 3D look preview. */
|
|
76
|
-
export function Preview3D({ api, projectId, version, look, mode, className, emptyLabel, placeholder, onClips, clip, view }) {
|
|
76
|
+
export function Preview3D({ api, projectId, version, look, mode, className, emptyLabel, placeholder, onClips, onTurned, clip, view }) {
|
|
77
77
|
const lookJson = JSON.stringify(look);
|
|
78
78
|
const stillKey = `${projectId}:${version}:${lookJson}`;
|
|
79
79
|
const [files, setFiles] = useState(null);
|
|
@@ -138,10 +138,12 @@ export function Preview3D({ api, projectId, version, look, mode, className, empt
|
|
|
138
138
|
}
|
|
139
139
|
if (data?.gamedev === 'preview-clips' && mode === 'spin')
|
|
140
140
|
onClips?.(data.names, data.parts);
|
|
141
|
+
if (data?.gamedev === 'preview-turned' && mode === 'spin')
|
|
142
|
+
onTurned?.();
|
|
141
143
|
};
|
|
142
144
|
window.addEventListener('message', onMessage);
|
|
143
145
|
return () => { window.removeEventListener('message', onMessage); };
|
|
144
|
-
}, [mode, stillKey, onClips]);
|
|
146
|
+
}, [mode, stillKey, onClips, onTurned]);
|
|
145
147
|
useEffect(() => {
|
|
146
148
|
if (view == null || mode !== 'spin' || !booted.current)
|
|
147
149
|
return;
|