@drawcall/design 0.5.1 → 0.5.3

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/dist/cli.js CHANGED
@@ -4,7 +4,7 @@ import { Command, Option } from "commander";
4
4
  import { clearConfig, getConfigPath, saveConfig } from "./config.js";
5
5
  import { getCliClient } from "./cli-client.js";
6
6
  import { readImageInput } from "./image.js";
7
- import { designSkill } from "./skill.generated.js";
7
+ import { cliDesignSkill } from "./skill.generated.js";
8
8
  import { parseFrameSize } from "./target.js";
9
9
  import { createClient, DEFAULT_BASE_URL } from "./v1/client.js";
10
10
  import { designIdSchema, marketAssetSchema } from "./v1/schemas.js";
@@ -20,7 +20,7 @@ program
20
20
  .command("skill")
21
21
  .description("Print the Drawcall Design skill")
22
22
  .action(() => {
23
- process.stdout.write(designSkill);
23
+ process.stdout.write(cliDesignSkill);
24
24
  });
25
25
  program
26
26
  .command("login")
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  export * as v1 from "./v1/index.js";
2
- export { designSkill } from "./skill.generated.js";
2
+ export { cliDesignSkill, mcpDesignSkill } from "./skill.generated.js";
3
3
  export { frameCreationCapabilities, type FrameCreationCapability, type FrameCreationCapabilityId, type FrameCreationInput, } from "./v1/capabilities.js";
4
4
  export { cameraPoseSchema, IMAGE_GENERATION_MODEL, IMAGE_GENERATION_PROVIDER, } from "./v1/schemas.js";
5
5
  export { parseFrameSize } from "./target.js";
6
- export { acknowledgesInspection, cameraCaptureCommandSchema, cameraCaptureResultSchema, cameraMessageTypes, gltsExportCancelCommandSchema, gltsExportCancelledResultSchema, gltsExportCommandSchema, gltsExportFrameMessageSchema, gltsExportMessageTypes, gltsExportParentMessageSchema, gltsExportResultSchema, gltsRuntimeExportFormatSchema, inspectionCommandSchema, inspectionFrameMessageSchema, inspectionMessageTypes, projectSyncMaps, projectSyncUrl, type GltsExportCancelCommand, type GltsExportCancelledResult, type GltsExportCommand, type GltsExportFrameMessage, type GltsExportParentMessage, type GltsExportResult, type GltsRuntimeExportFormat, type CameraCaptureCommand, type CameraCaptureFailure, type CameraCaptureResult, type InspectionAppliedMessage, type InspectionCommand, type InspectionFrameMessage, } from "./protocol.js";
6
+ export { projectFrameLayoutSchema, projectFrameRecordSchema, projectGltsFrameRecordSchema, projectImageFrameRecordSchema, projectMarketFileSchema, projectMarketFrameRecordSchema, projectPresenceClientMessageSchema, projectPresenceServerMessageSchema, projectStateSchema, type ProjectFrameLayout, type ProjectFrameRecord, type ProjectGltsFrameRecord, type ProjectImageFrameRecord, type ProjectMarketFile, type ProjectMarketFrameRecord, type ProjectPresenceClientMessage, type ProjectPresenceServerMessage, type ProjectState, } from "./project-state.js";
7
+ export { acknowledgesInspection, cameraCaptureCommandSchema, cameraCaptureResultSchema, cameraMessageTypes, gltsExportCancelCommandSchema, gltsExportCancelledResultSchema, gltsExportCommandSchema, gltsExportFrameMessageSchema, gltsExportMessageTypes, gltsExportParentMessageSchema, gltsExportResultSchema, gltsRuntimeExportFormatSchema, inspectionCommandSchema, inspectionFrameMessageSchema, inspectionMessageTypes, projectSyncUrl, sourceFileChangeSchema, sourceFileMessageTypes, sourceFileReloadResultSchema, sourceFilesChangedMessageSchema, type GltsExportCancelCommand, type GltsExportCancelledResult, type GltsExportCommand, type GltsExportFrameMessage, type GltsExportParentMessage, type GltsExportResult, type GltsRuntimeExportFormat, type CameraCaptureCommand, type CameraCaptureFailure, type CameraCaptureResult, type InspectionAppliedMessage, type InspectionCommand, type InspectionFrameMessage, type SourceFileChange, type SourceFileReloadResult, type SourceFilesChangedMessage, } from "./protocol.js";
7
8
  export type { BinaryFile, CameraPose, CreateFrame, CreateProjectFromBrief, CreateGltsFrame, CreateImageFrame, CreateMarketFrame, GenerateImageFrame, DesignFile, FileList, FileMutation, FrameExport, Frame, GltsFrame, GltsFrameExport, ImageFrame, ImageFrameExport, ImageGenerationOperation, ImageGenerationProvenance, ImageGenerationResult, MarketFrame, MarketFrameExport, Project, ProjectDerivationStatus, Screenshot, TextFile, User, } from "./v1/schemas.js";
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export * as v1 from "./v1/index.js";
2
- export { designSkill } from "./skill.generated.js";
2
+ export { cliDesignSkill, mcpDesignSkill } from "./skill.generated.js";
3
3
  export { frameCreationCapabilities, } from "./v1/capabilities.js";
4
4
  export { cameraPoseSchema, IMAGE_GENERATION_MODEL, IMAGE_GENERATION_PROVIDER, } from "./v1/schemas.js";
5
5
  export { parseFrameSize } from "./target.js";
