@khorsheed/dsh-game 0.0.0-stage → 0.1.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/CHANGELOG.md +17 -0
- package/README.en.md +53 -0
- package/README.i18n.yaml +6 -0
- package/README.md +52 -2
- package/cordis.patch.yml +23 -0
- package/lib/client.js +30348 -0
- package/lib/index.js +4154 -0
- package/lib/typert.host.d.ts +3 -0
- package/lib/typert.host.js +3769 -0
- package/lib/typert.remote-client.d.ts +101 -0
- package/lib/typert.remote-client.js +2082 -0
- package/lib/types/agent.d.ts +20 -0
- package/lib/types/agent.js +42 -0
- package/lib/types/checks.d.ts +44 -0
- package/lib/types/checks.js +267 -0
- package/lib/types/client/DesignView.d.ts +22 -0
- package/lib/types/client/DesignView.js +134 -0
- package/lib/types/client/ElementsView.d.ts +21 -0
- package/lib/types/client/ElementsView.js +187 -0
- package/lib/types/client/GameTab.d.ts +14 -0
- package/lib/types/client/GameTab.js +256 -0
- package/lib/types/client/PlayFrame.d.ts +54 -0
- package/lib/types/client/PlayFrame.js +129 -0
- package/lib/types/client/PlayView.d.ts +19 -0
- package/lib/types/client/PlayView.js +161 -0
- package/lib/types/client/Preview3D.d.ts +50 -0
- package/lib/types/client/Preview3D.js +176 -0
- package/lib/types/client/ProjectSwitcher.d.ts +20 -0
- package/lib/types/client/ProjectSwitcher.js +75 -0
- package/lib/types/client/Recipe3DEditor.d.ts +19 -0
- package/lib/types/client/Recipe3DEditor.js +44 -0
- package/lib/types/client/StyleGallery.d.ts +18 -0
- package/lib/types/client/StyleGallery.js +27 -0
- package/lib/types/client/TurnCard.d.ts +62 -0
- package/lib/types/client/TurnCard.js +100 -0
- package/lib/types/client/VersionsView.d.ts +17 -0
- package/lib/types/client/VersionsView.js +68 -0
- package/lib/types/client/chat-node.d.ts +42 -0
- package/lib/types/client/chat-node.js +77 -0
- package/lib/types/client/contract.d.ts +125 -0
- package/lib/types/client/contract.js +6 -0
- package/lib/types/client/definition.d.ts +22 -0
- package/lib/types/client/definition.js +28 -0
- package/lib/types/client/index.d.ts +21 -0
- package/lib/types/client/index.js +229 -0
- package/lib/types/client/locales.d.ts +376 -0
- package/lib/types/client/locales.js +727 -0
- package/lib/types/client/looks.d.ts +36 -0
- package/lib/types/client/looks.js +105 -0
- package/lib/types/client/markdown.d.ts +11 -0
- package/lib/types/client/markdown.js +52 -0
- package/lib/types/client/preset-visibility.d.ts +94 -0
- package/lib/types/client/preset-visibility.js +115 -0
- package/lib/types/client/preview-entry.d.ts +24 -0
- package/lib/types/client/preview-entry.js +107 -0
- package/lib/types/client/refs.d.ts +36 -0
- package/lib/types/client/refs.js +44 -0
- package/lib/types/client/style-samples.d.ts +5 -0
- package/lib/types/client/style-samples.js +196 -0
- package/lib/types/fsutil.d.ts +26 -0
- package/lib/types/fsutil.js +104 -0
- package/lib/types/hooks.d.ts +83 -0
- package/lib/types/hooks.js +108 -0
- package/lib/types/index.d.ts +30 -0
- package/lib/types/index.js +22 -0
- package/lib/types/kits/canvas2d.d.ts +6 -0
- package/lib/types/kits/canvas2d.js +60 -0
- package/lib/types/kits/ids.d.ts +11 -0
- package/lib/types/kits/ids.js +6 -0
- package/lib/types/kits/index.d.ts +26 -0
- package/lib/types/kits/index.js +28 -0
- package/lib/types/kits/three3d.d.ts +12 -0
- package/lib/types/kits/three3d.js +188 -0
- package/lib/types/kits/types.d.ts +52 -0
- package/lib/types/kits/types.js +6 -0
- package/lib/types/look3d.d.ts +20 -0
- package/lib/types/look3d.js +175 -0
- package/lib/types/panel-session.d.ts +21 -0
- package/lib/types/panel-session.js +16 -0
- package/lib/types/project.d.ts +132 -0
- package/lib/types/project.js +494 -0
- package/lib/types/remote.d.ts +182 -0
- package/lib/types/remote.js +256 -0
- package/lib/types/skills.d.ts +13 -0
- package/lib/types/skills.js +140 -0
- package/lib/types/store.d.ts +325 -0
- package/lib/types/store.js +1285 -0
- package/lib/types/tools.d.ts +12 -0
- package/lib/types/tools.js +301 -0
- package/lib/types/trash.d.ts +5 -0
- package/lib/types/trash.js +64 -0
- package/lib/types/types.d.ts +522 -0
- package/lib/types/types.js +85 -0
- package/lib/types/vfs.d.ts +92 -0
- package/lib/types/vfs.js +217 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +132 -3
- package/runtime/dsh3d.js +1279 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The game Remote service: the panel's data face, namespace `game`. A thin
|
|
3
|
+
* adapter over `ctx.gameStore`. Methods that read or act for a session take
|
|
4
|
+
* its id first and resolve it with {@link panelSession} (subagent sessions
|
|
5
|
+
* included); project-addressed reads take none.
|
|
6
|
+
* @module @khorsheed/dsh-game
|
|
7
|
+
*/
|
|
8
|
+
import type { SessionId } from '@deepseek-ai/dsh-session/types';
|
|
9
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
10
|
+
import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
|
|
11
|
+
import type { BundleFile, CommitResult, DeleteProjectResult, WorkingChanges, GameResult, PlayBundle, ProjectCard, SessionGameState, TurnReport, VersionDiff } from './types.ts';
|
|
12
|
+
declare module '@deepseek-ai/cordis' {
|
|
13
|
+
interface Context {
|
|
14
|
+
/** The game panel's Remote face. */
|
|
15
|
+
gameRemote: GameRemoteService;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** Remote construction options (reserved). */
|
|
19
|
+
export interface GameRemoteConfig {
|
|
20
|
+
}
|
|
21
|
+
/** The `game` wire namespace. */
|
|
22
|
+
export declare class GameRemoteService extends TypertRemoteService<GameRemoteConfig> {
|
|
23
|
+
static inject: string[];
|
|
24
|
+
/**
|
|
25
|
+
* @param ctx - host context carrying the service core.
|
|
26
|
+
* @param _config - reserved.
|
|
27
|
+
*/
|
|
28
|
+
constructor(ctx: Context, _config?: GameRemoteConfig);
|
|
29
|
+
private get store();
|
|
30
|
+
/** The session's bound project (full view) and the project list. */
|
|
31
|
+
state(sessionId: SessionId): Promise<SessionGameState>;
|
|
32
|
+
/** What one of the session's turns changed (null when nothing, or not recorded). */
|
|
33
|
+
turnReport(sessionId: SessionId, request: {
|
|
34
|
+
turn: number;
|
|
35
|
+
}): Promise<TurnReport | null>;
|
|
36
|
+
/** Every project as a switcher card. */
|
|
37
|
+
projectCards(): Promise<ProjectCard[]>;
|
|
38
|
+
/** Delete a project: `trash` moves its folder to the system trash, `forget` only removes it from the plugin. */
|
|
39
|
+
deleteProject(sessionId: SessionId, request: {
|
|
40
|
+
projectId: string;
|
|
41
|
+
mode: 'trash' | 'forget';
|
|
42
|
+
}): Promise<DeleteProjectResult>;
|
|
43
|
+
/** Bind the session to a project, or unbind with `projectId: null`. */
|
|
44
|
+
bind(sessionId: SessionId, request: {
|
|
45
|
+
projectId: string | null;
|
|
46
|
+
}): Promise<GameResult>;
|
|
47
|
+
/** One working build file, for a panel preview ahead of any version. */
|
|
48
|
+
workingFile(request: {
|
|
49
|
+
projectId: string;
|
|
50
|
+
path: string;
|
|
51
|
+
}): Promise<GameResult<{
|
|
52
|
+
readonly ok: true;
|
|
53
|
+
readonly file: BundleFile;
|
|
54
|
+
}>>;
|
|
55
|
+
/** A version's files for the play area. */
|
|
56
|
+
bundle(request: {
|
|
57
|
+
projectId: string;
|
|
58
|
+
which?: 'current' | 'candidate';
|
|
59
|
+
}): Promise<GameResult<{
|
|
60
|
+
readonly ok: true;
|
|
61
|
+
readonly bundle: PlayBundle;
|
|
62
|
+
}>>;
|
|
63
|
+
/** Promote the candidate into the play area. */
|
|
64
|
+
confirm(sessionId: SessionId, request: {
|
|
65
|
+
projectId: string;
|
|
66
|
+
}): Promise<GameResult<{
|
|
67
|
+
readonly ok: true;
|
|
68
|
+
readonly version: number;
|
|
69
|
+
}>>;
|
|
70
|
+
/** What the working files hold that the play area does not (the commit bar polls it). */
|
|
71
|
+
changes(request: {
|
|
72
|
+
projectId: string;
|
|
73
|
+
}): Promise<GameResult<WorkingChanges & {
|
|
74
|
+
readonly ok: true;
|
|
75
|
+
}>>;
|
|
76
|
+
/** 检查并发版: check the working files and cut a version (by the user) carrying every change. */
|
|
77
|
+
commit(sessionId: SessionId, request: {
|
|
78
|
+
projectId: string;
|
|
79
|
+
}): Promise<GameResult<CommitResult>>;
|
|
80
|
+
/** Switch the project's auto-confirm. */
|
|
81
|
+
setAutoConfirm(sessionId: SessionId, request: {
|
|
82
|
+
projectId: string;
|
|
83
|
+
on: boolean;
|
|
84
|
+
}): Promise<GameResult>;
|
|
85
|
+
/** Record one play session into the playtest log. */
|
|
86
|
+
logPlay(sessionId: SessionId, request: {
|
|
87
|
+
projectId: string;
|
|
88
|
+
version: number;
|
|
89
|
+
seconds: number;
|
|
90
|
+
errors: string[];
|
|
91
|
+
}): Promise<GameResult>;
|
|
92
|
+
/** Drop one pending change (the dock's ×). */
|
|
93
|
+
dropPending(sessionId: SessionId, request: {
|
|
94
|
+
projectId: string;
|
|
95
|
+
key: string;
|
|
96
|
+
}): Promise<GameResult>;
|
|
97
|
+
/** Set one slider value (user layer). */
|
|
98
|
+
setParam(sessionId: SessionId, request: {
|
|
99
|
+
projectId: string;
|
|
100
|
+
key: string;
|
|
101
|
+
value: number;
|
|
102
|
+
}): Promise<GameResult>;
|
|
103
|
+
/** 定稿: write slider values into game.json. */
|
|
104
|
+
finalizeParams(sessionId: SessionId, request: {
|
|
105
|
+
projectId: string;
|
|
106
|
+
}): Promise<GameResult>;
|
|
107
|
+
/** 还原: drop the slider overrides. */
|
|
108
|
+
resetParams(sessionId: SessionId, request: {
|
|
109
|
+
projectId: string;
|
|
110
|
+
}): Promise<GameResult>;
|
|
111
|
+
/** Edit one element's look (JSON text) and/or scalar fields (JSON text of an object). */
|
|
112
|
+
editElement(sessionId: SessionId, request: {
|
|
113
|
+
projectId: string;
|
|
114
|
+
elementId: string;
|
|
115
|
+
look?: string;
|
|
116
|
+
fields?: string;
|
|
117
|
+
}): Promise<GameResult<{
|
|
118
|
+
readonly ok: true;
|
|
119
|
+
readonly elementJson: string;
|
|
120
|
+
}>>;
|
|
121
|
+
/** Pick one appearance variant. */
|
|
122
|
+
pickProposal(sessionId: SessionId, request: {
|
|
123
|
+
projectId: string;
|
|
124
|
+
elementId: string;
|
|
125
|
+
at: string;
|
|
126
|
+
index: number;
|
|
127
|
+
}): Promise<GameResult>;
|
|
128
|
+
/** Write a design chapter. */
|
|
129
|
+
writeChapter(sessionId: SessionId, request: {
|
|
130
|
+
projectId: string;
|
|
131
|
+
chapterId: string;
|
|
132
|
+
text: string;
|
|
133
|
+
}): Promise<GameResult>;
|
|
134
|
+
/** Edit the one-pager (game.json pitch / element types / pillars). */
|
|
135
|
+
setOnePager(sessionId: SessionId, request: {
|
|
136
|
+
projectId: string;
|
|
137
|
+
pitch?: string;
|
|
138
|
+
elementTypes?: string;
|
|
139
|
+
pillars?: string;
|
|
140
|
+
}): Promise<GameResult>;
|
|
141
|
+
/** Mark a pending restyle (the next passing version becomes a candidate). */
|
|
142
|
+
requestRestyle(sessionId: SessionId, request: {
|
|
143
|
+
projectId: string;
|
|
144
|
+
styleId: string;
|
|
145
|
+
}): Promise<GameResult>;
|
|
146
|
+
/** Throw the candidate away. */
|
|
147
|
+
reject(sessionId: SessionId, request: {
|
|
148
|
+
projectId: string;
|
|
149
|
+
reason: string;
|
|
150
|
+
}): Promise<GameResult>;
|
|
151
|
+
/** Put an older version into the play area. */
|
|
152
|
+
rollback(sessionId: SessionId, request: {
|
|
153
|
+
projectId: string;
|
|
154
|
+
version: number;
|
|
155
|
+
}): Promise<GameResult>;
|
|
156
|
+
/** Files that differ between two versions. */
|
|
157
|
+
diff(request: {
|
|
158
|
+
projectId: string;
|
|
159
|
+
from: number;
|
|
160
|
+
to: number;
|
|
161
|
+
}): Promise<GameResult<{
|
|
162
|
+
readonly ok: true;
|
|
163
|
+
readonly diff: VersionDiff;
|
|
164
|
+
}>>;
|
|
165
|
+
/** The last check's screenshot. */
|
|
166
|
+
checkShot(request: {
|
|
167
|
+
projectId: string;
|
|
168
|
+
version?: number;
|
|
169
|
+
}): Promise<GameResult<{
|
|
170
|
+
readonly ok: true;
|
|
171
|
+
readonly webp: string;
|
|
172
|
+
}>>;
|
|
173
|
+
/** A specific version's files (rollback preview, export). */
|
|
174
|
+
versionBundle(request: {
|
|
175
|
+
projectId: string;
|
|
176
|
+
version: number;
|
|
177
|
+
}): Promise<GameResult<{
|
|
178
|
+
readonly ok: true;
|
|
179
|
+
readonly bundle: PlayBundle;
|
|
180
|
+
}>>;
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=remote.d.ts.map
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
2
|
+
var useValue = arguments.length > 2;
|
|
3
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
4
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
5
|
+
}
|
|
6
|
+
return useValue ? value : void 0;
|
|
7
|
+
};
|
|
8
|
+
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
9
|
+
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
10
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
11
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
12
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
13
|
+
var _, done = false;
|
|
14
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
15
|
+
var context = {};
|
|
16
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
17
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
18
|
+
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
19
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
20
|
+
if (kind === "accessor") {
|
|
21
|
+
if (result === void 0) continue;
|
|
22
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
23
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
24
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
25
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
26
|
+
}
|
|
27
|
+
else if (_ = accept(result)) {
|
|
28
|
+
if (kind === "field") initializers.unshift(_);
|
|
29
|
+
else descriptor[key] = _;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
33
|
+
done = true;
|
|
34
|
+
};
|
|
35
|
+
import { Remote, TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
|
|
36
|
+
import { panelSession } from "./panel-session.js";
|
|
37
|
+
/** The `game` wire namespace. */
|
|
38
|
+
let GameRemoteService = (() => {
|
|
39
|
+
let _classSuper = TypertRemoteService;
|
|
40
|
+
let _instanceExtraInitializers = [];
|
|
41
|
+
let _state_decorators;
|
|
42
|
+
let _turnReport_decorators;
|
|
43
|
+
let _projectCards_decorators;
|
|
44
|
+
let _deleteProject_decorators;
|
|
45
|
+
let _bind_decorators;
|
|
46
|
+
let _workingFile_decorators;
|
|
47
|
+
let _bundle_decorators;
|
|
48
|
+
let _confirm_decorators;
|
|
49
|
+
let _changes_decorators;
|
|
50
|
+
let _commit_decorators;
|
|
51
|
+
let _setAutoConfirm_decorators;
|
|
52
|
+
let _logPlay_decorators;
|
|
53
|
+
let _dropPending_decorators;
|
|
54
|
+
let _setParam_decorators;
|
|
55
|
+
let _finalizeParams_decorators;
|
|
56
|
+
let _resetParams_decorators;
|
|
57
|
+
let _editElement_decorators;
|
|
58
|
+
let _pickProposal_decorators;
|
|
59
|
+
let _writeChapter_decorators;
|
|
60
|
+
let _setOnePager_decorators;
|
|
61
|
+
let _requestRestyle_decorators;
|
|
62
|
+
let _reject_decorators;
|
|
63
|
+
let _rollback_decorators;
|
|
64
|
+
let _diff_decorators;
|
|
65
|
+
let _checkShot_decorators;
|
|
66
|
+
let _versionBundle_decorators;
|
|
67
|
+
return class GameRemoteService extends _classSuper {
|
|
68
|
+
static {
|
|
69
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
70
|
+
_state_decorators = [Remote('state')];
|
|
71
|
+
_turnReport_decorators = [Remote('turnReport')];
|
|
72
|
+
_projectCards_decorators = [Remote('projectCards')];
|
|
73
|
+
_deleteProject_decorators = [Remote('deleteProject')];
|
|
74
|
+
_bind_decorators = [Remote('bind')];
|
|
75
|
+
_workingFile_decorators = [Remote('workingFile')];
|
|
76
|
+
_bundle_decorators = [Remote('bundle')];
|
|
77
|
+
_confirm_decorators = [Remote('confirm')];
|
|
78
|
+
_changes_decorators = [Remote('changes')];
|
|
79
|
+
_commit_decorators = [Remote('commit')];
|
|
80
|
+
_setAutoConfirm_decorators = [Remote('setAutoConfirm')];
|
|
81
|
+
_logPlay_decorators = [Remote('logPlay')];
|
|
82
|
+
_dropPending_decorators = [Remote('dropPending')];
|
|
83
|
+
_setParam_decorators = [Remote('setParam')];
|
|
84
|
+
_finalizeParams_decorators = [Remote('finalizeParams')];
|
|
85
|
+
_resetParams_decorators = [Remote('resetParams')];
|
|
86
|
+
_editElement_decorators = [Remote('editElement')];
|
|
87
|
+
_pickProposal_decorators = [Remote('pickProposal')];
|
|
88
|
+
_writeChapter_decorators = [Remote('writeChapter')];
|
|
89
|
+
_setOnePager_decorators = [Remote('setOnePager')];
|
|
90
|
+
_requestRestyle_decorators = [Remote('requestRestyle')];
|
|
91
|
+
_reject_decorators = [Remote('reject')];
|
|
92
|
+
_rollback_decorators = [Remote('rollback')];
|
|
93
|
+
_diff_decorators = [Remote('diff')];
|
|
94
|
+
_checkShot_decorators = [Remote('checkShot')];
|
|
95
|
+
_versionBundle_decorators = [Remote('versionBundle')];
|
|
96
|
+
__esDecorate(this, null, _state_decorators, { kind: "method", name: "state", static: false, private: false, access: { has: obj => "state" in obj, get: obj => obj.state }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
97
|
+
__esDecorate(this, null, _turnReport_decorators, { kind: "method", name: "turnReport", static: false, private: false, access: { has: obj => "turnReport" in obj, get: obj => obj.turnReport }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
98
|
+
__esDecorate(this, null, _projectCards_decorators, { kind: "method", name: "projectCards", static: false, private: false, access: { has: obj => "projectCards" in obj, get: obj => obj.projectCards }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
99
|
+
__esDecorate(this, null, _deleteProject_decorators, { kind: "method", name: "deleteProject", static: false, private: false, access: { has: obj => "deleteProject" in obj, get: obj => obj.deleteProject }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
100
|
+
__esDecorate(this, null, _bind_decorators, { kind: "method", name: "bind", static: false, private: false, access: { has: obj => "bind" in obj, get: obj => obj.bind }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
101
|
+
__esDecorate(this, null, _workingFile_decorators, { kind: "method", name: "workingFile", static: false, private: false, access: { has: obj => "workingFile" in obj, get: obj => obj.workingFile }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
102
|
+
__esDecorate(this, null, _bundle_decorators, { kind: "method", name: "bundle", static: false, private: false, access: { has: obj => "bundle" in obj, get: obj => obj.bundle }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
103
|
+
__esDecorate(this, null, _confirm_decorators, { kind: "method", name: "confirm", static: false, private: false, access: { has: obj => "confirm" in obj, get: obj => obj.confirm }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
104
|
+
__esDecorate(this, null, _changes_decorators, { kind: "method", name: "changes", static: false, private: false, access: { has: obj => "changes" in obj, get: obj => obj.changes }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
105
|
+
__esDecorate(this, null, _commit_decorators, { kind: "method", name: "commit", static: false, private: false, access: { has: obj => "commit" in obj, get: obj => obj.commit }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
106
|
+
__esDecorate(this, null, _setAutoConfirm_decorators, { kind: "method", name: "setAutoConfirm", static: false, private: false, access: { has: obj => "setAutoConfirm" in obj, get: obj => obj.setAutoConfirm }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
107
|
+
__esDecorate(this, null, _logPlay_decorators, { kind: "method", name: "logPlay", static: false, private: false, access: { has: obj => "logPlay" in obj, get: obj => obj.logPlay }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
108
|
+
__esDecorate(this, null, _dropPending_decorators, { kind: "method", name: "dropPending", static: false, private: false, access: { has: obj => "dropPending" in obj, get: obj => obj.dropPending }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
109
|
+
__esDecorate(this, null, _setParam_decorators, { kind: "method", name: "setParam", static: false, private: false, access: { has: obj => "setParam" in obj, get: obj => obj.setParam }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
110
|
+
__esDecorate(this, null, _finalizeParams_decorators, { kind: "method", name: "finalizeParams", static: false, private: false, access: { has: obj => "finalizeParams" in obj, get: obj => obj.finalizeParams }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
111
|
+
__esDecorate(this, null, _resetParams_decorators, { kind: "method", name: "resetParams", static: false, private: false, access: { has: obj => "resetParams" in obj, get: obj => obj.resetParams }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
112
|
+
__esDecorate(this, null, _editElement_decorators, { kind: "method", name: "editElement", static: false, private: false, access: { has: obj => "editElement" in obj, get: obj => obj.editElement }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
113
|
+
__esDecorate(this, null, _pickProposal_decorators, { kind: "method", name: "pickProposal", static: false, private: false, access: { has: obj => "pickProposal" in obj, get: obj => obj.pickProposal }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
114
|
+
__esDecorate(this, null, _writeChapter_decorators, { kind: "method", name: "writeChapter", static: false, private: false, access: { has: obj => "writeChapter" in obj, get: obj => obj.writeChapter }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
115
|
+
__esDecorate(this, null, _setOnePager_decorators, { kind: "method", name: "setOnePager", static: false, private: false, access: { has: obj => "setOnePager" in obj, get: obj => obj.setOnePager }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
116
|
+
__esDecorate(this, null, _requestRestyle_decorators, { kind: "method", name: "requestRestyle", static: false, private: false, access: { has: obj => "requestRestyle" in obj, get: obj => obj.requestRestyle }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
117
|
+
__esDecorate(this, null, _reject_decorators, { kind: "method", name: "reject", static: false, private: false, access: { has: obj => "reject" in obj, get: obj => obj.reject }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
118
|
+
__esDecorate(this, null, _rollback_decorators, { kind: "method", name: "rollback", static: false, private: false, access: { has: obj => "rollback" in obj, get: obj => obj.rollback }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
119
|
+
__esDecorate(this, null, _diff_decorators, { kind: "method", name: "diff", static: false, private: false, access: { has: obj => "diff" in obj, get: obj => obj.diff }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
120
|
+
__esDecorate(this, null, _checkShot_decorators, { kind: "method", name: "checkShot", static: false, private: false, access: { has: obj => "checkShot" in obj, get: obj => obj.checkShot }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
121
|
+
__esDecorate(this, null, _versionBundle_decorators, { kind: "method", name: "versionBundle", static: false, private: false, access: { has: obj => "versionBundle" in obj, get: obj => obj.versionBundle }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
122
|
+
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
123
|
+
}
|
|
124
|
+
static inject = ['gameStore'];
|
|
125
|
+
/**
|
|
126
|
+
* @param ctx - host context carrying the service core.
|
|
127
|
+
* @param _config - reserved.
|
|
128
|
+
*/
|
|
129
|
+
constructor(ctx, _config = {}) {
|
|
130
|
+
super(ctx, 'gameRemote', { namespace: 'game' });
|
|
131
|
+
__runInitializers(this, _instanceExtraInitializers);
|
|
132
|
+
}
|
|
133
|
+
get store() {
|
|
134
|
+
return this.ctx.gameStore;
|
|
135
|
+
}
|
|
136
|
+
/** The session's bound project (full view) and the project list. */
|
|
137
|
+
state(sessionId) {
|
|
138
|
+
return this.store.sessionState(sessionId);
|
|
139
|
+
}
|
|
140
|
+
/** What one of the session's turns changed (null when nothing, or not recorded). */
|
|
141
|
+
turnReport(sessionId, request) {
|
|
142
|
+
return this.store.turnReport(sessionId, request.turn);
|
|
143
|
+
}
|
|
144
|
+
/** Every project as a switcher card. */
|
|
145
|
+
projectCards() {
|
|
146
|
+
return this.store.projectCards();
|
|
147
|
+
}
|
|
148
|
+
/** Delete a project: `trash` moves its folder to the system trash, `forget` only removes it from the plugin. */
|
|
149
|
+
async deleteProject(sessionId, request) {
|
|
150
|
+
return this.store.deleteProject(request.projectId, request.mode === 'forget' ? 'forget' : 'trash', await panelSession(this.ctx, sessionId));
|
|
151
|
+
}
|
|
152
|
+
/** Bind the session to a project, or unbind with `projectId: null`. */
|
|
153
|
+
bind(sessionId, request) {
|
|
154
|
+
return this.store.bind(sessionId, request.projectId);
|
|
155
|
+
}
|
|
156
|
+
/** One working build file, for a panel preview ahead of any version. */
|
|
157
|
+
workingFile(request) {
|
|
158
|
+
return this.store.workingFile(request.projectId, request.path);
|
|
159
|
+
}
|
|
160
|
+
/** A version's files for the play area. */
|
|
161
|
+
bundle(request) {
|
|
162
|
+
return this.store.bundle(request.projectId, request.which ?? 'current');
|
|
163
|
+
}
|
|
164
|
+
/** Promote the candidate into the play area. */
|
|
165
|
+
async confirm(sessionId, request) {
|
|
166
|
+
return this.store.confirm(request.projectId, await panelSession(this.ctx, sessionId));
|
|
167
|
+
}
|
|
168
|
+
/** What the working files hold that the play area does not (the commit bar polls it). */
|
|
169
|
+
changes(request) {
|
|
170
|
+
return this.store.changes(request.projectId);
|
|
171
|
+
}
|
|
172
|
+
/** 检查并发版: check the working files and cut a version (by the user) carrying every change. */
|
|
173
|
+
async commit(sessionId, request) {
|
|
174
|
+
return this.store.commit(request.projectId, await panelSession(this.ctx, sessionId));
|
|
175
|
+
}
|
|
176
|
+
/** Switch the project's auto-confirm. */
|
|
177
|
+
async setAutoConfirm(sessionId, request) {
|
|
178
|
+
return this.store.setAutoConfirm(request.projectId, request.on, await panelSession(this.ctx, sessionId));
|
|
179
|
+
}
|
|
180
|
+
/** Record one play session into the playtest log. */
|
|
181
|
+
async logPlay(sessionId, request) {
|
|
182
|
+
return this.store.logPlay(request.projectId, request, await panelSession(this.ctx, sessionId));
|
|
183
|
+
}
|
|
184
|
+
/** Drop one pending change (the dock's ×). */
|
|
185
|
+
async dropPending(sessionId, request) {
|
|
186
|
+
return this.store.dropPending(request.projectId, request.key, await panelSession(this.ctx, sessionId));
|
|
187
|
+
}
|
|
188
|
+
/** Set one slider value (user layer). */
|
|
189
|
+
async setParam(sessionId, request) {
|
|
190
|
+
return this.store.setParam(request.projectId, request.key, request.value, await panelSession(this.ctx, sessionId));
|
|
191
|
+
}
|
|
192
|
+
/** 定稿: write slider values into game.json. */
|
|
193
|
+
async finalizeParams(sessionId, request) {
|
|
194
|
+
return this.store.finalizeParams(request.projectId, await panelSession(this.ctx, sessionId));
|
|
195
|
+
}
|
|
196
|
+
/** 还原: drop the slider overrides. */
|
|
197
|
+
async resetParams(sessionId, request) {
|
|
198
|
+
return this.store.resetParams(request.projectId, await panelSession(this.ctx, sessionId));
|
|
199
|
+
}
|
|
200
|
+
/** Edit one element's look (JSON text) and/or scalar fields (JSON text of an object). */
|
|
201
|
+
async editElement(sessionId, request) {
|
|
202
|
+
let look;
|
|
203
|
+
let fields;
|
|
204
|
+
try {
|
|
205
|
+
if (request.look !== undefined)
|
|
206
|
+
look = JSON.parse(request.look);
|
|
207
|
+
if (request.fields !== undefined)
|
|
208
|
+
fields = JSON.parse(request.fields);
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
return { ok: false, error: 'invalid' };
|
|
212
|
+
}
|
|
213
|
+
const result = await this.store.editElement(request.projectId, request.elementId, {
|
|
214
|
+
...(look === undefined ? {} : { look }), ...(fields === undefined ? {} : { fields }),
|
|
215
|
+
}, await panelSession(this.ctx, sessionId));
|
|
216
|
+
return result.ok ? { ok: true, elementJson: JSON.stringify(result.element) } : result;
|
|
217
|
+
}
|
|
218
|
+
/** Pick one appearance variant. */
|
|
219
|
+
async pickProposal(sessionId, request) {
|
|
220
|
+
return this.store.pickProposal(request.projectId, request.elementId, request.at, request.index, await panelSession(this.ctx, sessionId));
|
|
221
|
+
}
|
|
222
|
+
/** Write a design chapter. */
|
|
223
|
+
async writeChapter(sessionId, request) {
|
|
224
|
+
return this.store.writeChapter(request.projectId, request.chapterId, request.text, await panelSession(this.ctx, sessionId));
|
|
225
|
+
}
|
|
226
|
+
/** Edit the one-pager (game.json pitch / element types / pillars). */
|
|
227
|
+
async setOnePager(sessionId, request) {
|
|
228
|
+
return this.store.setOnePager(request.projectId, request, await panelSession(this.ctx, sessionId));
|
|
229
|
+
}
|
|
230
|
+
/** Mark a pending restyle (the next passing version becomes a candidate). */
|
|
231
|
+
async requestRestyle(sessionId, request) {
|
|
232
|
+
return this.store.requestRestyle(request.projectId, request.styleId, await panelSession(this.ctx, sessionId));
|
|
233
|
+
}
|
|
234
|
+
/** Throw the candidate away. */
|
|
235
|
+
async reject(sessionId, request) {
|
|
236
|
+
return this.store.reject(request.projectId, request.reason, await panelSession(this.ctx, sessionId));
|
|
237
|
+
}
|
|
238
|
+
/** Put an older version into the play area. */
|
|
239
|
+
async rollback(sessionId, request) {
|
|
240
|
+
return this.store.rollback(request.projectId, request.version, await panelSession(this.ctx, sessionId));
|
|
241
|
+
}
|
|
242
|
+
/** Files that differ between two versions. */
|
|
243
|
+
diff(request) {
|
|
244
|
+
return this.store.diff(request.projectId, request.from, request.to);
|
|
245
|
+
}
|
|
246
|
+
/** The last check's screenshot. */
|
|
247
|
+
checkShot(request) {
|
|
248
|
+
return this.store.checkShot(request.projectId, request.version);
|
|
249
|
+
}
|
|
250
|
+
/** A specific version's files (rollback preview, export). */
|
|
251
|
+
versionBundle(request) {
|
|
252
|
+
return this.store.versionBundle(request.projectId, request.version);
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
})();
|
|
256
|
+
export { GameRemoteService };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** One skill as the registry takes it. */
|
|
2
|
+
export interface GameSkill {
|
|
3
|
+
readonly name: string;
|
|
4
|
+
readonly description: string;
|
|
5
|
+
readonly content: string;
|
|
6
|
+
}
|
|
7
|
+
/** The mechanics skill. */
|
|
8
|
+
export declare const GAMEDEV_SKILL: GameSkill;
|
|
9
|
+
/** The mentoring skill. */
|
|
10
|
+
export declare const GAME_DESIGN_SKILL: GameSkill;
|
|
11
|
+
/** Both skills, registration order. */
|
|
12
|
+
export declare const GAME_SKILLS: readonly GameSkill[];
|
|
13
|
+
//# sourceMappingURL=skills.d.ts.map
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The game mode's two skills (decision D11: one agent, preset prompt plus
|
|
3
|
+
* skills — no separate designer agent):
|
|
4
|
+
*
|
|
5
|
+
* - `gamedev`: the mechanics — project layout, the `window.dshGame` contract
|
|
6
|
+
* the checks and the play area rely on, element files, test scripts, what
|
|
7
|
+
* happens at the end of a turn.
|
|
8
|
+
* - `game-design`: the mentoring — how to take a non-designer from an idea to
|
|
9
|
+
* a one-pager, pillars and a core loop, and how to read a playtest.
|
|
10
|
+
*
|
|
11
|
+
* The `./agent` entry registers both beside the tools.
|
|
12
|
+
* @module @khorsheed/dsh-game/agent
|
|
13
|
+
*/
|
|
14
|
+
import { CANVAS_2D } from "./kits/canvas2d.js";
|
|
15
|
+
import { THREE_3D } from "./kits/three3d.js";
|
|
16
|
+
/** The mechanics skill. */
|
|
17
|
+
export const GAMEDEV_SKILL = {
|
|
18
|
+
name: 'gamedev',
|
|
19
|
+
description: 'How to build a game in the game panel: project layout, the window.dshGame contract, element files, '
|
|
20
|
+
+ 'tests/*.test.js, and the end-of-turn checks that deploy into the play area. Load before writing game code.',
|
|
21
|
+
content: `# gamedev —— 在游戏面板里做游戏
|
|
22
|
+
|
|
23
|
+
## 项目
|
|
24
|
+
- 用 game_open 建项目(过轻量门:title、pitch、elementTypes、artStyle 都得是用户认可的)。项目是会话工作区里的一个文件夹,game_open 会告诉你路径;之后用普通的文件工具读写其中的文件。
|
|
25
|
+
- 目录:
|
|
26
|
+
- \`game.json\` 清单(插件写的;改 pitch/支柱/元素类型可以直接编辑,保持合法 JSON)
|
|
27
|
+
- \`index.html\` 入口,\`src/\` 代码(ES module,相对路径 import),\`assets/\` 图片音频(png/jpg/webp、mp3/wav/ogg 都行,用相对路径 \`assets/xx.png\` 引用;游戏里不能联网,所有素材都放项目里。单个文件 8MB 以内、全部 48MB 以内,图片建议 1024 像素以内)
|
|
28
|
+
- \`elements/*.json\` 元素:每个文件一个对象或对象数组,必须有 \`id\`、\`name\`、\`type\`(type 取 game.json 的 elementTypes 之一)。数值放顶层字段(hp、speed、cost……),面板会自动汇成「元素与数值」表;外观放 \`look\`(见下);设定放 \`lore\`(见下)。
|
|
29
|
+
- \`design/*.md\` 策划文档(见 game-design 技能)
|
|
30
|
+
- \`tests/*.test.js\` 测试脚本
|
|
31
|
+
- \`.game/\` 插件自己的状态,别动
|
|
32
|
+
- game_read 看项目现状:章节状态、元素、最近一次检查、当前版本。
|
|
33
|
+
|
|
34
|
+
先看 game.json 的 runtime:没写或是 2d-canvas 用 2D 套件,3d-three 用 3D 套件。只按对应那一节写。
|
|
35
|
+
|
|
36
|
+
${CANVAS_2D.skillSection}
|
|
37
|
+
${THREE_3D.skillSection}
|
|
38
|
+
## 参数、元素与外观(面板能直接调的部分)
|
|
39
|
+
- **参数**:值得边玩边调的数(速度、间隔、伤害、难度系数)声明在 game.json 的 \`params\`:
|
|
40
|
+
\`[{ "key": "speed", "label": "移动速度", "min": 20, "max": 120, "step": 1, "value": 60, "unit": "px/s" }]\`。
|
|
41
|
+
代码**每帧**从 \`window.dshParams.speed\` 读,不要缓存到变量里——用户在右栏拖滑块时值会被直接改掉。参数控制在 3–8 个。
|
|
42
|
+
- **元素**:运行时从 \`window.dshElements[id]\` 读(加载器已把 elements/*.json 全部放进去),同样每帧读,用户在面板改了外观或数值会热替换。
|
|
43
|
+
- **外观 look**:格式和画法见上面「运行环境」一节。**游戏里看得见的元素都要有 look**——主角、敌人、道具,也包括树、石头、建筑这类场景物件;代码按 look 画,别另外手写一份。只有看不见的(规则、能力这类)可以没有。没有 look 的元素,右栏只能显示一个字,用户看不到也改不了它的样子。
|
|
44
|
+
- 用户要你改某个元素的样子时,用 **game_propose** 一次给 3 个方案(看得出差别:轮廓、配色、细节各不同),让用户在右栏挑;挑中的会自动替换进游戏,你别再自己写 look。
|
|
45
|
+
- **设定 lore**:每个元素都写一段 \`lore\` 字符串——它是谁、从哪来(有出处就引原文)、什么脾气、遇到玩家会怎样。新建元素时一并写,用户可以在面板里改;它的行为、台词、提示文字都照设定来。用户改了设定,就按新设定调整代码。策划里的「元素设定」章节由它自动汇总,不用另写。
|
|
46
|
+
- 美术风格要换时(右栏会附上「换风格」请求):重画所有 look,更新 game.json 的 \`artStyle\` 与 \`palette\`;那个版本会作为候选等用户确认。
|
|
47
|
+
|
|
48
|
+
## window.dshGame 约定(必须)
|
|
49
|
+
入口加载完后在 window 上挂:
|
|
50
|
+
\`\`\`js
|
|
51
|
+
window.dshGame = {
|
|
52
|
+
ready: true, // 资源就绪后置 true
|
|
53
|
+
step(dt) {}, // 推进 dt 秒的游戏逻辑(不依赖真实时间),测试靠它
|
|
54
|
+
input(key, down) {}, // 模拟按键,key 用 KeyboardEvent.key('ArrowRight'、' '、'z')
|
|
55
|
+
state() { return {...} }, // 返回可序列化的关键状态(玩家位置、分数、关卡……)
|
|
56
|
+
pick(x, y) { return id }, // 可选但建议:画布坐标上是哪个元素,返回元素 id 或 null(右栏「点选」用)
|
|
57
|
+
look(dx, dy) {}, // 可选:鼠标拖动转视角(测试里的 drag 调它)
|
|
58
|
+
loading: false, // 加载资源期间设 true,检查会多等(最多 20 秒)
|
|
59
|
+
}
|
|
60
|
+
\`\`\`
|
|
61
|
+
游戏主循环用 requestAnimationFrame 调同一个 step,键盘事件转给同一个 input,这样测试和真玩走的是同一套逻辑。用 \`window.__GAMEDEV_TEST__\` 判断是否在检查里(可跳过开场动画)。
|
|
62
|
+
|
|
63
|
+
## 测试脚本
|
|
64
|
+
写代码时一并写测试,放 \`tests/<主题>.test.js\`。文件体直接写语句,可用的变量:
|
|
65
|
+
- \`test(名称, async () => {...})\` 登记用例
|
|
66
|
+
- \`assert(条件, 说明)\`、\`assert.equal(实际, 期望, 说明)\`、\`assert.near(实际, 期望, 误差, 说明)\`
|
|
67
|
+
- \`game\`(= window.dshGame)、\`step(帧数, dt=1/60)\`、\`press(key, 帧数)\`
|
|
68
|
+
\`\`\`js
|
|
69
|
+
test('按住右键 3 秒能走出起点', () => {
|
|
70
|
+
game.input('ArrowRight', true); step(180); game.input('ArrowRight', false)
|
|
71
|
+
assert(game.state().player.x > 150, '应走出 150px')
|
|
72
|
+
})
|
|
73
|
+
\`\`\`
|
|
74
|
+
每个文件在一次全新加载上运行。测玩法规则(移动、碰撞、得分、胜负、存档),别测像素。
|
|
75
|
+
|
|
76
|
+
## 用户在面板里的改动
|
|
77
|
+
用户在右栏改的元素外观、字段、设定,定稿的参数,直接改的策划文字,都直接写进了项目文件——以文件为准,是用户的决定,别改回去。元素和参数的修改由用户在面板里「提交为新版本」(走同样的检查)才进试玩区;还没提交的,你下次 game_publish 时会一起带上。
|
|
78
|
+
game_read 的总览会列出用户改过、你还没看过的东西(看过一次就不再列);改元素文件或 game.json 之前先 game_read,再读文件现状,别凭记忆整份覆盖。用户有时会发一条以「【面板改动】」开头的消息,说明试玩时调了什么、感觉如何。
|
|
79
|
+
|
|
80
|
+
## 插件不够用时
|
|
81
|
+
插件给的是机制和口子,题材和玩法由你按用户的描述做;three.js 能做的,原则上游戏都能自己做。先看上面有没有现成的口子。确实被插件挡住(沙箱、加载、检查、面板这些你改不了的地方)时:
|
|
82
|
+
- 别悄悄降级凑合,跟用户直说「这是插件的限制」;
|
|
83
|
+
- 在 \`design/plugin-requests.md\` 记一条:想做什么、卡在哪(文件和行号)、试过什么。插件维护者会按这个改。
|
|
84
|
+
|
|
85
|
+
## 发版:game_publish
|
|
86
|
+
试玩区只放**通过检查的版本**。检查依次是:game.json 与元素文件校验 → 加载并跑 2 秒冒烟(报错、ready、画面不能全空)→ 跑 tests/。
|
|
87
|
+
- **改了能玩的东西,汇报或追问之前就先 game_publish,不用等用户开口。** 用户要看到效果才好做决定;用 ask_user_question 提问不会结束这一轮,不发版的话用户在右栏看到的还是上一版(或者什么都没有)。发版没有风险:自动上线关着就只是候选,没过检查就不出版本。
|
|
88
|
+
- game_publish 通过:生成新版本,自动上线开着就直接进试玩区;关着则成为候选,等用户在右栏确认。工具会告诉你是哪种,照实跟用户说。
|
|
89
|
+
- 不通过:工具返回问题清单,修好再调用;修好之前别请用户试玩。
|
|
90
|
+
- 一个功能写完、能玩了就可以发,不必等到这一轮最后;文件还没写完时别调。
|
|
91
|
+
- 纯设计问题(不需要玩)直接问,不用发版。
|
|
92
|
+
- 和 Claude Code 这类成员一起做时:成员手里没有发版工具。它说改完了,你马上 game_publish 再回复用户;给成员写交接说明时写「改完告诉我,我来发版」,别写「发版不归你管」。
|
|
93
|
+
- 用户也能在右栏点「检查并发版」,那样出的版本标「用户发布」,是用户认可过的,别随手改回去。
|
|
94
|
+
|
|
95
|
+
另外,你结束这一轮时插件也会自动检查改过的项目:不通过时检查结果会作为消息发回给你,这一轮继续,修好再结束(最多自动来回 2 次);已经用 game_publish 发过的同一版不会重复检查。
|
|
96
|
+
不用自己去「部署」或「运行」,也别为了过检查删测试。
|
|
97
|
+
`,
|
|
98
|
+
};
|
|
99
|
+
/** The mentoring skill. */
|
|
100
|
+
export const GAME_DESIGN_SKILL = {
|
|
101
|
+
name: 'game-design',
|
|
102
|
+
description: 'How to act as the user\'s game-design mentor: from an idea to a one-pager, pillars and a core loop, the '
|
|
103
|
+
+ 'design doc chapters, element design and reading playtests. Load when shaping or changing what the game is.',
|
|
104
|
+
content: `# game-design —— 当用户的策划搭档
|
|
105
|
+
|
|
106
|
+
用户多半没当过策划。你既是程序也是策划导师:给具体选项和理由,一次只问一两个问题,用户拍板。
|
|
107
|
+
|
|
108
|
+
## 从想法到能动手(轻量门)
|
|
109
|
+
1. 一句话 pitch:玩家做什么 + 为什么好玩。给 2–3 个写法让用户挑或改。
|
|
110
|
+
2. 元素类型:这个游戏里有哪几类「东西」(角色、敌人、道具、地块、技能……),后面每类都能单独编辑。
|
|
111
|
+
3. 美术风格:从示例里选(game_open 不带参数会列出),没合适的就 custom:描述。
|
|
112
|
+
4. 设计支柱(可后补):2–3 条「一定要做到的体验」,后面所有取舍拿它当尺子。
|
|
113
|
+
四样都有了才 game_open create。别替用户编,缺什么问什么。
|
|
114
|
+
|
|
115
|
+
## 策划文档(design/ 下,右栏「策划」按章节显示)
|
|
116
|
+
| 章节 | 文件 | 写什么 |
|
|
117
|
+
|---|---|---|
|
|
118
|
+
| 一页纸 | game.json | pitch、元素类型、风格、支柱(面板置顶显示;改支柱就改 game.json 的 pillars) |
|
|
119
|
+
| 支柱说明 | design/pillars.md | 每条支柱为什么重要、怎么检验(别复述一页纸) |
|
|
120
|
+
| 核心循环 | design/core-loop.md | 玩家每 10 秒 / 每 1 分钟 / 每局在重复什么,奖励是什么 |
|
|
121
|
+
| 机制与规则 | design/mechanics.md | 操作、规则、胜负、成长 |
|
|
122
|
+
| 元素与数值 | 自动 | 由 elements/*.json 生成,别手写 |
|
|
123
|
+
| 关卡与节奏 | design/levels.md | 关卡/波次列表,难度曲线 |
|
|
124
|
+
| 美术与音效 | design/art-audio.md | 配色、尺寸、动画、音效清单 |
|
|
125
|
+
| 试玩记录 | 自动 | 插件按版本和试玩自动记 |
|
|
126
|
+
- 章节写完、用户认可后,在章节里加一行 \`状态:定稿\`。改定稿章节前先和用户确认。
|
|
127
|
+
- 用户可能直接在文件里改策划;以文件为准,别覆盖用户的字。
|
|
128
|
+
- 先写短的。一个能玩的最小循环比完整文档重要:支柱 + 核心循环有了就先做出能玩的版本。
|
|
129
|
+
|
|
130
|
+
## 做元素
|
|
131
|
+
- 一个元素一组可调的数值;名字要有画面感。给用户 2–3 个变体(数值或外观不同),用户挑一个就落进 elements/。
|
|
132
|
+
- 改数值优先改 elements/ 里的文件,别硬编码进代码。
|
|
133
|
+
|
|
134
|
+
## 读试玩
|
|
135
|
+
- 用户玩完说「不好玩」时,追问具体:哪一刻无聊/太难/看不懂?对照支柱判断是不是要改。
|
|
136
|
+
- 每次只改一两处再让用户玩,改了什么写进对应章节。
|
|
137
|
+
`,
|
|
138
|
+
};
|
|
139
|
+
/** Both skills, registration order. */
|
|
140
|
+
export const GAME_SKILLS = [GAMEDEV_SKILL, GAME_DESIGN_SKILL];
|