@drawcall/design 0.1.8 → 0.2.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/README.md +20 -10
- package/dist/cli.js +142 -141
- package/dist/index.d.ts +2 -3
- package/dist/index.js +1 -2
- package/dist/skill.generated.d.ts +1 -1
- package/dist/skill.generated.js +1 -1
- package/dist/target.d.ts +0 -14
- package/dist/target.js +0 -23
- package/dist/v1/contract.d.ts +109 -67
- package/dist/v1/contract.js +32 -54
- package/dist/v1/schemas.d.ts +107 -44
- package/dist/v1/schemas.js +86 -60
- package/package.json +1 -1
- package/skills/drawcall-design/SKILL.md +30 -15
- package/dist/source.d.ts +0 -10
- package/dist/source.js +0 -38
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @drawcall/design
|
|
2
2
|
|
|
3
|
-
The Drawcall Design v1
|
|
3
|
+
The typed Drawcall Design v1 contract, client, and remote CLI.
|
|
4
4
|
|
|
5
5
|
```ts
|
|
6
6
|
import { v1 } from "@drawcall/design";
|
|
@@ -9,17 +9,27 @@ const design = v1.createClient({ authToken: process.env.DRAWCALL_AUTH_TOKEN });
|
|
|
9
9
|
const projects = await design.project.list();
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
+
Projects and frames have immutable 14-character lowercase IDs. A project is a hosted filesystem at `https://<project-id>.design.drawcallcontent.com/`; every frame owns `/<frame-id>/` within it.
|
|
13
|
+
|
|
12
14
|
```sh
|
|
13
15
|
npx @drawcall/design login
|
|
14
|
-
npx @drawcall/design skill
|
|
15
16
|
npx @drawcall/design project create showroom
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
npx @drawcall/design frame create
|
|
19
|
-
|
|
17
|
+
# `project list` prints: <project-id> <name>
|
|
18
|
+
|
|
19
|
+
npx @drawcall/design -p r6z2n9k4x8m1qc frame create racecar \
|
|
20
|
+
--type glts --size 800x800
|
|
21
|
+
# `frame create` prints its frame ID and /<frame-id>/ path.
|
|
22
|
+
|
|
23
|
+
npx @drawcall/design -p r6z2n9k4x8m1qc write /a4z8m2q7v9kcde/index.glts \
|
|
24
|
+
'export default class Racecar extends THREE.Group {}'
|
|
25
|
+
npx @drawcall/design -p r6z2n9k4x8m1qc ls /
|
|
26
|
+
npx @drawcall/design -p r6z2n9k4x8m1qc read /a4z8m2q7v9kcde/index.glts
|
|
27
|
+
npx @drawcall/design -p r6z2n9k4x8m1qc frame screenshot a4z8m2q7v9kcde
|
|
28
|
+
|
|
29
|
+
npx @drawcall/design -p r6z2n9k4x8m1qc frame create reference \
|
|
30
|
+
--type image --image ./reference.png
|
|
31
|
+
npx @drawcall/design -p r6z2n9k4x8m1qc frame create oak-chair \
|
|
32
|
+
--type market --asset oak-chair@1.2.3
|
|
20
33
|
```
|
|
21
34
|
|
|
22
|
-
|
|
23
|
-
linking. `frame source replace` accepts a `Record<path, code>` JSON object inline or on stdin.
|
|
24
|
-
Agents should read `npx @drawcall/design skill` before creating or changing code-frame source. MCP
|
|
25
|
-
clients get the same text from `get_skill`.
|
|
35
|
+
GLTS frames accept only `.glts` files. `index.glts` is optional: an absent entry renders an empty frame. Image and Market files are available through the same filesystem but are read-only. Read `npx @drawcall/design skill` (or MCP `get_skill`) before creating or changing a GLTS asset.
|
package/dist/cli.js
CHANGED
|
@@ -5,18 +5,17 @@ import { clearConfig, getConfigPath, saveConfig } from "./config.js";
|
|
|
5
5
|
import { getCliClient } from "./cli-client.js";
|
|
6
6
|
import { readImageInput } from "./image.js";
|
|
7
7
|
import { designSkill } from "./skill.generated.js";
|
|
8
|
-
import { parseFrameSize
|
|
8
|
+
import { parseFrameSize } from "./target.js";
|
|
9
9
|
import { createClient, DEFAULT_BASE_URL } from "./v1/client.js";
|
|
10
|
+
import { designIdSchema, marketAssetSchema } from "./v1/schemas.js";
|
|
10
11
|
const AUTH_ISSUER_URL = "https://auth.drawcall.ai/api/auth";
|
|
11
12
|
const DEVICE_CLIENT_ID = "drawcall-cli";
|
|
12
|
-
function sourceInput(source) {
|
|
13
|
-
return source === undefined ? {} : { source: { "/index.ts": source } };
|
|
14
|
-
}
|
|
15
13
|
const program = new Command()
|
|
16
14
|
.name("design")
|
|
17
|
-
.description("Design 3D
|
|
15
|
+
.description("Design 3D assets on Drawcall Design")
|
|
18
16
|
.version(readPackageVersion())
|
|
19
|
-
.addOption(new Option("--api <url>", "Design API URL").default(process.env.DESIGN_API_URL, "from DESIGN_API_URL / config / default"))
|
|
17
|
+
.addOption(new Option("--api <url>", "Design API URL").default(process.env.DESIGN_API_URL, "from DESIGN_API_URL / config / default"))
|
|
18
|
+
.addOption(new Option("-p, --project <id>", "Project ID"));
|
|
20
19
|
program
|
|
21
20
|
.command("skill")
|
|
22
21
|
.description("Print the Drawcall Design skill")
|
|
@@ -53,7 +52,7 @@ project
|
|
|
53
52
|
return;
|
|
54
53
|
}
|
|
55
54
|
for (const item of projects)
|
|
56
|
-
console.log(`${item.
|
|
55
|
+
console.log(`${item.id}\t${item.name}`);
|
|
57
56
|
});
|
|
58
57
|
project
|
|
59
58
|
.command("create")
|
|
@@ -62,190 +61,163 @@ project
|
|
|
62
61
|
.action(async (name, _options, command) => {
|
|
63
62
|
const client = await clientFor(command);
|
|
64
63
|
const created = await client.project.create({ name });
|
|
65
|
-
console.log(`Created ${created.
|
|
64
|
+
console.log(`Created ${created.id}\t${created.name}`);
|
|
66
65
|
});
|
|
67
66
|
project
|
|
68
67
|
.command("delete")
|
|
69
68
|
.description("Delete a project")
|
|
70
|
-
.argument("<
|
|
69
|
+
.argument("<project-id>", "Project ID")
|
|
71
70
|
.option("-y, --yes", "Confirm deletion", false)
|
|
72
|
-
.action(async (
|
|
71
|
+
.action(async (projectId, options, command) => {
|
|
73
72
|
requireConfirmation(options.yes);
|
|
73
|
+
const id = designIdSchema.parse(projectId);
|
|
74
74
|
const client = await clientFor(command);
|
|
75
|
-
await client.project.delete({ project:
|
|
76
|
-
console.log(`Deleted ${
|
|
75
|
+
await client.project.delete({ project: id });
|
|
76
|
+
console.log(`Deleted ${id}.`);
|
|
77
77
|
});
|
|
78
78
|
const frame = program.command("frame").description("Manage frames");
|
|
79
79
|
frame
|
|
80
80
|
.command("list")
|
|
81
|
-
.description("List frames in
|
|
82
|
-
.
|
|
83
|
-
.action(async (projectName, _options, command) => {
|
|
81
|
+
.description("List frames in the selected project")
|
|
82
|
+
.action(async (_options, command) => {
|
|
84
83
|
const client = await clientFor(command);
|
|
85
|
-
const frames = await client.frame.list({ project:
|
|
84
|
+
const frames = await client.frame.list({ project: projectId(command) });
|
|
86
85
|
if (frames.length === 0) {
|
|
87
86
|
console.log("No frames.");
|
|
88
87
|
return;
|
|
89
88
|
}
|
|
90
89
|
for (const item of frames) {
|
|
91
|
-
console.log(`${item.
|
|
90
|
+
console.log(`${item.id}\t${item.name}\t${item.type}\t${item.width}x${item.height}`);
|
|
92
91
|
}
|
|
93
92
|
});
|
|
94
93
|
frame
|
|
95
94
|
.command("create")
|
|
96
|
-
.description("Create a
|
|
97
|
-
.argument("<
|
|
98
|
-
.
|
|
99
|
-
.
|
|
100
|
-
.option("--image <url-or-path>", "
|
|
101
|
-
.
|
|
102
|
-
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
throw new Error("Source and --image cannot be used together");
|
|
106
|
-
}
|
|
95
|
+
.description("Create a GLTS, image, or pinned Market frame")
|
|
96
|
+
.argument("<name>", "Frame name")
|
|
97
|
+
.requiredOption("-t, --type <type>", "glts, image, or market")
|
|
98
|
+
.option("-s, --size <width>x<height>", "GLTS viewport size")
|
|
99
|
+
.option("--image <url-or-path>", "Image URL or local PNG, JPEG, or WebP")
|
|
100
|
+
.option("--asset <name@version>", "Exact public Market asset version")
|
|
101
|
+
.action(async (name, options, command) => {
|
|
102
|
+
const project = projectId(command);
|
|
103
|
+
const input = await createFrameInput(project, name, options);
|
|
107
104
|
const client = await clientFor(command);
|
|
108
|
-
const created =
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
name: target.frame,
|
|
112
|
-
kind: "code",
|
|
113
|
-
...size,
|
|
114
|
-
...sourceInput(await optionalIndexSource(sourceValue)),
|
|
115
|
-
})
|
|
116
|
-
: await client.frame.create({
|
|
117
|
-
project: target.project,
|
|
118
|
-
name: target.frame,
|
|
119
|
-
kind: "image",
|
|
120
|
-
image: await readImageInput(options.image),
|
|
121
|
-
...size,
|
|
122
|
-
});
|
|
123
|
-
console.log(`Created ${targetValue}\t${created.id}`);
|
|
105
|
+
const created = await client.frame.create(input);
|
|
106
|
+
console.log(`Created ${created.id}\t${created.name}\t${created.type}`);
|
|
107
|
+
console.log(`Path /${created.id}/`);
|
|
124
108
|
});
|
|
125
109
|
frame
|
|
126
110
|
.command("rename")
|
|
127
111
|
.description("Rename a frame")
|
|
128
|
-
.argument("<
|
|
112
|
+
.argument("<frame-id>", "Frame ID")
|
|
129
113
|
.argument("<name>", "New frame name")
|
|
130
|
-
.action(async (
|
|
114
|
+
.action(async (frameId, name, _options, command) => {
|
|
115
|
+
const id = designIdSchema.parse(frameId);
|
|
131
116
|
const client = await clientFor(command);
|
|
132
117
|
const renamed = await client.frame.rename({
|
|
133
|
-
|
|
118
|
+
project: projectId(command),
|
|
119
|
+
frame: id,
|
|
134
120
|
name,
|
|
135
121
|
});
|
|
136
|
-
console.log(`Renamed ${
|
|
122
|
+
console.log(`Renamed ${renamed.id}\t${renamed.name}.`);
|
|
137
123
|
});
|
|
138
124
|
frame
|
|
139
125
|
.command("delete")
|
|
140
|
-
.description("Delete
|
|
141
|
-
.argument("<
|
|
126
|
+
.description("Delete frames")
|
|
127
|
+
.argument("<frame-id...>", "Frame IDs")
|
|
142
128
|
.option("-y, --yes", "Confirm deletion", false)
|
|
143
|
-
.action(async (
|
|
129
|
+
.action(async (frameIds, options, command) => {
|
|
144
130
|
requireConfirmation(options.yes);
|
|
131
|
+
const project = projectId(command);
|
|
145
132
|
const client = await clientFor(command);
|
|
146
|
-
for (const
|
|
147
|
-
|
|
148
|
-
|
|
133
|
+
for (const frameId of frameIds) {
|
|
134
|
+
const id = designIdSchema.parse(frameId);
|
|
135
|
+
await client.frame.delete({ project, frame: id });
|
|
136
|
+
console.log(`Deleted ${id}.`);
|
|
149
137
|
}
|
|
150
138
|
});
|
|
151
139
|
frame
|
|
152
140
|
.command("screenshot")
|
|
153
141
|
.description("Render frames and print their screenshot URLs")
|
|
154
|
-
.argument("<
|
|
155
|
-
.action(async (
|
|
142
|
+
.argument("<frame-id...>", "Frame IDs")
|
|
143
|
+
.action(async (frameIds, _options, command) => {
|
|
144
|
+
const project = projectId(command);
|
|
156
145
|
const client = await clientFor(command);
|
|
157
|
-
for (const
|
|
158
|
-
|
|
146
|
+
for (const frameId of frameIds) {
|
|
147
|
+
const id = designIdSchema.parse(frameId);
|
|
148
|
+
const result = await client.frame.screenshot({ project, frame: id });
|
|
149
|
+
console.log(`${id}\t${result.url}`);
|
|
150
|
+
}
|
|
159
151
|
});
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
.
|
|
163
|
-
.
|
|
164
|
-
.
|
|
165
|
-
.action(async (targetValue, _options, command) => {
|
|
152
|
+
program
|
|
153
|
+
.command("ls")
|
|
154
|
+
.description("List paths in the selected project filesystem")
|
|
155
|
+
.argument("[path]", "Absolute directory path", "/")
|
|
156
|
+
.action(async (path, _options, command) => {
|
|
166
157
|
const client = await clientFor(command);
|
|
167
|
-
const result = await client.
|
|
168
|
-
|
|
169
|
-
|
|
158
|
+
const result = await client.filesystem.list({
|
|
159
|
+
project: projectId(command),
|
|
160
|
+
path,
|
|
161
|
+
});
|
|
162
|
+
for (const item of result.paths)
|
|
163
|
+
console.log(item);
|
|
170
164
|
});
|
|
171
|
-
|
|
165
|
+
program
|
|
172
166
|
.command("read")
|
|
173
|
-
.description("Read
|
|
174
|
-
.argument("<
|
|
175
|
-
.
|
|
176
|
-
.action(async (targetValue, path, _options, command) => {
|
|
167
|
+
.description("Read a project file")
|
|
168
|
+
.argument("<path>", "Absolute project path")
|
|
169
|
+
.action(async (path, _options, command) => {
|
|
177
170
|
const client = await clientFor(command);
|
|
178
|
-
const
|
|
179
|
-
|
|
171
|
+
const file = await client.filesystem.read({
|
|
172
|
+
project: projectId(command),
|
|
180
173
|
path,
|
|
181
174
|
});
|
|
182
|
-
|
|
175
|
+
if (file.type === "text") {
|
|
176
|
+
process.stdout.write(file.text);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
console.log(file.url);
|
|
183
180
|
});
|
|
184
|
-
|
|
181
|
+
program
|
|
185
182
|
.command("write")
|
|
186
|
-
.description("Create or
|
|
187
|
-
.argument("<
|
|
188
|
-
.argument("
|
|
189
|
-
.
|
|
190
|
-
.action(async (targetValue, path, codeValue, _options, command) => {
|
|
191
|
-
const code = codeValue === undefined || codeValue === "-"
|
|
192
|
-
? await readStdin()
|
|
193
|
-
: codeValue;
|
|
183
|
+
.description("Create or overwrite a text project file")
|
|
184
|
+
.argument("<path>", "Absolute project path")
|
|
185
|
+
.argument("[text]", "Inline text; omit or use - to read stdin")
|
|
186
|
+
.action(async (path, text, _options, command) => {
|
|
194
187
|
const client = await clientFor(command);
|
|
195
|
-
await client.
|
|
196
|
-
|
|
188
|
+
await client.filesystem.write({
|
|
189
|
+
project: projectId(command),
|
|
197
190
|
path,
|
|
198
|
-
|
|
191
|
+
text: text === undefined || text === "-" ? await readStdin() : text,
|
|
199
192
|
});
|
|
200
193
|
console.log(`Wrote ${path}.`);
|
|
201
194
|
});
|
|
202
|
-
|
|
195
|
+
program
|
|
203
196
|
.command("edit")
|
|
204
|
-
.description("Replace text that occurs exactly once in
|
|
205
|
-
.argument("<
|
|
206
|
-
.argument("<path>", "Absolute source path")
|
|
197
|
+
.description("Replace text that occurs exactly once in a project file")
|
|
198
|
+
.argument("<path>", "Absolute project path")
|
|
207
199
|
.argument("<old-text>", "Text that must occur exactly once")
|
|
208
200
|
.argument("<new-text>", "Replacement text")
|
|
209
|
-
.action(async (
|
|
201
|
+
.action(async (path, oldText, newText, _options, command) => {
|
|
210
202
|
const client = await clientFor(command);
|
|
211
|
-
await client.
|
|
212
|
-
|
|
203
|
+
await client.filesystem.edit({
|
|
204
|
+
project: projectId(command),
|
|
213
205
|
path,
|
|
214
206
|
oldText,
|
|
215
207
|
newText,
|
|
216
208
|
});
|
|
217
209
|
console.log(`Edited ${path}.`);
|
|
218
210
|
});
|
|
219
|
-
|
|
220
|
-
.command("replace")
|
|
221
|
-
.description("Replace all source files from a Record<path, code> JSON object")
|
|
222
|
-
.argument("<target>", "Project and frame as <project>/<frame>")
|
|
223
|
-
.argument("[files]", "Inline JSON, or omit/use - to read stdin")
|
|
224
|
-
.action(async (targetValue, filesValue, _options, command) => {
|
|
225
|
-
const input = filesValue === undefined || filesValue === "-"
|
|
226
|
-
? await readStdin()
|
|
227
|
-
: filesValue;
|
|
228
|
-
const client = await clientFor(command);
|
|
229
|
-
await client.frame.source.replace({
|
|
230
|
-
...parseFrameTarget(targetValue),
|
|
231
|
-
files: parseSourceFiles(input),
|
|
232
|
-
});
|
|
233
|
-
console.log("Replaced source.");
|
|
234
|
-
});
|
|
235
|
-
source
|
|
211
|
+
program
|
|
236
212
|
.command("delete")
|
|
237
|
-
.description("Delete
|
|
238
|
-
.argument("<
|
|
239
|
-
.argument("<paths...>", "Absolute paths, or quoted *")
|
|
213
|
+
.description("Delete a project file")
|
|
214
|
+
.argument("<path>", "Absolute project path")
|
|
240
215
|
.option("-y, --yes", "Confirm deletion", false)
|
|
241
|
-
.action(async (
|
|
216
|
+
.action(async (path, options, command) => {
|
|
242
217
|
requireConfirmation(options.yes);
|
|
243
218
|
const client = await clientFor(command);
|
|
244
|
-
await client.
|
|
245
|
-
|
|
246
|
-
paths,
|
|
247
|
-
});
|
|
248
|
-
console.log("Deleted source.");
|
|
219
|
+
await client.filesystem.delete({ project: projectId(command), path });
|
|
220
|
+
console.log(`Deleted ${path}.`);
|
|
249
221
|
});
|
|
250
222
|
if (process.argv.length <= 2) {
|
|
251
223
|
program.outputHelp();
|
|
@@ -256,6 +228,49 @@ else {
|
|
|
256
228
|
process.exitCode = 1;
|
|
257
229
|
});
|
|
258
230
|
}
|
|
231
|
+
async function createFrameInput(project, name, options) {
|
|
232
|
+
if (options.type === "glts") {
|
|
233
|
+
if (options.image !== undefined || options.asset !== undefined) {
|
|
234
|
+
throw new Error("GLTS frames do not accept --image or --asset");
|
|
235
|
+
}
|
|
236
|
+
if (options.size === undefined) {
|
|
237
|
+
throw new Error("GLTS frames require --size <width>x<height>");
|
|
238
|
+
}
|
|
239
|
+
return {
|
|
240
|
+
project,
|
|
241
|
+
name,
|
|
242
|
+
type: "glts",
|
|
243
|
+
...parseFrameSize(options.size),
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
if (options.type === "image") {
|
|
247
|
+
if (options.size !== undefined || options.asset !== undefined) {
|
|
248
|
+
throw new Error("Image frames do not accept --size or --asset");
|
|
249
|
+
}
|
|
250
|
+
if (options.image === undefined)
|
|
251
|
+
throw new Error("Image frames require --image");
|
|
252
|
+
return {
|
|
253
|
+
project,
|
|
254
|
+
name,
|
|
255
|
+
type: "image",
|
|
256
|
+
image: await readImageInput(options.image),
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
if (options.type === "market") {
|
|
260
|
+
if (options.size !== undefined || options.image !== undefined) {
|
|
261
|
+
throw new Error("Market frames do not accept --size or --image");
|
|
262
|
+
}
|
|
263
|
+
if (options.asset === undefined)
|
|
264
|
+
throw new Error("Market frames require --asset");
|
|
265
|
+
return {
|
|
266
|
+
project,
|
|
267
|
+
name,
|
|
268
|
+
type: "market",
|
|
269
|
+
asset: marketAssetSchema.parse(options.asset),
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
throw new Error("--type must be glts, image, or market");
|
|
273
|
+
}
|
|
259
274
|
async function clientFor(command) {
|
|
260
275
|
return getCliClient(apiOption(command));
|
|
261
276
|
}
|
|
@@ -263,15 +278,17 @@ function apiOption(command) {
|
|
|
263
278
|
const value = command.optsWithGlobals().api;
|
|
264
279
|
return typeof value === "string" ? value : undefined;
|
|
265
280
|
}
|
|
281
|
+
function projectId(command) {
|
|
282
|
+
const value = command.optsWithGlobals().project;
|
|
283
|
+
if (typeof value !== "string") {
|
|
284
|
+
throw new Error("Select a project with -p, --project <project-id>.");
|
|
285
|
+
}
|
|
286
|
+
return designIdSchema.parse(value);
|
|
287
|
+
}
|
|
266
288
|
function requireConfirmation(confirmed) {
|
|
267
289
|
if (!confirmed)
|
|
268
290
|
throw new Error("Destructive commands require --yes.");
|
|
269
291
|
}
|
|
270
|
-
async function optionalIndexSource(value) {
|
|
271
|
-
if (value === undefined)
|
|
272
|
-
return undefined;
|
|
273
|
-
return value === "-" ? readStdin() : value;
|
|
274
|
-
}
|
|
275
292
|
async function readStdin() {
|
|
276
293
|
const chunks = [];
|
|
277
294
|
for await (const chunk of process.stdin) {
|
|
@@ -279,22 +296,6 @@ async function readStdin() {
|
|
|
279
296
|
}
|
|
280
297
|
return Buffer.concat(chunks).toString("utf8");
|
|
281
298
|
}
|
|
282
|
-
async function screenshotTarget(client, value) {
|
|
283
|
-
const target = parseScreenshotTarget(value);
|
|
284
|
-
if (target.frame) {
|
|
285
|
-
const result = await client.frame.screenshot(target);
|
|
286
|
-
console.log(`${value}\t${result.url}`);
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
const frames = await client.frame.list({ project: target.project });
|
|
290
|
-
for (const item of frames) {
|
|
291
|
-
const result = await client.frame.screenshot({
|
|
292
|
-
project: target.project,
|
|
293
|
-
frame: item.name,
|
|
294
|
-
});
|
|
295
|
-
console.log(`${target.project}/${item.name}\t${result.url}`);
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
299
|
function readPackageVersion() {
|
|
299
300
|
const manifest = createRequire(import.meta.url)("../package.json");
|
|
300
301
|
if (!manifest ||
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export * as v1 from "./v1/index.js";
|
|
2
2
|
export { designSkill } from "./skill.generated.js";
|
|
3
|
-
export {
|
|
4
|
-
export { parseFrameSize, parseFrameTarget, parseScreenshotTarget, parseSourceFiles, type FrameTarget, type ScreenshotTarget, } from "./target.js";
|
|
3
|
+
export { parseFrameSize } from "./target.js";
|
|
5
4
|
export { acknowledgesInspection, inspectionCommandSchema, inspectionFrameMessageSchema, inspectionMessageTypes, projectSyncUrl, type InspectionAppliedMessage, type InspectionCommand, type InspectionFrameMessage, } from "./protocol.js";
|
|
6
|
-
export type {
|
|
5
|
+
export type { BinaryFile, CreateFrame, CreateGltsFrame, CreateImageFrame, CreateMarketFrame, DesignFile, FileList, FileMutation, Frame, GltsFrame, ImageFrame, MarketFrame, Project, Screenshot, TextFile, User, } from "./v1/schemas.js";
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export * as v1 from "./v1/index.js";
|
|
2
2
|
export { designSkill } from "./skill.generated.js";
|
|
3
|
-
export {
|
|
4
|
-
export { parseFrameSize, parseFrameTarget, parseScreenshotTarget, parseSourceFiles, } from "./target.js";
|
|
3
|
+
export { parseFrameSize } from "./target.js";
|
|
5
4
|
export { acknowledgesInspection, inspectionCommandSchema, inspectionFrameMessageSchema, inspectionMessageTypes, projectSyncUrl, } from "./protocol.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const designSkill = "---\nname: drawcall-design\ndescription: Create, modify, inspect, and screenshot 3D
|
|
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\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";
|
package/dist/skill.generated.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated from skills/drawcall-design/SKILL.md.
|
|
2
|
-
export const designSkill = '---\nname: drawcall-design\ndescription: Create, modify, inspect, and screenshot 3D
|
|
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\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';
|
package/dist/target.d.ts
CHANGED
|
@@ -1,18 +1,4 @@
|
|
|
1
|
-
export interface FrameTarget {
|
|
2
|
-
project: string;
|
|
3
|
-
frame: string;
|
|
4
|
-
}
|
|
5
|
-
export type ScreenshotTarget = {
|
|
6
|
-
project: string;
|
|
7
|
-
frame?: never;
|
|
8
|
-
} | {
|
|
9
|
-
project: string;
|
|
10
|
-
frame: string;
|
|
11
|
-
};
|
|
12
|
-
export declare function parseFrameTarget(value: string): FrameTarget;
|
|
13
|
-
export declare function parseScreenshotTarget(value: string): ScreenshotTarget;
|
|
14
1
|
export declare function parseFrameSize(value: string): {
|
|
15
2
|
width: number;
|
|
16
3
|
height: number;
|
|
17
4
|
};
|
|
18
|
-
export declare function parseSourceFiles(value: string): Record<string, string>;
|
package/dist/target.js
CHANGED
|
@@ -1,22 +1,3 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { frameNameSchema, projectNameSchema, sourceFilesSchema, } from "./v1/schemas.js";
|
|
3
|
-
export function parseFrameTarget(value) {
|
|
4
|
-
const segments = value.split("/");
|
|
5
|
-
const project = segments[0];
|
|
6
|
-
const frame = segments[1];
|
|
7
|
-
if (segments.length !== 2 || project === undefined || frame === undefined) {
|
|
8
|
-
throw new Error(`Expected <project>/<frame>, received ${JSON.stringify(value)}`);
|
|
9
|
-
}
|
|
10
|
-
return {
|
|
11
|
-
project: projectNameSchema.parse(project),
|
|
12
|
-
frame: frameNameSchema.parse(frame),
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
export function parseScreenshotTarget(value) {
|
|
16
|
-
if (value.includes("/"))
|
|
17
|
-
return parseFrameTarget(value);
|
|
18
|
-
return { project: projectNameSchema.parse(value) };
|
|
19
|
-
}
|
|
20
1
|
export function parseFrameSize(value) {
|
|
21
2
|
const match = /^(\d+)[x×](\d+)$/i.exec(value);
|
|
22
3
|
const widthText = match?.[1];
|
|
@@ -34,7 +15,3 @@ export function parseFrameSize(value) {
|
|
|
34
15
|
}
|
|
35
16
|
return { width, height };
|
|
36
17
|
}
|
|
37
|
-
export function parseSourceFiles(value) {
|
|
38
|
-
const parsed = JSON.parse(value);
|
|
39
|
-
return sourceFilesSchema.parse(parsed);
|
|
40
|
-
}
|