6
- export { acknowledgesInspection, cameraCaptureCommandSchema, cameraCaptureResultSchema, cameraMessageTypes, gltsExportCancelCommandSchema, gltsExportCancelledResultSchema, gltsExportCommandSchema, gltsExportFrameMessageSchema, gltsExportMessageTypes, gltsExportParentMessageSchema, gltsExportResultSchema, gltsRuntimeExportFormatSchema, inspectionCommandSchema, inspectionFrameMessageSchema, inspectionMessageTypes, projectSyncMaps, projectSyncUrl, } from "./protocol.js";
6
+ export { projectFrameLayoutSchema, projectFrameRecordSchema, projectGltsFrameRecordSchema, projectImageFrameRecordSchema, projectMarketFileSchema, projectMarketFrameRecordSchema, projectPresenceClientMessageSchema, projectPresenceServerMessageSchema, projectStateSchema, } from "./project-state.js";
7
+ export { acknowledgesInspection, cameraCaptureCommandSchema, cameraCaptureResultSchema, cameraMessageTypes, gltsExportCancelCommandSchema, gltsExportCancelledResultSchema, gltsExportCommandSchema, gltsExportFrameMessageSchema, gltsExportMessageTypes, gltsExportParentMessageSchema, gltsExportResultSchema, gltsRuntimeExportFormatSchema, inspectionCommandSchema, inspectionFrameMessageSchema, inspectionMessageTypes, projectSyncUrl, sourceFileChangeSchema, sourceFileMessageTypes, sourceFileReloadResultSchema, sourceFilesChangedMessageSchema, } from "./protocol.js";
@@ -0,0 +1,369 @@
1
+ import { z } from "zod";
2
+ export declare const projectFrameLayoutSchema: z.ZodObject<{
3
+ x: z.ZodNumber;
4
+ y: z.ZodNumber;
5
+ width: z.ZodNumber;
6
+ height: z.ZodNumber;
7
+ }, z.core.$strict>;
8
+ export declare const projectGltsFrameRecordSchema: z.ZodObject<{
9
+ x: z.ZodNumber;
10
+ y: z.ZodNumber;
11
+ width: z.ZodNumber;
12
+ height: z.ZodNumber;
13
+ id: z.ZodString;
14
+ projectId: z.ZodString;
15
+ name: z.ZodString;
16
+ viewUrl: z.ZodString;
17
+ contentRevision: z.ZodNumber;
18
+ createdAt: z.ZodString;
19
+ updatedAt: z.ZodString;
20
+ type: z.ZodLiteral<"glts">;
21
+ camera: z.ZodOptional<z.ZodObject<{
22
+ position: z.ZodObject<{
23
+ x: z.ZodNumber;
24
+ y: z.ZodNumber;
25
+ z: z.ZodNumber;
26
+ }, z.core.$strict>;
27
+ quaternion: z.ZodObject<{
28
+ x: z.ZodNumber;
29
+ y: z.ZodNumber;
30
+ z: z.ZodNumber;
31
+ w: z.ZodNumber;
32
+ }, z.core.$strict>;
33
+ }, z.core.$strict>>;
34
+ }, z.core.$strict>;
35
+ export declare const projectImageFrameRecordSchema: z.ZodObject<{
36
+ x: z.ZodNumber;
37
+ y: z.ZodNumber;
38
+ width: z.ZodNumber;
39
+ height: z.ZodNumber;
40
+ id: z.ZodString;
41
+ projectId: z.ZodString;
42
+ name: z.ZodString;
43
+ viewUrl: z.ZodString;
44
+ contentRevision: z.ZodNumber;
45
+ createdAt: z.ZodString;
46
+ updatedAt: z.ZodString;
47
+ type: z.ZodLiteral<"image">;
48
+ image: z.ZodObject<{
49
+ path: z.ZodString;
50
+ mediaType: z.ZodEnum<{
51
+ "image/png": "image/png";
52
+ "image/jpeg": "image/jpeg";
53
+ "image/webp": "image/webp";
54
+ }>;
55
+ }, z.core.$strict>;
56
+ provenance: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
57
+ kind: z.ZodLiteral<"generated">;
58
+ operation: z.ZodEnum<{
59
+ generate: "generate";
60
+ edit: "edit";
61
+ }>;
62
+ prompt: z.ZodString;
63
+ references: z.ZodArray<z.ZodObject<{
64
+ frameId: z.ZodString;
65
+ frameUpdatedAt: z.ZodString;
66
+ }, z.core.$strip>>;
67
+ result: z.ZodEnum<{
68
+ replace: "replace";
69
+ new: "new";
70
+ }>;
71
+ provider: z.ZodLiteral<"fal-ai">;
72
+ model: z.ZodLiteral<"openai/gpt-image-2">;
73
+ }, z.core.$strip>, z.ZodObject<{
74
+ kind: z.ZodLiteral<"generated">;
75
+ operation: z.ZodEnum<{
76
+ generate: "generate";
77
+ edit: "edit";
78
+ }>;
79
+ prompt: z.ZodString;
80
+ references: z.ZodArray<z.ZodObject<{
81
+ frameId: z.ZodString;
82
+ frameUpdatedAt: z.ZodString;
83
+ }, z.core.$strip>>;
84
+ result: z.ZodEnum<{
85
+ replace: "replace";
86
+ new: "new";
87
+ }>;
88
+ provider: z.ZodLiteral<"cloudflare-workers-ai">;
89
+ model: z.ZodLiteral<"@cf/black-forest-labs/flux-2-klein-4b">;
90
+ }, z.core.$strip>], "provider">>;
91
+ }, z.core.$strict>;
92
+ export declare const projectMarketFileSchema: z.ZodObject<{
93
+ path: z.ZodString;
94
+ url: z.ZodString;
95
+ mediaType: z.ZodOptional<z.ZodString>;
96
+ }, z.core.$strict>;
97
+ export declare const projectMarketFrameRecordSchema: z.ZodObject<{
98
+ x: z.ZodNumber;
99
+ y: z.ZodNumber;
100
+ width: z.ZodNumber;
101
+ height: z.ZodNumber;
102
+ id: z.ZodString;
103
+ projectId: z.ZodString;
104
+ name: z.ZodString;
105
+ viewUrl: z.ZodString;
106
+ contentRevision: z.ZodNumber;
107
+ createdAt: z.ZodString;
108
+ updatedAt: z.ZodString;
109
+ type: z.ZodLiteral<"market">;
110
+ market: z.ZodObject<{
111
+ name: z.ZodString;
112
+ version: z.ZodString;
113
+ previewUrl: z.ZodString;
114
+ files: z.ZodArray<z.ZodObject<{
115
+ path: z.ZodString;
116
+ url: z.ZodString;
117
+ mediaType: z.ZodOptional<z.ZodString>;
118
+ }, z.core.$strict>>;
119
+ }, z.core.$strict>;
120
+ }, z.core.$strict>;
121
+ export declare const projectFrameRecordSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
122
+ x: z.ZodNumber;
123
+ y: z.ZodNumber;
124
+ width: z.ZodNumber;
125
+ height: z.ZodNumber;
126
+ id: z.ZodString;
127
+ projectId: z.ZodString;
128
+ name: z.ZodString;
129
+ viewUrl: z.ZodString;
130
+ contentRevision: z.ZodNumber;
131
+ createdAt: z.ZodString;
132
+ updatedAt: z.ZodString;
133
+ type: z.ZodLiteral<"glts">;
134
+ camera: z.ZodOptional<z.ZodObject<{
135
+ position: z.ZodObject<{
136
+ x: z.ZodNumber;
137
+ y: z.ZodNumber;
138
+ z: z.ZodNumber;
139
+ }, z.core.$strict>;
140
+ quaternion: z.ZodObject<{
141
+ x: z.ZodNumber;
142
+ y: z.ZodNumber;
143
+ z: z.ZodNumber;
144
+ w: z.ZodNumber;
145
+ }, z.core.$strict>;
146
+ }, z.core.$strict>>;
147
+ }, z.core.$strict>, z.ZodObject<{
148
+ x: z.ZodNumber;
149
+ y: z.ZodNumber;
150
+ width: z.ZodNumber;
151
+ height: z.ZodNumber;
152
+ id: z.ZodString;
153
+ projectId: z.ZodString;
154
+ name: z.ZodString;
155
+ viewUrl: z.ZodString;
156
+ contentRevision: z.ZodNumber;
157
+ createdAt: z.ZodString;
158
+ updatedAt: z.ZodString;
159
+ type: z.ZodLiteral<"image">;
160
+ image: z.ZodObject<{
161
+ path: z.ZodString;
162
+ mediaType: z.ZodEnum<{
163
+ "image/png": "image/png";
164
+ "image/jpeg": "image/jpeg";
165
+ "image/webp": "image/webp";
166
+ }>;
167
+ }, z.core.$strict>;
168
+ provenance: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
169
+ kind: z.ZodLiteral<"generated">;
170
+ operation: z.ZodEnum<{
171
+ generate: "generate";
172
+ edit: "edit";
173
+ }>;
174
+ prompt: z.ZodString;
175
+ references: z.ZodArray<z.ZodObject<{
176
+ frameId: z.ZodString;
177
+ frameUpdatedAt: z.ZodString;
178
+ }, z.core.$strip>>;
179
+ result: z.ZodEnum<{
180
+ replace: "replace";
181
+ new: "new";
182
+ }>;
183
+ provider: z.ZodLiteral<"fal-ai">;
184
+ model: z.ZodLiteral<"openai/gpt-image-2">;
185
+ }, z.core.$strip>, z.ZodObject<{
186
+ kind: z.ZodLiteral<"generated">;
187
+ operation: z.ZodEnum<{
188
+ generate: "generate";
189
+ edit: "edit";
190
+ }>;
191
+ prompt: z.ZodString;
192
+ references: z.ZodArray<z.ZodObject<{
193
+ frameId: z.ZodString;
194
+ frameUpdatedAt: z.ZodString;
195
+ }, z.core.$strip>>;
196
+ result: z.ZodEnum<{
197
+ replace: "replace";
198
+ new: "new";
199
+ }>;
200
+ provider: z.ZodLiteral<"cloudflare-workers-ai">;
201
+ model: z.ZodLiteral<"@cf/black-forest-labs/flux-2-klein-4b">;
202
+ }, z.core.$strip>], "provider">>;
203
+ }, z.core.$strict>, z.ZodObject<{
204
+ x: z.ZodNumber;
205
+ y: z.ZodNumber;
206
+ width: z.ZodNumber;
207
+ height: z.ZodNumber;
208
+ id: z.ZodString;
209
+ projectId: z.ZodString;
210
+ name: z.ZodString;
211
+ viewUrl: z.ZodString;
212
+ contentRevision: z.ZodNumber;
213
+ createdAt: z.ZodString;
214
+ updatedAt: z.ZodString;
215
+ type: z.ZodLiteral<"market">;
216
+ market: z.ZodObject<{
217
+ name: z.ZodString;
218
+ version: z.ZodString;
219
+ previewUrl: z.ZodString;
220
+ files: z.ZodArray<z.ZodObject<{
221
+ path: z.ZodString;
222
+ url: z.ZodString;
223
+ mediaType: z.ZodOptional<z.ZodString>;
224
+ }, z.core.$strict>>;
225
+ }, z.core.$strict>;
226
+ }, z.core.$strict>], "type">;
227
+ export declare const projectStateSchema: z.ZodObject<{
228
+ schemaVersion: z.ZodLiteral<1>;
229
+ projectId: z.ZodString;
230
+ revision: z.ZodNumber;
231
+ frames: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
232
+ x: z.ZodNumber;
233
+ y: z.ZodNumber;
234
+ width: z.ZodNumber;
235
+ height: z.ZodNumber;
236
+ id: z.ZodString;
237
+ projectId: z.ZodString;
238
+ name: z.ZodString;
239
+ viewUrl: z.ZodString;
240
+ contentRevision: z.ZodNumber;
241
+ createdAt: z.ZodString;
242
+ updatedAt: z.ZodString;
243
+ type: z.ZodLiteral<"glts">;
244
+ camera: z.ZodOptional<z.ZodObject<{
245
+ position: z.ZodObject<{
246
+ x: z.ZodNumber;
247
+ y: z.ZodNumber;
248
+ z: z.ZodNumber;
249
+ }, z.core.$strict>;
250
+ quaternion: z.ZodObject<{
251
+ x: z.ZodNumber;
252
+ y: z.ZodNumber;
253
+ z: z.ZodNumber;
254
+ w: z.ZodNumber;
255
+ }, z.core.$strict>;
256
+ }, z.core.$strict>>;
257
+ }, z.core.$strict>, z.ZodObject<{
258
+ x: z.ZodNumber;
259
+ y: z.ZodNumber;
260
+ width: z.ZodNumber;
261
+ height: z.ZodNumber;
262
+ id: z.ZodString;
263
+ projectId: z.ZodString;
264
+ name: z.ZodString;
265
+ viewUrl: z.ZodString;
266
+ contentRevision: z.ZodNumber;
267
+ createdAt: z.ZodString;
268
+ updatedAt: z.ZodString;
269
+ type: z.ZodLiteral<"image">;
270
+ image: z.ZodObject<{
271
+ path: z.ZodString;
272
+ mediaType: z.ZodEnum<{
273
+ "image/png": "image/png";
274
+ "image/jpeg": "image/jpeg";
275
+ "image/webp": "image/webp";
276
+ }>;
277
+ }, z.core.$strict>;
278
+ provenance: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
279
+ kind: z.ZodLiteral<"generated">;
280
+ operation: z.ZodEnum<{
281
+ generate: "generate";
282
+ edit: "edit";
283
+ }>;
284
+ prompt: z.ZodString;
285
+ references: z.ZodArray<z.ZodObject<{
286
+ frameId: z.ZodString;
287
+ frameUpdatedAt: z.ZodString;
288
+ }, z.core.$strip>>;
289
+ result: z.ZodEnum<{
290
+ replace: "replace";
291
+ new: "new";
292
+ }>;
293
+ provider: z.ZodLiteral<"fal-ai">;
294
+ model: z.ZodLiteral<"openai/gpt-image-2">;
295
+ }, z.core.$strip>, z.ZodObject<{
296
+ kind: z.ZodLiteral<"generated">;
297
+ operation: z.ZodEnum<{
298
+ generate: "generate";
299
+ edit: "edit";
300
+ }>;
301
+ prompt: z.ZodString;
302
+ references: z.ZodArray<z.ZodObject<{
303
+ frameId: z.ZodString;
304
+ frameUpdatedAt: z.ZodString;
305
+ }, z.core.$strip>>;
306
+ result: z.ZodEnum<{
307
+ replace: "replace";
308
+ new: "new";
309
+ }>;
310
+ provider: z.ZodLiteral<"cloudflare-workers-ai">;
311
+ model: z.ZodLiteral<"@cf/black-forest-labs/flux-2-klein-4b">;
312
+ }, z.core.$strip>], "provider">>;
313
+ }, z.core.$strict>, z.ZodObject<{
314
+ x: z.ZodNumber;
315
+ y: z.ZodNumber;
316
+ width: z.ZodNumber;
317
+ height: z.ZodNumber;
318
+ id: z.ZodString;
319
+ projectId: z.ZodString;
320
+ name: z.ZodString;
321
+ viewUrl: z.ZodString;
322
+ contentRevision: z.ZodNumber;
323
+ createdAt: z.ZodString;
324
+ updatedAt: z.ZodString;
325
+ type: z.ZodLiteral<"market">;
326
+ market: z.ZodObject<{
327
+ name: z.ZodString;
328
+ version: z.ZodString;
329
+ previewUrl: z.ZodString;
330
+ files: z.ZodArray<z.ZodObject<{
331
+ path: z.ZodString;
332
+ url: z.ZodString;
333
+ mediaType: z.ZodOptional<z.ZodString>;
334
+ }, z.core.$strict>>;
335
+ }, z.core.$strict>;
336
+ }, z.core.$strict>], "type">>;
337
+ fileRevisions: z.ZodRecord<z.ZodString, z.ZodNumber>;
338
+ }, z.core.$strict>;
339
+ export declare const projectPresenceClientMessageSchema: z.ZodObject<{
340
+ type: z.ZodLiteral<"presence:update">;
341
+ cursor: z.ZodNullable<z.ZodObject<{
342
+ x: z.ZodNumber;
343
+ y: z.ZodNumber;
344
+ }, z.core.$strict>>;
345
+ }, z.core.$strict>;
346
+ export declare const projectPresenceServerMessageSchema: z.ZodObject<{
347
+ type: z.ZodLiteral<"presence">;
348
+ collaborators: z.ZodArray<z.ZodObject<{
349
+ connectionId: z.ZodString;
350
+ user: z.ZodObject<{
351
+ id: z.ZodString;
352
+ name: z.ZodString;
353
+ color: z.ZodString;
354
+ }, z.core.$strict>;
355
+ cursor: z.ZodOptional<z.ZodObject<{
356
+ x: z.ZodNumber;
357
+ y: z.ZodNumber;
358
+ }, z.core.$strict>>;
359
+ }, z.core.$strict>>;
360
+ }, z.core.$strict>;
361
+ export type ProjectPresenceClientMessage = z.infer<typeof projectPresenceClientMessageSchema>;
362
+ export type ProjectPresenceServerMessage = z.infer<typeof projectPresenceServerMessageSchema>;
363
+ export type ProjectFrameLayout = z.infer<typeof projectFrameLayoutSchema>;
364
+ export type ProjectGltsFrameRecord = z.infer<typeof projectGltsFrameRecordSchema>;
365
+ export type ProjectImageFrameRecord = z.infer<typeof projectImageFrameRecordSchema>;
366
+ export type ProjectMarketFile = z.infer<typeof projectMarketFileSchema>;
367
+ export type ProjectMarketFrameRecord = z.infer<typeof projectMarketFrameRecordSchema>;
368
+ export type ProjectFrameRecord = z.infer<typeof projectFrameRecordSchema>;
369
+ export type ProjectState = z.infer<typeof projectStateSchema>;
@@ -0,0 +1,112 @@
1
+ import { z } from "zod";
2
+ import { cameraPoseSchema, designIdSchema, frameNameSchema, framePositionSchema, frameSizeSchema, httpUrlSchema, imageGenerationProvenanceSchema, marketAssetNameSchema, marketAssetVersionSchema, projectPathSchema, } from "./v1/schemas.js";
3
+ export const projectFrameLayoutSchema = z
4
+ .object({
5
+ x: framePositionSchema,
6
+ y: framePositionSchema,
7
+ width: frameSizeSchema,
8
+ height: frameSizeSchema,
9
+ })
10
+ .strict();
11
+ const relativeAssetPathSchema = z
12
+ .string()
13
+ .max(1_024)
14
+ .refine((path) => !path.startsWith("/") &&
15
+ !path.endsWith("/") &&
16
+ !path.includes("\\") &&
17
+ !path.includes("\0") &&
18
+ path
19
+ .split("/")
20
+ .every((segment) => segment.length > 0 && segment !== "." && segment !== ".."), "Asset paths must be relative and cannot contain empty, . or .. segments");
21
+ const projectFrameRecordBaseSchema = z
22
+ .object({
23
+ id: designIdSchema,
24
+ projectId: designIdSchema,
25
+ name: frameNameSchema,
26
+ viewUrl: httpUrlSchema,
27
+ contentRevision: z.number().int().nonnegative(),
28
+ createdAt: z.string().datetime(),
29
+ updatedAt: z.string().datetime(),
30
+ ...projectFrameLayoutSchema.shape,
31
+ })
32
+ .strict();
33
+ export const projectGltsFrameRecordSchema = projectFrameRecordBaseSchema
34
+ .extend({
35
+ type: z.literal("glts"),
36
+ camera: cameraPoseSchema.optional(),
37
+ })
38
+ .strict();
39
+ export const projectImageFrameRecordSchema = projectFrameRecordBaseSchema
40
+ .extend({
41
+ type: z.literal("image"),
42
+ image: z
43
+ .object({
44
+ path: relativeAssetPathSchema,
45
+ mediaType: z.enum(["image/jpeg", "image/png", "image/webp"]),
46
+ })
47
+ .strict(),
48
+ provenance: imageGenerationProvenanceSchema.optional(),
49
+ })
50
+ .strict();
51
+ export const projectMarketFileSchema = z
52
+ .object({
53
+ path: relativeAssetPathSchema,
54
+ url: httpUrlSchema,
55
+ mediaType: z.string().min(1).optional(),
56
+ })
57
+ .strict();
58
+ export const projectMarketFrameRecordSchema = projectFrameRecordBaseSchema
59
+ .extend({
60
+ type: z.literal("market"),
61
+ market: z
62
+ .object({
63
+ name: marketAssetNameSchema,
64
+ version: marketAssetVersionSchema,
65
+ previewUrl: httpUrlSchema,
66
+ files: z.array(projectMarketFileSchema),
67
+ })
68
+ .strict(),
69
+ })
70
+ .strict();
71
+ export const projectFrameRecordSchema = z.discriminatedUnion("type", [
72
+ projectGltsFrameRecordSchema,
73
+ projectImageFrameRecordSchema,
74
+ projectMarketFrameRecordSchema,
75
+ ]);
76
+ export const projectStateSchema = z
77
+ .object({
78
+ schemaVersion: z.literal(1),
79
+ projectId: designIdSchema,
80
+ revision: z.number().int().nonnegative(),
81
+ frames: z.array(projectFrameRecordSchema),
82
+ fileRevisions: z.record(projectPathSchema, z.number().int().nonnegative()),
83
+ })
84
+ .strict();
85
+ const cursorSchema = z
86
+ .object({ x: z.number().finite(), y: z.number().finite() })
87
+ .strict();
88
+ export const projectPresenceClientMessageSchema = z
89
+ .object({
90
+ type: z.literal("presence:update"),
91
+ cursor: cursorSchema.nullable(),
92
+ })
93
+ .strict();
94
+ const projectCollaboratorSchema = z
95
+ .object({
96
+ connectionId: z.string().min(1),
97
+ user: z
98
+ .object({
99
+ id: z.string().min(1),
100
+ name: z.string(),
101
+ color: z.string().min(1),
102
+ })
103
+ .strict(),
104
+ cursor: cursorSchema.optional(),
105
+ })
106
+ .strict();
107
+ export const projectPresenceServerMessageSchema = z
108
+ .object({
109
+ type: z.literal("presence"),
110
+ collaborators: z.array(projectCollaboratorSchema),
111
+ })
112
+ .strict();
@@ -1,12 +1,8 @@
1
1
  import { z } from "zod";
