@drawcall/design 0.9.1 → 0.10.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 CHANGED
@@ -10,7 +10,7 @@ const projects = await design.project.list();
10
10
  ```
11
11
 
12
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
- The current rendered image for any GLTS, image, or Market frame is available at
13
+ The current rendered image for any GLTS, Markdown, image, or Market frame is available at
14
14
  `https://<project-id>.design.drawcallcontent.com/<frame-id>.webp`.
15
15
 
16
16
  ```sh
@@ -28,6 +28,11 @@ npx drawcall design -p r6z2n9k4x8m1qc ls /
28
28
  npx drawcall design -p r6z2n9k4x8m1qc read /a4z8m2q7v9kcde/index.glts
29
29
  npx drawcall design -p r6z2n9k4x8m1qc frame screenshot a4z8m2q7v9kcde
30
30
 
31
+ npx drawcall design -p r6z2n9k4x8m1qc frame create release-notes \
32
+ --type markdown --size 720x900
33
+ npx drawcall design -p r6z2n9k4x8m1qc write /b4z8m2q7v9kcdf/index.md \
34
+ $'# Release notes\n\n![Racecar](/a4z8m2q7v9kcde.webp)'
35
+
31
36
  npx drawcall design -p r6z2n9k4x8m1qc frame create reference \
32
37
  --type image --image ./reference.png
33
38
  npx drawcall design -p r6z2n9k4x8m1qc frame create oak-chair \
@@ -66,9 +71,11 @@ registerDesignTools(server, client);
66
71
  ```
67
72
 
68
73
  Image generation accepts public HTTP(S) reference URLs. Use a frame's canonical
69
- WebP URL to reference a GLTS, image, or Market frame.
74
+ WebP URL to reference a GLTS, Markdown, image, or Market frame.
70
75
 
71
76
  The host owns the server identity, authentication, and transport. The MCP SDK
72
77
  is an optional peer dependency and is required only when mounting these tools.
73
78
 
74
- GLTS frames accept only `.glts` files. An absent `index.glts` still renders an intentionally empty frame. For authored scenes, work top-down: write `index.glts`, reference planned child assets, then implement those children progressively. A missing imported `.glts` path renders a labeled glowing placeholder without creating a stored file; writing the real file replaces it on revalidation. Image and Market files are available through the same filesystem but are read-only. Read `npx drawcall design skill` (or MCP `get_design_instructions`) before creating or changing a GLTS asset.
79
+ GLTS frames accept only `.glts` files. An absent `index.glts` still renders an intentionally empty frame. For authored scenes, work top-down: write `index.glts`, reference planned child assets, then implement those children progressively. A missing imported `.glts` path renders a labeled glowing placeholder without creating a stored file; writing the real file replaces it on revalidation.
80
+
81
+ Markdown frames accept only `index.md`; an absent source renders an empty document. Embed an existing non-Markdown frame with standard image syntax such as `![Racecar](/a4z8m2q7v9kcde.webp)`. Raw HTML is disabled, Markdown frames cannot embed other Markdown frames, and each document is limited to 32 frame embeds. Image and Market files are available through the same filesystem but are read-only. Read `npx drawcall design skill` (or MCP `get_design_instructions`) before creating or changing a GLTS or Markdown frame.
package/dist/browser.d.ts CHANGED
@@ -3,8 +3,8 @@ export { frameImageUrl } from "./frame-image.js";
3
3
  export { registerDesignTools, type DesignMcpOptions, type DesignMcpServer, type DesignMcpToolResult, } from "./mcp/index.js";
4
4
  export { cliDesignSkill, mcpDesignSkill } from "./skill.generated.js";
5
5
  export { frameCreationCapabilities, type FrameCreationCapability, type FrameCreationCapabilityId, type FrameCreationInput, } from "./v1/capabilities.js";
6
- export { cameraPoseSchema, IMAGE_GENERATION_MODEL, IMAGE_GENERATION_PROVIDER, } from "./v1/schemas.js";
6
+ export { cameraPoseSchema, commentBodySchema, commentPositionInputSchema, commentPositionSchema, commentSchema, createCommentSchema, IMAGE_GENERATION_MODEL, IMAGE_GENERATION_PROVIDER, } from "./v1/schemas.js";
7
7
  export { parseFrameSize } from "./target.js";
8
- 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";
9
- export { cameraCaptureCommandSchema, cameraCaptureResultSchema, cameraMessageTypes, cameraSetCommandSchema, gltsExportCancelCommandSchema, gltsExportCancelledResultSchema, gltsExportCommandSchema, gltsExportFrameMessageSchema, gltsExportMessageTypes, gltsExportParentMessageSchema, gltsExportResultSchema, gltsRuntimeExportFormatSchema, immersiveCommandSchema, immersiveFrameMessageSchema, immersiveMessageTypes, immersiveModeSchema, inspectionCommandSchema, inspectionFrameMessageSchema, inspectionMessageTypes, posterMessageTypes, posterPagePath, posterPageUrl, posterRenderCommandSchema, posterRenderResultSchema, projectSyncUrl, sourceFileChangeSchema, sourceFileMessageTypes, sourceFileReloadResultSchema, sourceFilesChangedMessageSchema, type GltsExportCancelCommand, type GltsExportCancelledResult, type GltsExportCommand, type GltsExportFrameMessage, type GltsExportParentMessage, type GltsExportResult, type GltsRuntimeExportFormat, type CameraCaptureCommand, type CameraSetCommand, type CameraCaptureFailure, type CameraCaptureResult, type InspectionAppliedMessage, type InspectionCommand, type InspectionFrameMessage, type PosterRenderCommand, type PosterRenderResult, type ImmersiveCommand, type ImmersiveFrameMessage, type ImmersiveMode, type SourceFileChange, type SourceFileReloadResult, type SourceFilesChangedMessage, } from "./protocol.js";
10
- export type { BinaryFile, CameraPose, CreateFrame, CreateProjectFromBrief, CreateGltsFrame, CreateImageFrame, CreateMarketFrame, GenerateImage, GenerateImageUrl, DesignFile, FileList, FileMutation, FrameExport, Frame, GltsFrame, GltsFrameExport, ImageFrame, ImageFrameExport, ImageGenerationOperation, ImageGenerationProvenance, ImageGenerationResult, ImageInput, ImageInputProvenance, MarketFrame, MarketFrameExport, Project, ProjectDerivationStatus, Screenshot, TextFile, User, } from "./v1/schemas.js";
8
+ export { projectFrameLayoutSchema, projectCommentsChangedServerMessageSchema, projectFrameRecordSchema, projectGltsFrameRecordSchema, projectImageFrameRecordSchema, projectMarkdownFrameRecordSchema, projectMarketFileSchema, projectMarketFrameRecordSchema, projectPresenceClientMessageSchema, projectPresenceServerMessageSchema, projectStateSchema, type ProjectFrameLayout, type ProjectCommentsChangedServerMessage, type ProjectFrameRecord, type ProjectGltsFrameRecord, type ProjectImageFrameRecord, type ProjectMarkdownFrameRecord, type ProjectMarketFile, type ProjectMarketFrameRecord, type ProjectPresenceClientMessage, type ProjectPresenceServerMessage, type ProjectState, } from "./project-state.js";
9
+ export { cameraCaptureCommandSchema, cameraCaptureResultSchema, cameraMessageTypes, cameraSetCommandSchema, commentActionMessageSchema, commentActionResultSchema, commentPickCommandSchema, commentPickResultSchema, commentRuntimeMessageTypes, commentSelectionMessageSchema, commentStateCommandSchema, frameRenderResultSchema, gltsExportCancelCommandSchema, gltsExportCancelledResultSchema, gltsExportCommandSchema, gltsExportFrameMessageSchema, gltsExportMessageTypes, gltsExportParentMessageSchema, gltsExportResultSchema, gltsRuntimeExportFormatSchema, immersiveCommandSchema, immersiveFrameMessageSchema, immersiveMessageTypes, immersiveModeSchema, inspectionCommandSchema, inspectionFrameMessageSchema, inspectionMessageTypes, posterMessageTypes, posterPagePath, posterPageUrl, posterRenderCommandSchema, posterRenderResultSchema, previewConfigureCommandSchema, previewLoadCommandSchema, previewLoadResultSchema, previewMessageTypes, previewPagePath, previewPageUrl, previewPixelRatioMax, previewSessionEventSchema, projectSyncUrl, sourceFileChangeSchema, sourceFileMessageTypes, sourceFileReloadResultSchema, sourceFilesChangedMessageSchema, type GltsExportCancelCommand, type GltsExportCancelledResult, type GltsExportCommand, type GltsExportFrameMessage, type GltsExportParentMessage, type GltsExportResult, type GltsRuntimeExportFormat, type CameraCaptureCommand, type CameraSetCommand, type CameraCaptureFailure, type CameraCaptureResult, type CommentActionMessage, type CommentActionResult, type CommentPickCommand, type CommentPickResult, type CommentSelectionMessage, type CommentStateCommand, type FrameRenderResult, type InspectionAppliedMessage, type InspectionCommand, type InspectionFrameMessage, type PosterRenderCommand, type PosterRenderResult, type PreviewLoadCommand, type PreviewLoadResult, type ImmersiveCommand, type ImmersiveFrameMessage, type ImmersiveMode, type SourceFileChange, type SourceFileReloadResult, type SourceFilesChangedMessage, } from "./protocol.js";
10
+ export type { BinaryFile, CameraPose, Comment, CommentAuthor, CommentPosition, CommentPositionInput, CommentReply, CommentResolution, CreateComment, CreateFrame, CreateProjectFromBrief, CreateGltsFrame, CreateImageFrame, CreateMarkdownFrame, CreateMarketFrame, GenerateImage, GenerateImageUrl, DesignFile, FileList, FileMutation, FrameExport, Frame, GltsFrame, GltsFrameExport, ImageFrame, ImageFrameExport, ImageGenerationOperation, ImageGenerationProvenance, ImageGenerationResult, ImageInput, ImageInputProvenance, MarketFrame, MarketFrameExport, MarkdownFrame, MarkdownFrameExport, Project, ProjectDerivationStatus, Screenshot, TextFile, User, } from "./v1/schemas.js";
package/dist/browser.js CHANGED
@@ -3,7 +3,7 @@ export { frameImageUrl } from "./frame-image.js";
3
3
  export { registerDesignTools, } from "./mcp/index.js";