2
- export declare const projectSyncMaps: {
3
- readonly frameContentRevisions: "frame-content-revisions";
4
- readonly filesystemRevision: "filesystem-revision";
5
- readonly frameRecords: "frame-records";
6
- };
7
2
  export declare const inspectionMessageTypes: {
8
3
  readonly applied: "drawcall:inspection:applied";
9
4
  readonly exit: "drawcall:inspection:exit";
5
+ readonly failed: "drawcall:inspection:failed";
10
6
  readonly loading: "drawcall:inspection:loading";
11
7
  readonly ready: "drawcall:inspection:ready";
12
8
  readonly set: "drawcall:inspection:set";
@@ -100,6 +96,33 @@ export declare const cameraMessageTypes: {
100
96
  readonly captured: "drawcall:camera:captured";
101
97
  readonly unavailable: "drawcall:camera:unavailable";
102
98
  };
99
+ export declare const sourceFileMessageTypes: {
100
+ readonly changed: "drawcall:source-files:changed";
101
+ readonly reloadResult: "drawcall:source-file:reload-result";
102
+ };
103
+ export declare const sourceFileChangeSchema: z.ZodObject<{
104
+ path: z.ZodString;
105
+ revision: z.ZodNumber;
106
+ }, z.core.$strict>;
107
+ export declare const sourceFilesChangedMessageSchema: z.ZodObject<{
108
+ type: z.ZodLiteral<"drawcall:source-files:changed">;
109
+ changes: z.ZodArray<z.ZodObject<{
110
+ path: z.ZodString;
111
+ revision: z.ZodNumber;
112
+ }, z.core.$strict>>;
113
+ }, z.core.$strict>;
114
+ export declare const sourceFileReloadResultSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
115
+ type: z.ZodLiteral<"drawcall:source-file:reload-result">;
116
+ path: z.ZodString;
117
+ revision: z.ZodNumber;
118
+ ok: z.ZodLiteral<true>;
119
+ }, z.core.$strict>, z.ZodObject<{
120
+ type: z.ZodLiteral<"drawcall:source-file:reload-result">;
121
+ path: z.ZodString;
122
+ revision: z.ZodNumber;
123
+ ok: z.ZodLiteral<false>;
124
+ error: z.ZodString;
125
+ }, z.core.$strict>], "ok">;
103
126
  export declare const cameraCaptureCommandSchema: z.ZodObject<{
104
127
  type: z.ZodLiteral<"drawcall:camera:capture">;
105
128
  requestId: z.ZodString;
@@ -135,6 +158,8 @@ export declare const inspectionCommandSchema: z.ZodObject<{
135
158
  enabled: z.ZodBoolean;
136
159
  }, z.core.$strict>;
137
160
  export declare const inspectionFrameMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
161
+ type: z.ZodLiteral<"drawcall:inspection:failed">;
162
+ }, z.core.$strict>, z.ZodObject<{
138
163
  type: z.ZodLiteral<"drawcall:inspection:loading">;
139
164
  }, z.core.$strict>, z.ZodObject<{
140
165
  type: z.ZodLiteral<"drawcall:inspection:ready">;
@@ -148,6 +173,9 @@ export declare const inspectionFrameMessageSchema: z.ZodDiscriminatedUnion<[z.Zo
148
173
  export type InspectionCommand = z.infer<typeof inspectionCommandSchema>;
149
174
  export type CameraCaptureCommand = z.infer<typeof cameraCaptureCommandSchema>;
150
175
  export type CameraCaptureResult = z.infer<typeof cameraCaptureResultSchema>;
176
+ export type SourceFileChange = z.infer<typeof sourceFileChangeSchema>;
177
+ export type SourceFilesChangedMessage = z.infer<typeof sourceFilesChangedMessageSchema>;
178
+ export type SourceFileReloadResult = z.infer<typeof sourceFileReloadResultSchema>;
151
179
  export type CameraCaptureFailure = Extract<CameraCaptureResult, {
152
180
  type: typeof cameraMessageTypes.unavailable;
153
181
  }>;
package/dist/protocol.js CHANGED
@@ -1,13 +1,9 @@
1
1
  import { z } from "zod";
2
- import { cameraPoseSchema } from "./v1/schemas.js";
3
- export const projectSyncMaps = {
4
- frameContentRevisions: "frame-content-revisions",
5
- filesystemRevision: "filesystem-revision",
6
- frameRecords: "frame-records",
7
- };
2
+ import { cameraPoseSchema, projectPathSchema } from "./v1/schemas.js";
8
3
  export const inspectionMessageTypes = {
9
4
  applied: "drawcall:inspection:applied",
10
5
  exit: "drawcall:inspection:exit",
6
+ failed: "drawcall:inspection:failed",
11
7
  loading: "drawcall:inspection:loading",
12
8
  ready: "drawcall:inspection:ready",
13
9
  set: "drawcall:inspection:set",
@@ -79,6 +75,33 @@ export const cameraMessageTypes = {
79
75
  captured: "drawcall:camera:captured",
80
76
  unavailable: "drawcall:camera:unavailable",
81
77
  };
78
+ export const sourceFileMessageTypes = {
79
+ changed: "drawcall:source-files:changed",
80
+ reloadResult: "drawcall:source-file:reload-result",
81
+ };
82
+ export const sourceFileChangeSchema = z
83
+ .object({
84
+ path: projectPathSchema,
85
+ revision: z.number().int().nonnegative(),
86
+ })
87
+ .strict();
88
+ export const sourceFilesChangedMessageSchema = z
89
+ .object({
90
+ type: z.literal(sourceFileMessageTypes.changed),
91
+ changes: z.array(sourceFileChangeSchema).min(1),
92
+ })
93
+ .strict();
94
+ const sourceFileReloadResultBaseSchema = z.object({
95
+ type: z.literal(sourceFileMessageTypes.reloadResult),
96
+ path: projectPathSchema,
97
+ revision: z.number().int().nonnegative(),
98
+ });
99
+ export const sourceFileReloadResultSchema = z.discriminatedUnion("ok", [
100
+ sourceFileReloadResultBaseSchema.extend({ ok: z.literal(true) }).strict(),
101
+ sourceFileReloadResultBaseSchema
102
+ .extend({ ok: z.literal(false), error: z.string().min(1) })
103
+ .strict(),
104
+ ]);
82
105
  export const cameraCaptureCommandSchema = z
83
106
  .object({
84
107
  type: z.literal(cameraMessageTypes.capture),
@@ -113,6 +136,7 @@ export const inspectionCommandSchema = z
113
136
  })
114
137
  .strict();
115
138
  export const inspectionFrameMessageSchema = z.discriminatedUnion("type", [
139
+ z.object({ type: z.literal(inspectionMessageTypes.failed) }).strict(),
116
140
  z.object({ type: z.literal(inspectionMessageTypes.loading) }).strict(),
117
141
  z.object({ type: z.literal(inspectionMessageTypes.ready) }).strict(),
118
142
  z
@@ -1 +1,2 @@
1
- export declare const designSkill = "---\nname: drawcall-design\ndescription: Create, modify, inspect, and screenshot 3D assets and reference frames in Drawcall Design. Use for Drawcall Design projects, frames, the project filesystem, GLTS assets, or Drawcall Market frames. Do not use for full games or applications.\n---\n\n# Drawcall Design\n\nUse the Drawcall Design MCP tools when available. Otherwise use `npx @drawcall/design`. Design is a remote, current-state canvas: inspect the project and its frames before changing them. Use immutable IDs for every project and frame target; names are only labels.\n\n## Project filesystem\n\nA project is a hosted filesystem at `https://<project-id>.design.drawcallcontent.com/`. Each frame owns one top-level folder, `/<frame-id>/`. The CLI selects the project with `-p <project-id>`; its file paths are exactly the absolute paths inside that project, for example `/f7k3m9q2x8vd/index.glts`.\n\nCreate frames with an explicit type. GLTS frames require `--size`; image and Market frames derive their canvas size. A Market frame requires an exact public asset reference, `name@version`.\n\nRead a file before editing it. Use a narrow edit for one known change and write a complete file when replacing it. Only GLTS frame files may be created or deleted. Image and Market frame files are read-only.\n\n## GLTS assets\n\nA GLTS frame contains only `.glts` files. `index.glts` is its optional root asset; without it the frame renders empty. Every `.glts` file is a trusted TypeScript ESM module that default-exports a no-argument class derived from `THREE.Object3D`. Avoid top-level side effects because reload evaluates the module again. Implement `dispose()` when the asset exclusively owns disposable resources.\n\nAuthor GLTS scenes top-down: create the root entry scene first, reference the child `.glts` assets it will compose, then implement those children progressively. A missing `.glts` import renders as a glowing marker labeled with its filename until the real file is written, so the completed parts of the scene remain visible. Treat the marker and its console warning as a temporary missing-dependency diagnostic, not as authored content.\n\n```ts\nimport * as THREE from \"three\";\nimport Wheel from \"./parts/wheel.glts\";\n\nexport default class Racecar extends THREE.Group {\n constructor() {\n super();\n this.add(new Wheel());\n }\n}\n```\n\nUse relative `.glts` imports within a frame. Use a project-absolute path to import a GLTS asset from another frame:\n\n```ts\nimport Chassis from \"/other-frame-id/index.glts\";\n```\n\nFor a non-GLTS file from an image or Market frame, preserve the project filesystem URL through `import.meta.url`:\n\n```ts\nconst modelUrl = new URL(\"/market-frame-id/models/car.glb\", import.meta.url);\n```\n\nGLTS supports static `.glts`, `three`, Three addons, and bare npm imports. It does not support local helper `.ts` modules, dynamic imports, cyclic GLTS graphs, or cross-asset inheritance. Keep the asset self-contained and compose with nested GLTS assets.\n\nThe viewer uses the first camera found by depth-first traversal. If none exists, it autofits the asset. Put an authored camera in the scene only when its framing is intentional. Double-clicking a frame enters orbit from that resolved view; deselecting restores it.\n\nAfter every meaningful visual change, take and inspect a screenshot. Iterate until the asset, camera, composition, and requested frame size are right.\n";
1
+ export declare const mcpDesignSkill = "---\nname: drawcall-design\ndescription: Create, modify, inspect, compose, and reuse 3D GLTS assets and optional image or Market references in Drawcall Design. Use whenever the user names Drawcall Design or one of its projects, canvases, frames, filesystems, or GLTS assets. Do not use for full games, applications, or unrelated image generation.\n---\n\n# Drawcall Design\n\n## MCP transport\n\nMCP tools are the only Drawcall transport in this environment. Do not invoke a CLI or shell, make direct HTTP requests, or search the web for another transport. A failed MCP call does not make MCP unavailable.\n\nUse `generate_image` only when the user asks for a 2D image or reference. A 3D object, scene, or reusable asset is GLTS work, even when the user calls its canvas container a frame.\n\nTool arguments are JSON objects. File tools identify their target with `project` and a project-absolute `path`; they do not accept a separate `frame` argument. Call `list_files` and pass one of its returned paths unchanged.\n\n```json\n[\n {\n \"tool\": \"list_projects\",\n \"arguments\": {}\n },\n {\n \"tool\": \"list_frames\",\n \"arguments\": {\n \"project\": \"r6z2n9k4x8m1qc\"\n }\n },\n {\n \"tool\": \"list_files\",\n \"arguments\": {\n \"project\": \"r6z2n9k4x8m1qc\"\n }\n },\n {\n \"tool\": \"read_file\",\n \"arguments\": {\n \"project\": \"r6z2n9k4x8m1qc\",\n \"path\": \"/a4z8m2q7v9kcde/index.glts\"\n }\n },\n {\n \"tool\": \"edit_file\",\n \"arguments\": {\n \"project\": \"r6z2n9k4x8m1qc\",\n \"path\": \"/a4z8m2q7v9kcde/index.glts\",\n \"oldText\": \"color: 0xffffff\",\n \"newText\": \"color: 0x000000\"\n }\n }\n]\n```\n\nDesign is a remote, current-state canvas. Inspect the project and its frames before changing them. Use immutable IDs for every project and frame target; names are only labels.\n\n## Project filesystem\n\nA project is a hosted filesystem at `https://<project-id>.design.drawcallcontent.com/`. Each frame owns one top-level directory, `/<frame-id>`. Files use project-absolute paths that include that directory, for example `/a4z8m2q7v9kcde/index.glts`.\n\nCreate frames with an explicit type. Choose the type from the requested artifact, not from the word \"frame\": use GLTS for a 3D object or scene, especially one another frame will reuse. Use image only for a supplied 2D image URL and Market only for an exact public asset reference, `name@version`. GLTS frames require a viewport size; image and Market frames derive their canvas size.\n\nRead a file before editing it. Use a narrow edit for one known change and write a complete file when replacing it. Only GLTS frame files may be created or deleted. Image and Market frame files are read-only.\n\n## Failures\n\nAn error means the requested operation did not happen. Follow its next action without switching transport. Correct invalid arguments from the documented shape. Refresh projects, frames, or files after a not-found or conflict error, then reuse the exact returned IDs and paths. Retry an upstream or internal failure once; if it repeats, report the failed operation and error. Never repeat an unchanged failed operation.\n\n## GLTS assets\n\nA GLTS frame contains only `.glts` files. `index.glts` is its optional root asset; without it the frame renders empty. Every `.glts` file is a trusted TypeScript ESM module that default-exports a no-argument class derived from `THREE.Object3D`. Avoid top-level side effects because reload evaluates the module again. Implement `dispose()` when the asset exclusively owns disposable resources.\n\nAuthor GLTS scenes top-down: create the root entry scene first, reference the child `.glts` assets it will compose, then implement those children progressively. A missing `.glts` import renders as a glowing marker labeled with its filename until the real file is written, so the completed parts of the scene remain visible. Treat the marker and its console warning as a temporary missing-dependency diagnostic, not as authored content.\n\n```ts\nimport * as THREE from \"three\";\nimport Wheel from \"./parts/wheel.glts\";\n\nexport default class Racecar extends THREE.Group {\n constructor() {\n super();\n this.add(new Wheel());\n }\n}\n```\n\nUse relative `.glts` imports within a frame. When a reusable 3D asset belongs in another frame, keep it in its own GLTS frame and import its root by project-absolute path from the consuming frame. Instantiate that import as often as needed instead of copying its source:\n\n```ts\nimport Chassis from \"/other-frame-id/index.glts\";\n```\n\nFor a non-GLTS file from an image or Market frame, preserve the project filesystem URL through `import.meta.url`:\n\n```ts\nconst modelUrl = new URL(\"/market-frame-id/models/car.glb\", import.meta.url);\n```\n\nGLTS supports static `.glts`, `three`, Three addons, and bare npm imports. It does not support local helper `.ts` modules, dynamic imports, cyclic GLTS graphs, or cross-asset inheritance. Keep the asset self-contained and compose with nested GLTS assets.\n\nThe viewer uses the first camera found by depth-first traversal. If none exists, it autofits the asset. Put an authored camera in the scene only when its framing is intentional. Double-clicking a frame enters orbit from that resolved view; deselecting restores it.\n\nTreat authoritative source or structured state as sufficient when it directly and completely determines the requested property. Do not take a screenshot merely to reconfirm that evidence. Take one only when the result depends on rendering or visual relationships the source cannot establish, such as layout, overlap, clipping, camera framing, lighting, or runtime-generated appearance, or when the user explicitly asks. Then inspect it against the request and iterate until the evidence supports completion.\n";
2
+ export declare const cliDesignSkill = "---\nname: drawcall-design\ndescription: Create, modify, inspect, compose, and reuse 3D GLTS assets and optional image or Market references in Drawcall Design. Use whenever the user names Drawcall Design or one of its projects, canvases, frames, filesystems, or GLTS assets. Do not use for full games, applications, or unrelated image generation.\n---\n\n# Drawcall Design\n\n## CLI transport\n\nThe CLI is the only Drawcall transport in this environment. Do not search for MCP tools or make direct HTTP requests. A failed CLI command does not justify switching transport.\n\nCLI calls are shell command strings. Select the project with `-p <project-id>`. File commands take project-absolute paths that include the frame ID.\n\n```sh\nnpx @drawcall/design project list\nnpx @drawcall/design -p r6z2n9k4x8m1qc frame list\nnpx @drawcall/design -p r6z2n9k4x8m1qc ls\nnpx @drawcall/design -p r6z2n9k4x8m1qc read /a4z8m2q7v9kcde/index.glts\nnpx @drawcall/design -p r6z2n9k4x8m1qc edit /a4z8m2q7v9kcde/index.glts 'color: 0xffffff' 'color: 0x000000'\n```\n\nDesign is a remote, current-state canvas. Inspect the project and its frames before changing them. Use immutable IDs for every project and frame target; names are only labels.\n\n## Project filesystem\n\nA project is a hosted filesystem at `https://<project-id>.design.drawcallcontent.com/`. Each frame owns one top-level directory, `/<frame-id>`. Files use project-absolute paths that include that directory, for example `/a4z8m2q7v9kcde/index.glts`.\n\nCreate frames with an explicit type. Choose the type from the requested artifact, not from the word \"frame\": use GLTS for a 3D object or scene, especially one another frame will reuse. Use image only for a supplied 2D image URL and Market only for an exact public asset reference, `name@version`. GLTS frames require a viewport size; image and Market frames derive their canvas size.\n\nRead a file before editing it. Use a narrow edit for one known change and write a complete file when replacing it. Only GLTS frame files may be created or deleted. Image and Market frame files are read-only.\n\n## Failures\n\nAn error means the requested operation did not happen. Follow its next action without switching transport. Correct invalid arguments from the documented shape. Refresh projects, frames, or files after a not-found or conflict error, then reuse the exact returned IDs and paths. Retry an upstream or internal failure once; if it repeats, report the failed operation and error. Never repeat an unchanged failed operation.\n\n## GLTS assets\n\nA GLTS frame contains only `.glts` files. `index.glts` is its optional root asset; without it the frame renders empty. Every `.glts` file is a trusted TypeScript ESM module that default-exports a no-argument class derived from `THREE.Object3D`. Avoid top-level side effects because reload evaluates the module again. Implement `dispose()` when the asset exclusively owns disposable resources.\n\nAuthor GLTS scenes top-down: create the root entry scene first, reference the child `.glts` assets it will compose, then implement those children progressively. A missing `.glts` import renders as a glowing marker labeled with its filename until the real file is written, so the completed parts of the scene remain visible. Treat the marker and its console warning as a temporary missing-dependency diagnostic, not as authored content.\n\n```ts\nimport * as THREE from \"three\";\nimport Wheel from \"./parts/wheel.glts\";\n\nexport default class Racecar extends THREE.Group {\n constructor() {\n super();\n this.add(new Wheel());\n }\n}\n```\n\nUse relative `.glts` imports within a frame. When a reusable 3D asset belongs in another frame, keep it in its own GLTS frame and import its root by project-absolute path from the consuming frame. Instantiate that import as often as needed instead of copying its source:\n\n```ts\nimport Chassis from \"/other-frame-id/index.glts\";\n```\n\nFor a non-GLTS file from an image or Market frame, preserve the project filesystem URL through `import.meta.url`:\n\n```ts\nconst modelUrl = new URL(\"/market-frame-id/models/car.glb\", import.meta.url);\n```\n\nGLTS supports static `.glts`, `three`, Three addons, and bare npm imports. It does not support local helper `.ts` modules, dynamic imports, cyclic GLTS graphs, or cross-asset inheritance. Keep the asset self-contained and compose with nested GLTS assets.\n\nThe viewer uses the first camera found by depth-first traversal. If none exists, it autofits the asset. Put an authored camera in the scene only when its framing is intentional. Double-clicking a frame enters orbit from that resolved view; deselecting restores it.\n\nTreat authoritative source or structured state as sufficient when it directly and completely determines the requested property. Do not take a screenshot merely to reconfirm that evidence. Take one only when the result depends on rendering or visual relationships the source cannot establish, such as layout, overlap, clipping, camera framing, lighting, or runtime-generated appearance, or when the user explicitly asks. Then inspect it against the request and iterate until the evidence supports completion.\n";
@@ -1,2 +1,3 @@
1
- // Generated from skills/drawcall-design/SKILL.md.
2
- export const designSkill = '---\nname: drawcall-design\ndescription: Create, modify, inspect, and screenshot 3D assets and reference frames in Drawcall Design. Use for Drawcall Design projects, frames, the project filesystem, GLTS assets, or Drawcall Market frames. Do not use for full games or applications.\n---\n\n# Drawcall Design\n\nUse the Drawcall Design MCP tools when available. Otherwise use `npx @drawcall/design`. Design is a remote, current-state canvas: inspect the project and its frames before changing them. Use immutable IDs for every project and frame target; names are only labels.\n\n## Project filesystem\n\nA project is a hosted filesystem at `https://<project-id>.design.drawcallcontent.com/`. Each frame owns one top-level folder, `/<frame-id>/`. The CLI selects the project with `-p <project-id>`; its file paths are exactly the absolute paths inside that project, for example `/f7k3m9q2x8vd/index.glts`.\n\nCreate frames with an explicit type. GLTS frames require `--size`; image and Market frames derive their canvas size. A Market frame requires an exact public asset reference, `name@version`.\n\nRead a file before editing it. Use a narrow edit for one known change and write a complete file when replacing it. Only GLTS frame files may be created or deleted. Image and Market frame files are read-only.\n\n## GLTS assets\n\nA GLTS frame contains only `.glts` files. `index.glts` is its optional root asset; without it the frame renders empty. Every `.glts` file is a trusted TypeScript ESM module that default-exports a no-argument class derived from `THREE.Object3D`. Avoid top-level side effects because reload evaluates the module again. Implement `dispose()` when the asset exclusively owns disposable resources.\n\nAuthor GLTS scenes top-down: create the root entry scene first, reference the child `.glts` assets it will compose, then implement those children progressively. A missing `.glts` import renders as a glowing marker labeled with its filename until the real file is written, so the completed parts of the scene remain visible. Treat the marker and its console warning as a temporary missing-dependency diagnostic, not as authored content.\n\n```ts\nimport * as THREE from "three";\nimport Wheel from "./parts/wheel.glts";\n\nexport default class Racecar extends THREE.Group {\n constructor() {\n super();\n this.add(new Wheel());\n }\n}\n```\n\nUse relative `.glts` imports within a frame. Use a project-absolute path to import a GLTS asset from another frame:\n\n```ts\nimport Chassis from "/other-frame-id/index.glts";\n```\n\nFor a non-GLTS file from an image or Market frame, preserve the project filesystem URL through `import.meta.url`:\n\n```ts\nconst modelUrl = new URL("/market-frame-id/models/car.glb", import.meta.url);\n```\n\nGLTS supports static `.glts`, `three`, Three addons, and bare npm imports. It does not support local helper `.ts` modules, dynamic imports, cyclic GLTS graphs, or cross-asset inheritance. Keep the asset self-contained and compose with nested GLTS assets.\n\nThe viewer uses the first camera found by depth-first traversal. If none exists, it autofits the asset. Put an authored camera in the scene only when its framing is intentional. Double-clicking a frame enters orbit from that resolved view; deselecting restores it.\n\nAfter every meaningful visual change, take and inspect a screenshot. Iterate until the asset, camera, composition, and requested frame size are right.\n';
1
+ // Generated from skill/SKILL.template.md.
2
+ export const mcpDesignSkill = '---\nname: drawcall-design\ndescription: Create, modify, inspect, compose, and reuse 3D GLTS assets and optional image or Market references in Drawcall Design. Use whenever the user names Drawcall Design or one of its projects, canvases, frames, filesystems, or GLTS assets. Do not use for full games, applications, or unrelated image generation.\n---\n\n# Drawcall Design\n\n## MCP transport\n\nMCP tools are the only Drawcall transport in this environment. Do not invoke a CLI or shell, make direct HTTP requests, or search the web for another transport. A failed MCP call does not make MCP unavailable.\n\nUse `generate_image` only when the user asks for a 2D image or reference. A 3D object, scene, or reusable asset is GLTS work, even when the user calls its canvas container a frame.\n\nTool arguments are JSON objects. File tools identify their target with `project` and a project-absolute `path`; they do not accept a separate `frame` argument. Call `list_files` and pass one of its returned paths unchanged.\n\n```json\n[\n {\n "tool": "list_projects",\n "arguments": {}\n },\n {\n "tool": "list_frames",\n "arguments": {\n "project": "r6z2n9k4x8m1qc"\n }\n },\n {\n "tool": "list_files",\n "arguments": {\n "project": "r6z2n9k4x8m1qc"\n }\n },\n {\n "tool": "read_file",\n "arguments": {\n "project": "r6z2n9k4x8m1qc",\n "path": "/a4z8m2q7v9kcde/index.glts"\n }\n },\n {\n "tool": "edit_file",\n "arguments": {\n "project": "r6z2n9k4x8m1qc",\n "path": "/a4z8m2q7v9kcde/index.glts",\n "oldText": "color: 0xffffff",\n "newText": "color: 0x000000"\n }\n }\n]\n```\n\nDesign is a remote, current-state canvas. Inspect the project and its frames before changing them. Use immutable IDs for every project and frame target; names are only labels.\n\n## Project filesystem\n\nA project is a hosted filesystem at `https://<project-id>.design.drawcallcontent.com/`. Each frame owns one top-level directory, `/<frame-id>`. Files use project-absolute paths that include that directory, for example `/a4z8m2q7v9kcde/index.glts`.\n\nCreate frames with an explicit type. Choose the type from the requested artifact, not from the word "frame": use GLTS for a 3D object or scene, especially one another frame will reuse. Use image only for a supplied 2D image URL and Market only for an exact public asset reference, `name@version`. GLTS frames require a viewport size; image and Market frames derive their canvas size.\n\nRead a file before editing it. Use a narrow edit for one known change and write a complete file when replacing it. Only GLTS frame files may be created or deleted. Image and Market frame files are read-only.\n\n## Failures\n\nAn error means the requested operation did not happen. Follow its next action without switching transport. Correct invalid arguments from the documented shape. Refresh projects, frames, or files after a not-found or conflict error, then reuse the exact returned IDs and paths. Retry an upstream or internal failure once; if it repeats, report the failed operation and error. Never repeat an unchanged failed operation.\n\n## GLTS assets\n\nA GLTS frame contains only `.glts` files. `index.glts` is its optional root asset; without it the frame renders empty. Every `.glts` file is a trusted TypeScript ESM module that default-exports a no-argument class derived from `THREE.Object3D`. Avoid top-level side effects because reload evaluates the module again. Implement `dispose()` when the asset exclusively owns disposable resources.\n\nAuthor GLTS scenes top-down: create the root entry scene first, reference the child `.glts` assets it will compose, then implement those children progressively. A missing `.glts` import renders as a glowing marker labeled with its filename until the real file is written, so the completed parts of the scene remain visible. Treat the marker and its console warning as a temporary missing-dependency diagnostic, not as authored content.\n\n```ts\nimport * as THREE from "three";\nimport Wheel from "./parts/wheel.glts";\n\nexport default class Racecar extends THREE.Group {\n constructor() {\n super();\n this.add(new Wheel());\n }\n}\n```\n\nUse relative `.glts` imports within a frame. When a reusable 3D asset belongs in another frame, keep it in its own GLTS frame and import its root by project-absolute path from the consuming frame. Instantiate that import as often as needed instead of copying its source:\n\n```ts\nimport Chassis from "/other-frame-id/index.glts";\n```\n\nFor a non-GLTS file from an image or Market frame, preserve the project filesystem URL through `import.meta.url`:\n\n```ts\nconst modelUrl = new URL("/market-frame-id/models/car.glb", import.meta.url);\n```\n\nGLTS supports static `.glts`, `three`, Three addons, and bare npm imports. It does not support local helper `.ts` modules, dynamic imports, cyclic GLTS graphs, or cross-asset inheritance. Keep the asset self-contained and compose with nested GLTS assets.\n\nThe viewer uses the first camera found by depth-first traversal. If none exists, it autofits the asset. Put an authored camera in the scene only when its framing is intentional. Double-clicking a frame enters orbit from that resolved view; deselecting restores it.\n\nTreat authoritative source or structured state as sufficient when it directly and completely determines the requested property. Do not take a screenshot merely to reconfirm that evidence. Take one only when the result depends on rendering or visual relationships the source cannot establish, such as layout, overlap, clipping, camera framing, lighting, or runtime-generated appearance, or when the user explicitly asks. Then inspect it against the request and iterate until the evidence supports completion.\n';
3
+ export const cliDesignSkill = '---\nname: drawcall-design\ndescription: Create, modify, inspect, compose, and reuse 3D GLTS assets and optional image or Market references in Drawcall Design. Use whenever the user names Drawcall Design or one of its projects, canvases, frames, filesystems, or GLTS assets. Do not use for full games, applications, or unrelated image generation.\n---\n\n# Drawcall Design\n\n## CLI transport\n\nThe CLI is the only Drawcall transport in this environment. Do not search for MCP tools or make direct HTTP requests. A failed CLI command does not justify switching transport.\n\nCLI calls are shell command strings. Select the project with `-p <project-id>`. File commands take project-absolute paths that include the frame ID.\n\n```sh\nnpx @drawcall/design project list\nnpx @drawcall/design -p r6z2n9k4x8m1qc frame list\nnpx @drawcall/design -p r6z2n9k4x8m1qc ls\nnpx @drawcall/design -p r6z2n9k4x8m1qc read /a4z8m2q7v9kcde/index.glts\nnpx @drawcall/design -p r6z2n9k4x8m1qc edit /a4z8m2q7v9kcde/index.glts \'color: 0xffffff\' \'color: 0x000000\'\n```\n\nDesign is a remote, current-state canvas. Inspect the project and its frames before changing them. Use immutable IDs for every project and frame target; names are only labels.\n\n## Project filesystem\n\nA project is a hosted filesystem at `https://<project-id>.design.drawcallcontent.com/`. Each frame owns one top-level directory, `/<frame-id>`. Files use project-absolute paths that include that directory, for example `/a4z8m2q7v9kcde/index.glts`.\n\nCreate frames with an explicit type. Choose the type from the requested artifact, not from the word "frame": use GLTS for a 3D object or scene, especially one another frame will reuse. Use image only for a supplied 2D image URL and Market only for an exact public asset reference, `name@version`. GLTS frames require a viewport size; image and Market frames derive their canvas size.\n\nRead a file before editing it. Use a narrow edit for one known change and write a complete file when replacing it. Only GLTS frame files may be created or deleted. Image and Market frame files are read-only.\n\n## Failures\n\nAn error means the requested operation did not happen. Follow its next action without switching transport. Correct invalid arguments from the documented shape. Refresh projects, frames, or files after a not-found or conflict error, then reuse the exact returned IDs and paths. Retry an upstream or internal failure once; if it repeats, report the failed operation and error. Never repeat an unchanged failed operation.\n\n## GLTS assets\n\nA GLTS frame contains only `.glts` files. `index.glts` is its optional root asset; without it the frame renders empty. Every `.glts` file is a trusted TypeScript ESM module that default-exports a no-argument class derived from `THREE.Object3D`. Avoid top-level side effects because reload evaluates the module again. Implement `dispose()` when the asset exclusively owns disposable resources.\n\nAuthor GLTS scenes top-down: create the root entry scene first, reference the child `.glts` assets it will compose, then implement those children progressively. A missing `.glts` import renders as a glowing marker labeled with its filename until the real file is written, so the completed parts of the scene remain visible. Treat the marker and its console warning as a temporary missing-dependency diagnostic, not as authored content.\n\n```ts\nimport * as THREE from "three";\nimport Wheel from "./parts/wheel.glts";\n\nexport default class Racecar extends THREE.Group {\n constructor() {\n super();\n this.add(new Wheel());\n }\n}\n```\n\nUse relative `.glts` imports within a frame. When a reusable 3D asset belongs in another frame, keep it in its own GLTS frame and import its root by project-absolute path from the consuming frame. Instantiate that import as often as needed instead of copying its source:\n\n```ts\nimport Chassis from "/other-frame-id/index.glts";\n```\n\nFor a non-GLTS file from an image or Market frame, preserve the project filesystem URL through `import.meta.url`:\n\n```ts\nconst modelUrl = new URL("/market-frame-id/models/car.glb", import.meta.url);\n```\n\nGLTS supports static `.glts`, `three`, Three addons, and bare npm imports. It does not support local helper `.ts` modules, dynamic imports, cyclic GLTS graphs, or cross-asset inheritance. Keep the asset self-contained and compose with nested GLTS assets.\n\nThe viewer uses the first camera found by depth-first traversal. If none exists, it autofits the asset. Put an authored camera in the scene only when its framing is intentional. Double-clicking a frame enters orbit from that resolved view; deselecting restores it.\n\nTreat authoritative source or structured state as sufficient when it directly and completely determines the requested property. Do not take a screenshot merely to reconfirm that evidence. Take one only when the result depends on rendering or visual relationships the source cannot establish, such as layout, overlap, clipping, camera framing, lighting, or runtime-generated appearance, or when the user explicitly asks. Then inspect it against the request and iterate until the evidence supports completion.\n';
@@ -603,6 +603,101 @@ export declare const contract: {
603
603
  type: z.ZodLiteral<"market">;
604
604
  asset: z.ZodString;
605
605
  }, z.core.$strip>], "type">, Record<never, never>, Record<never, never>>;
606
+ setLayout: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<z.ZodObject<{
607
+ project: z.ZodString;
608
+ frame: z.ZodString;
609
+ x: z.ZodNumber;
610
+ y: z.ZodNumber;
611
+ width: z.ZodNumber;
612
+ height: z.ZodNumber;
613
+ }, z.core.$strip>, z.ZodDiscriminatedUnion<[z.ZodObject<{
614
+ id: z.ZodString;
615
+ projectId: z.ZodString;
616
+ name: z.ZodString;
617
+ x: z.ZodNumber;
618
+ y: z.ZodNumber;
619
+ width: z.ZodNumber;
620
+ height: z.ZodNumber;
621
+ viewUrl: z.ZodString;
622
+ createdAt: z.ZodString;
623
+ updatedAt: z.ZodString;
624
+ type: z.ZodLiteral<"glts">;
625
+ camera: z.ZodOptional<z.ZodObject<{
626
+ position: z.ZodObject<{
627
+ x: z.ZodNumber;
628
+ y: z.ZodNumber;
629
+ z: z.ZodNumber;
630
+ }, z.core.$strict>;
631
+ quaternion: z.ZodObject<{
632
+ x: z.ZodNumber;
633
+ y: z.ZodNumber;
634
+ z: z.ZodNumber;
635
+ w: z.ZodNumber;
636
+ }, z.core.$strict>;
637
+ }, z.core.$strict>>;
638
+ contentRevision: z.ZodNumber;
639
+ }, z.core.$strip>, z.ZodObject<{
640
+ id: z.ZodString;
641
+ projectId: z.ZodString;
642
+ name: z.ZodString;
643
+ x: z.ZodNumber;
644
+ y: z.ZodNumber;
645
+ width: z.ZodNumber;
646
+ height: z.ZodNumber;
647
+ viewUrl: z.ZodString;
648
+ createdAt: z.ZodString;
649
+ updatedAt: z.ZodString;
650
+ type: z.ZodLiteral<"image">;
651
+ file: z.ZodString;
652
+ provenance: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
653
+ kind: z.ZodLiteral<"generated">;
654
+ operation: z.ZodEnum<{
655
+ generate: "generate";
656
+ edit: "edit";
657
+ }>;
658
+ prompt: z.ZodString;
659
+ references: z.ZodArray<z.ZodObject<{
660
+ frameId: z.ZodString;
661
+ frameUpdatedAt: z.ZodString;
662
+ }, z.core.$strip>>;
663
+ result: z.ZodEnum<{
664
+ replace: "replace";
665
+ new: "new";
666
+ }>;
667
+ provider: z.ZodLiteral<"fal-ai">;
668
+ model: z.ZodLiteral<"openai/gpt-image-2">;
669
+ }, z.core.$strip>, z.ZodObject<{
670
+ kind: z.ZodLiteral<"generated">;
671
+ operation: z.ZodEnum<{
672
+ generate: "generate";
673
+ edit: "edit";
674
+ }>;
675
+ prompt: z.ZodString;
676
+ references: z.ZodArray<z.ZodObject<{
677
+ frameId: z.ZodString;
678
+ frameUpdatedAt: z.ZodString;
679
+ }, z.core.$strip>>;
680
+ result: z.ZodEnum<{
681
+ replace: "replace";
682
+ new: "new";
683
+ }>;
684
+ provider: z.ZodLiteral<"cloudflare-workers-ai">;
685
+ model: z.ZodLiteral<"@cf/black-forest-labs/flux-2-klein-4b">;
686
+ }, z.core.$strip>], "provider">>;
687
+ }, z.core.$strip>, z.ZodObject<{
688
+ id: z.ZodString;
689
+ projectId: z.ZodString;
690
+ name: z.ZodString;
691
+ x: z.ZodNumber;
692
+ y: z.ZodNumber;
693
+ width: z.ZodNumber;
694
+ height: z.ZodNumber;
695
+ viewUrl: z.ZodString;
696
+ createdAt: z.ZodString;
697
+ updatedAt: z.ZodString;
698
+ type: z.ZodLiteral<"market">;
699
+ asset: z.ZodString;
700
+ }, z.core.$strip>], "type">, Record<never, never>, Record<never, never>>;
606
701
  delete: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<z.ZodObject<{
607
702
  project: z.ZodString;
608
703
  frame: z.ZodString;
@@ -1,9 +1,12 @@
1
1
  import { oc } from "@orpc/contract";
2
2
  import { z } from "zod";
3
- import { cameraPoseSchema, createFrameSchema, createProjectFromBriefSchema, designIdSchema, fileListSchema, fileMutationSchema, fileSchema, fileTextSchema, frameExportSchema, frameNameSchema, frameSchema, generateImageFrameSchema, projectDirectoryPathSchema, projectNameSchema, projectPathSchema, projectSchema, screenshotSchema, userSchema, } from "./schemas.js";
3
+ import { projectFrameLayoutSchema } from "../project-state.js";
4
+ import { cameraPoseSchema, createFrameSchema, createProjectFromBriefSchema, designIdSchema, fileListSchema, fileMutationSchema, fileSchema, fileTextSchema, frameExportSchema, frameNameSchema, frameSchema, generateImageFrameSchema, projectDirectoryPathSchema, projectFilePathSchema, projectNameSchema, projectSchema, screenshotSchema, userSchema, } from "./schemas.js";
4
5
  const projectInputSchema = z.object({ project: designIdSchema });
5
6
  const frameInputSchema = projectInputSchema.extend({ frame: designIdSchema });
6
- const fileInputSchema = projectInputSchema.extend({ path: projectPathSchema });
7
+ const fileInputSchema = projectInputSchema.extend({
8
+ path: projectFilePathSchema,
9
+ });
7
10
  const deletedSchema = z.object({ id: designIdSchema });
8
11
  export const contract = {
9
12
  user: {
@@ -68,6 +71,13 @@ export const contract = {
68
71
  expectedUpdatedAt: z.string().datetime(),
69
72
  }))
70
73
  .output(frameSchema),
74
+ setLayout: oc
75
+ .route({
76
+ method: "PUT",
77
+ path: "/projects/{project}/frames/{frame}/layout",
78
+ })
79
+ .input(frameInputSchema.extend(projectFrameLayoutSchema.shape))
80
+ .output(frameSchema),
71
81
  delete: oc
72
82
  .route({ method: "DELETE", path: "/projects/{project}/frames/{frame}" })
73
83
  .input(frameInputSchema)
@@ -35,6 +35,7 @@ export declare const imageUrlSchema: z.ZodString;
35
35
  export declare const projectPathSchema: z.ZodString;
36
36
  /** A project directory path. `/` denotes the project root. */
37
37
  export declare const projectDirectoryPathSchema: z.ZodUnion<readonly [z.ZodLiteral<"/">, z.ZodString]>;
38
+ export declare const projectFilePathSchema: z.ZodString;
38
39
  export declare const fileTextSchema: z.ZodString;
39
40
  export declare const marketAssetNameSchema: z.ZodString;
40
41
  export declare const marketAssetVersionSchema: z.ZodString;
@@ -5,7 +5,7 @@ export const MAX_IMAGE_GENERATION_PROMPT_LENGTH = 2_048;
5
5
  export const MAX_IMAGE_GENERATION_REFERENCES = 4;
6
6
  export const designIdSchema = z
7
7
  .string()
8
- .regex(/^[a-z0-9]{14}$/, "IDs are 14 lowercase alphanumeric characters");
8
+ .regex(/^[a-z0-9]{14}$/, "IDs are exactly 14 lowercase alphanumeric characters; use an ID returned by a list operation");
9
9
  export const projectNameSchema = z
10
10
  .string()
11
11
  .trim()
@@ -66,8 +66,11 @@ export const projectPathSchema = z.string().max(1_024).refine(isProjectPath, {
66
66
  export const projectDirectoryPathSchema = z
67
67
  .union([z.literal("/"), projectPathSchema])
68
68
  .refine((path) => path === "/" || !path.endsWith("/"), {
69
- message: "Directory paths cannot end with /",
69
+ message: "Directory paths cannot end with /. Use /<frame-id> or omit the path to list the entire project",
70
70
  });
71
+ export const projectFilePathSchema = projectPathSchema
72
+ .regex(/^\/[a-z0-9]{14}\/.+/, "Project file paths must include a frame ID and filename, for example /a4z8m2q7v9kcde/index.glts")
73
+ .describe("Project-absolute file path including the frame ID, for example /a4z8m2q7v9kcde/index.glts");
71
74
  export const fileTextSchema = z.string().max(MAX_FILE_LENGTH);
72
75
  export const marketAssetNameSchema = z
73
76
  .string()
@@ -148,7 +151,7 @@ export const imageGenerationProvenanceSchema = z.discriminatedUnion("provider",
148
151
  ]);
149
152
  export const imageFrameSchema = frameBaseSchema.extend({
150
153
  type: z.literal("image"),
151
- file: projectPathSchema,
154
+ file: projectFilePathSchema,
152
155
  provenance: imageGenerationProvenanceSchema.optional(),
153
156
  });
154
157
  export const marketFrameSchema = frameBaseSchema.extend({
@@ -273,17 +276,17 @@ export const generateImageFrameSchema = z
273
276
  }
274
277
  });
275
278
  export const fileListSchema = z.object({
276
- paths: z.array(projectPathSchema),
279
+ paths: z.array(projectFilePathSchema),
277
280
  });
278
281
  export const textFileSchema = z.object({
279
282
  type: z.literal("text"),
280
- path: projectPathSchema,
283
+ path: projectFilePathSchema,
281
284
  text: z.string(),
282
285
  mediaType: z.literal("text/plain"),
283
286
  });
284
287
  export const binaryFileSchema = z.object({
285
288
  type: z.literal("binary"),
286
- path: projectPathSchema,
289
+ path: projectFilePathSchema,
287
290
  url: httpUrlSchema,
288
291
  mediaType: z.string().min(1),
289
292
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drawcall/design",
3
- "version": "0.5.1",
3
+ "version": "0.5.3",
4
4
  "description": "Typed API and remote CLI for Drawcall Design",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,20 +1,38 @@
1
1
  ---
2
2
  name: drawcall-design
3
- description: Create, modify, inspect, and screenshot 3D assets and reference frames in Drawcall Design. Use for Drawcall Design projects, frames, the project filesystem, GLTS assets, or Drawcall Market frames. Do not use for full games or applications.
3
+ description: Create, modify, inspect, compose, and reuse 3D GLTS assets and optional image or Market references in Drawcall Design. Use whenever the user names Drawcall Design or one of its projects, canvases, frames, filesystems, or GLTS assets. Do not use for full games, applications, or unrelated image generation.
4
4
  ---
5
5
 
6
6
  # Drawcall Design
7
7
 
8
- Use the Drawcall Design MCP tools when available. Otherwise use `npx @drawcall/design`. Design is a remote, current-state canvas: inspect the project and its frames before changing them. Use immutable IDs for every project and frame target; names are only labels.
8
+ ## CLI transport
9
+
10
+ The CLI is the only Drawcall transport in this environment. Do not search for MCP tools or make direct HTTP requests. A failed CLI command does not justify switching transport.
11
+
12
+ CLI calls are shell command strings. Select the project with `-p <project-id>`. File commands take project-absolute paths that include the frame ID.
13
+
14
+ ```sh
15
+ npx @drawcall/design project list
16
+ npx @drawcall/design -p r6z2n9k4x8m1qc frame list
17
+ npx @drawcall/design -p r6z2n9k4x8m1qc ls
18
+ npx @drawcall/design -p r6z2n9k4x8m1qc read /a4z8m2q7v9kcde/index.glts
19
+ npx @drawcall/design -p r6z2n9k4x8m1qc edit /a4z8m2q7v9kcde/index.glts 'color: 0xffffff' 'color: 0x000000'
20
+ ```
21
+
22
+ Design is a remote, current-state canvas. Inspect the project and its frames before changing them. Use immutable IDs for every project and frame target; names are only labels.
9
23
 
10
24
  ## Project filesystem
11
25
 
12
- A project is a hosted filesystem at `https://<project-id>.design.drawcallcontent.com/`. Each frame owns one top-level folder, `/<frame-id>/`. The CLI selects the project with `-p <project-id>`; its file paths are exactly the absolute paths inside that project, for example `/f7k3m9q2x8vd/index.glts`.
26
+ A project is a hosted filesystem at `https://<project-id>.design.drawcallcontent.com/`. Each frame owns one top-level directory, `/<frame-id>`. Files use project-absolute paths that include that directory, for example `/a4z8m2q7v9kcde/index.glts`.
13
27
 
14
- Create frames with an explicit type. GLTS frames require `--size`; image and Market frames derive their canvas size. A Market frame requires an exact public asset reference, `name@version`.
28
+ Create frames with an explicit type. Choose the type from the requested artifact, not from the word "frame": use GLTS for a 3D object or scene, especially one another frame will reuse. Use image only for a supplied 2D image URL and Market only for an exact public asset reference, `name@version`. GLTS frames require a viewport size; image and Market frames derive their canvas size.
15
29
 
16
30
  Read a file before editing it. Use a narrow edit for one known change and write a complete file when replacing it. Only GLTS frame files may be created or deleted. Image and Market frame files are read-only.
17
31
 
32
+ ## Failures
33
+
34
+ An error means the requested operation did not happen. Follow its next action without switching transport. Correct invalid arguments from the documented shape. Refresh projects, frames, or files after a not-found or conflict error, then reuse the exact returned IDs and paths. Retry an upstream or internal failure once; if it repeats, report the failed operation and error. Never repeat an unchanged failed operation.
35
+
18
36
  ## GLTS assets
19
37
 
20
38
  A GLTS frame contains only `.glts` files. `index.glts` is its optional root asset; without it the frame renders empty. Every `.glts` file is a trusted TypeScript ESM module that default-exports a no-argument class derived from `THREE.Object3D`. Avoid top-level side effects because reload evaluates the module again. Implement `dispose()` when the asset exclusively owns disposable resources.
@@ -33,7 +51,7 @@ export default class Racecar extends THREE.Group {
33
51
  }
34
52
  ```
35
53
 
36
- Use relative `.glts` imports within a frame. Use a project-absolute path to import a GLTS asset from another frame:
54
+ Use relative `.glts` imports within a frame. When a reusable 3D asset belongs in another frame, keep it in its own GLTS frame and import its root by project-absolute path from the consuming frame. Instantiate that import as often as needed instead of copying its source:
37
55
 
38
56
  ```ts
39
57
  import Chassis from "/other-frame-id/index.glts";
@@ -49,4 +67,4 @@ GLTS supports static `.glts`, `three`, Three addons, and bare npm imports. It do
49
67
 
50
68
  The viewer uses the first camera found by depth-first traversal. If none exists, it autofits the asset. Put an authored camera in the scene only when its framing is intentional. Double-clicking a frame enters orbit from that resolved view; deselecting restores it.
51
69
 
52
- After every meaningful visual change, take and inspect a screenshot. Iterate until the asset, camera, composition, and requested frame size are right.
70
+ Treat authoritative source or structured state as sufficient when it directly and completely determines the requested property. Do not take a screenshot merely to reconfirm that evidence. Take one only when the result depends on rendering or visual relationships the source cannot establish, such as layout, overlap, clipping, camera framing, lighting, or runtime-generated appearance, or when the user explicitly asks. Then inspect it against the request and iterate until the evidence supports completion.