4
4
  export { cliDesignSkill, mcpDesignSkill } from "./skill.generated.js";
5
5
  export { frameCreationCapabilities, } from "./v1/capabilities.js";
6
- export { cameraPoseSchema, IMAGE_GENERATION_MODEL, IMAGE_GENERATION_PROVIDER, } from "./v1/schemas.js";
6
+ export { cameraPoseSchema, commentBodySchema, commentPositionInputSchema, commentPositionSchema, commentSchema, createCommentSchema, IMAGE_GENERATION_MODEL, IMAGE_GENERATION_PROVIDER, } from "./v1/schemas.js";
7
7
  export { parseFrameSize } from "./target.js";
8
- export { projectFrameLayoutSchema, projectFrameRecordSchema, projectGltsFrameRecordSchema, projectImageFrameRecordSchema, projectMarketFileSchema, projectMarketFrameRecordSchema, projectPresenceClientMessageSchema, projectPresenceServerMessageSchema, projectStateSchema, } from "./project-state.js";
9
- export { cameraCaptureCommandSchema, cameraCaptureResultSchema, cameraMessageTypes, cameraSetCommandSchema, gltsExportCancelCommandSchema, gltsExportCancelledResultSchema, gltsExportCommandSchema, gltsExportFrameMessageSchema, gltsExportMessageTypes, gltsExportParentMessageSchema, gltsExportResultSchema, gltsRuntimeExportFormatSchema, immersiveCommandSchema, immersiveFrameMessageSchema, immersiveMessageTypes, immersiveModeSchema, inspectionCommandSchema, inspectionFrameMessageSchema, inspectionMessageTypes, posterMessageTypes, posterPagePath, posterPageUrl, posterRenderCommandSchema, posterRenderResultSchema, projectSyncUrl, sourceFileChangeSchema, sourceFileMessageTypes, sourceFileReloadResultSchema, sourceFilesChangedMessageSchema, } from "./protocol.js";
8
+ export { projectFrameLayoutSchema, projectCommentsChangedServerMessageSchema, projectFrameRecordSchema, projectGltsFrameRecordSchema, projectImageFrameRecordSchema, projectMarkdownFrameRecordSchema, projectMarketFileSchema, projectMarketFrameRecordSchema, projectPresenceClientMessageSchema, projectPresenceServerMessageSchema, projectStateSchema, } from "./project-state.js";
9
+ export { cameraCaptureCommandSchema, cameraCaptureResultSchema, cameraMessageTypes, cameraSetCommandSchema, commentActionMessageSchema, commentActionResultSchema, commentPickCommandSchema, commentPickResultSchema, commentRuntimeMessageTypes, commentSelectionMessageSchema, commentStateCommandSchema, frameRenderResultSchema, gltsExportCancelCommandSchema, gltsExportCancelledResultSchema, gltsExportCommandSchema, gltsExportFrameMessageSchema, gltsExportMessageTypes, gltsExportParentMessageSchema, gltsExportResultSchema, gltsRuntimeExportFormatSchema, immersiveCommandSchema, immersiveFrameMessageSchema, immersiveMessageTypes, immersiveModeSchema, inspectionCommandSchema, inspectionFrameMessageSchema, inspectionMessageTypes, posterMessageTypes, posterPagePath, posterPageUrl, posterRenderCommandSchema, posterRenderResultSchema, previewConfigureCommandSchema, previewLoadCommandSchema, previewLoadResultSchema, previewMessageTypes, previewPagePath, previewPageUrl, previewPixelRatioMax, previewSessionEventSchema, projectSyncUrl, sourceFileChangeSchema, sourceFileMessageTypes, sourceFileReloadResultSchema, sourceFilesChangedMessageSchema, } from "./protocol.js";
@@ -0,0 +1,2 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerCommentCommands(program: Command): void;
@@ -0,0 +1,142 @@
1
+ import { designIdSchema, } from "../v1/schemas.js";
2
+ import { clientFor, projectId, requireConfirmation } from "./context.js";
3
+ import { textArgument } from "./input.js";
4
+ export function registerCommentCommands(program) {
5
+ const comment = program.command("comment").description("Manage comments");
6
+ comment
7
+ .command("list")
8
+ .description("List comments, optionally for one frame")
9
+ .argument("[frame-id]", "Frame ID")
10
+ .action(async (frameId, _options, command) => {
11
+ const client = await clientFor(command);
12
+ const comments = await client.comment.list({
13
+ project: projectId(command),
14
+ ...(frameId ? { frame: designIdSchema.parse(frameId) } : {}),
15
+ });
16
+ for (const item of comments)
17
+ console.log(commentLine(item));
18
+ });
19
+ comment
20
+ .command("show")
21
+ .description("Show a comment and its replies")
22
+ .argument("<comment-id>", "Comment ID")
23
+ .action(async (commentId, _options, command) => {
24
+ const client = await clientFor(command);
25
+ const result = await client.comment.get({
26
+ project: projectId(command),
27
+ comment: designIdSchema.parse(commentId),
28
+ });
29
+ console.log(JSON.stringify(result, null, 2));
30
+ });
31
+ comment
32
+ .command("create")
33
+ .description("Create a frame or positioned comment")
34
+ .argument("<frame-id>", "Frame ID")
35
+ .argument("[text]", "Inline text; omit or use - to read stdin")
36
+ .option("--position-2d <x,y>", "Normalized position in an image frame")
37
+ .option("--position-3d <x,y,z>", "World position in a GLTS frame")
38
+ .action(async (frameId, text, options, command) => {
39
+ const client = await clientFor(command);
40
+ const project = projectId(command);
41
+ const frame = designIdSchema.parse(frameId);
42
+ const position = commentPosition(options);
43
+ const body = await textArgument(text);
44
+ const created = await client.comment.create(position
45
+ ? {
46
+ project,
47
+ frame,
48
+ body,
49
+ position,
50
+ expectedContentRevision: await commentPositionRevision(client, project, frame, position.kind),
51
+ }
52
+ : { project, frame, body });
53
+ console.log(`Created ${created.id}.`);
54
+ });
55
+ comment
56
+ .command("reply")
57
+ .description("Reply to a comment")
58
+ .argument("<comment-id>", "Comment ID")
59
+ .argument("[text]", "Inline text; omit or use - to read stdin")
60
+ .action(async (commentId, text, _options, command) => {
61
+ const client = await clientFor(command);
62
+ const updated = await client.comment.reply({
63
+ project: projectId(command),
64
+ comment: designIdSchema.parse(commentId),
65
+ body: await textArgument(text),
66
+ });
67
+ console.log(`Replied to ${updated.id}.`);
68
+ });
69
+ registerResolutionCommand(comment, "resolve", true);
70
+ registerResolutionCommand(comment, "reopen", false);
71
+ comment
72
+ .command("delete")
73
+ .description("Delete a comment or reply")
74
+ .argument("<comment-id>", "Comment or reply ID")
75
+ .option("-y, --yes", "Confirm deletion", false)
76
+ .action(async (commentId, options, command) => {
77
+ requireConfirmation(options.yes);
78
+ const client = await clientFor(command);
79
+ const deleted = await client.comment.delete({
80
+ project: projectId(command),
81
+ comment: designIdSchema.parse(commentId),
82
+ });
83
+ console.log(`Deleted ${deleted.id}.`);
84
+ });
85
+ }
86
+ function registerResolutionCommand(comment, name, resolved) {
87
+ comment
88
+ .command(name)
89
+ .description(`${resolved ? "Resolve" : "Reopen"} a comment`)
90
+ .argument("<comment-id>", "Comment ID")
91
+ .action(async (commentId, _options, command) => {
92
+ const client = await clientFor(command);
93
+ const updated = await client.comment.setResolved({
94
+ project: projectId(command),
95
+ comment: designIdSchema.parse(commentId),
96
+ resolved,
97
+ });
98
+ console.log(`${resolved ? "Resolved" : "Reopened"} ${updated.id}.`);
99
+ });
100
+ }
101
+ function commentPosition(options) {
102
+ if (options.position2d && options.position3d) {
103
+ throw new Error("Choose at most one of --position-2d or --position-3d.");
104
+ }
105
+ if (options.position2d) {
106
+ const [x, y] = coordinates(options.position2d, 2);
107
+ return { kind: "2d", x, y };
108
+ }
109
+ if (options.position3d) {
110
+ const [x, y, z] = coordinates(options.position3d, 3);
111
+ return { kind: "3d", x, y, z };
112
+ }
113
+ }
114
+ function coordinates(value, count) {
115
+ const parts = value.split(",");
116
+ const coordinates = parts.map(Number);
117
+ if (coordinates.length !== count ||
118
+ parts.some((part) => part.trim() === "") ||
119
+ coordinates.some((coordinate) => !Number.isFinite(coordinate))) {
120
+ throw new Error(`Position must contain ${count} comma-separated numbers.`);
121
+ }
122
+ return coordinates;
123
+ }
124
+ async function commentPositionRevision(client, project, frame, position) {
125
+ const target = (await client.frame.list({ project })).find((candidate) => candidate.id === frame);
126
+ if (!target)
127
+ throw new Error(`Frame ${frame} does not exist.`);
128
+ if ((position === "2d" && target.type !== "image") ||
129
+ (position === "3d" && target.type !== "glts")) {
130
+ throw new Error(`${target.type} frames do not support ${position.toUpperCase()} comment positions.`);
131
+ }
132
+ if (target.contentRevision === undefined) {
133
+ throw new Error(`Frame ${frame} has no content revision.`);
134
+ }
135
+ return target.contentRevision;
136
+ }
137
+ function commentLine(comment) {
138
+ const status = comment.resolution ? "resolved" : "open";
139
+ const position = comment.position?.kind ?? "frame";
140
+ const body = comment.body.replace(/\s+/gu, " ");
141
+ return `${comment.id}\t${comment.frameId}\t${position}\t${status}\t${comment.author.name}\t${body}`;
142
+ }