@drawcall/design 0.12.6 → 0.13.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 +2 -2
- package/dist/mcp/file.js +2 -2
- package/dist/mcp/schema.js +1 -1
- package/dist/skill.generated.d.ts +2 -2
- package/dist/skill.generated.js +2 -2
- package/package.json +1 -1
- package/skills/drawcall-design/SKILL.md +107 -61
package/README.md
CHANGED
|
@@ -21,12 +21,12 @@ npx drawcall design project create showroom
|
|
|
21
21
|
npx drawcall design -p r6z2n9k4x8m1qc frame create racecar \
|
|
22
22
|
--type glts --size 800x800 \
|
|
23
23
|
--import ./parts/wheel.glts=-0.5,0,-0.5:0.5,1,0.5 \
|
|
24
|
-
--text 'import
|
|
24
|
+
--text 'import { gltsLoader, scene } from "@drawcall/glts"; const wheel = await gltsLoader.loadAsync(new URL("./parts/wheel.glts", import.meta.url)); scene.add(wheel)'
|
|
25
25
|
# `frame create` prints its frame ID and /<frame-id>/ path. `--text -` reads stdin.
|
|
26
26
|
# Each `--import` box becomes a placeholder file until the real part is written.
|
|
27
27
|
|
|
28
28
|
npx drawcall design -p r6z2n9k4x8m1qc write /a4z8m2q7v9kcde/parts/wheel.glts \
|
|
29
|
-
'import * as THREE from "three";
|
|
29
|
+
'import * as THREE from "three"; import { scene } from "@drawcall/glts"; scene.add(new THREE.Mesh(new THREE.TorusGeometry(), new THREE.MeshStandardMaterial()))'
|
|
30
30
|
npx drawcall design -p r6z2n9k4x8m1qc ls /
|
|
31
31
|
npx drawcall design -p r6z2n9k4x8m1qc read /a4z8m2q7v9kcde/index.glts
|
|
32
32
|
npx drawcall design -p r6z2n9k4x8m1qc frame preview a4z8m2q7v9kcde
|
package/dist/mcp/file.js
CHANGED
|
@@ -34,7 +34,7 @@ export function registerFileTools(server, client) {
|
|
|
34
34
|
});
|
|
35
35
|
server.registerTool("write_design_file", {
|
|
36
36
|
title: "Write Design file",
|
|
37
|
-
description: "Create or replace one .glts or .md file at a canonical project-absolute path. Every .glts file it
|
|
37
|
+
description: "Create or replace one .glts or .md file at a canonical project-absolute path. Every .glts file it loads through the contextual gltsLoader must exist or be given a bounding box in imports, which creates a placeholder file to replace later. The path includes the frame ID; this tool does not accept a frame argument.",
|
|
38
38
|
inputSchema: fileInput.extend({
|
|
39
39
|
text: fileTextSchema,
|
|
40
40
|
imports: importsInput.optional(),
|
|
@@ -52,7 +52,7 @@ export function registerFileTools(server, client) {
|
|
|
52
52
|
})));
|
|
53
53
|
server.registerTool("edit_design_file", {
|
|
54
54
|
title: "Edit Design file",
|
|
55
|
-
description: "Replace oldText when it occurs exactly once at a canonical project-absolute .glts or .md path. A newly
|
|
55
|
+
description: "Replace oldText when it occurs exactly once at a canonical project-absolute .glts or .md path. A newly loaded .glts file that does not exist needs a bounding box in imports. The path includes the frame ID; this tool does not accept a frame argument.",
|
|
56
56
|
inputSchema: fileInput.extend({
|
|
57
57
|
oldText: fileTextSchema.min(1),
|
|
58
58
|
newText: fileTextSchema,
|
package/dist/mcp/schema.js
CHANGED
|
@@ -8,7 +8,7 @@ const sizeSchema = z.coerce.number().int().min(1).max(MAX_FRAME_DIMENSION);
|
|
|
8
8
|
// Some MCP clients send nested arguments as JSON text.
|
|
9
9
|
export const importsInput = z
|
|
10
10
|
.preprocess(jsonArgument, importsSchema)
|
|
11
|
-
.describe('Bounding box of each
|
|
11
|
+
.describe('Bounding box of each contextually loaded .glts file that does not exist yet, keyed by its URL specifier as written, e.g. {"./parts/wheel.glts": {"min": [-1, 0, -2], "max": [1, 1, 2]}}; a placeholder file is created for each');
|
|
12
12
|
function jsonArgument(value) {
|
|
13
13
|
if (typeof value !== "string")
|
|
14
14
|
return value;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const mcpDesignSkill = "---\nname: drawcall-design\ndescription: Create, modify, inspect, compose, and reuse GLTS scenes, Markdown documents, and image or Market references in Drawcall Design. Use whenever the user names Drawcall Design or one of its projects, canvases, frames, filesystems, GLTS assets, or Markdown frames. 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 Drawcall transport in this environment. For Design operations, use only the tools documented here. A failed tool call does not make the transport unavailable.\n\nImage frame creation uses a public HTTP(S) image URL.\n\nUse `generate_design_image` only when the user asks for a 2D image or reference. Its references must be public HTTP(S) URLs. 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. `create_design_frame` takes the root file of a glts or markdown frame as `text`, and `create_design_frame`, `write_design_file`, and `edit_design_file` take `imports`, the bounding box of each imported `.glts` file that does not exist yet, keyed by the import specifier as written. The create result includes the new frame ID that later paths start with. File tools identify their target with `project` and a project-absolute `path`; they do not accept a separate `frame` argument. Call `list_design_files` and pass one of its returned paths unchanged.\n\nFor comments, call `list_design_comments` and, when needed, `get_design_comment` before changing a thread. Use `create_design_comment`, `reply_to_design_comment`, `resolve_design_comment`, `reopen_design_comment`, and `delete_design_comment` for their named operations. Structured tool calls use `body` for comment text. A positioned create requires the target frame's current `contentRevision` as `expectedContentRevision`; list frames again and re-inspect the position after a conflict.\n\n```json\n[\n {\n \"tool\": \"list_design_projects\",\n \"arguments\": {}\n },\n {\n \"tool\": \"list_design_frames\",\n \"arguments\": {\n \"project\": \"r6z2n9k4x8m1qc\"\n }\n },\n {\n \"tool\": \"create_design_frame\",\n \"arguments\": {\n \"project\": \"r6z2n9k4x8m1qc\",\n \"name\": \"Racecar\",\n \"type\": \"glts\",\n \"width\": 1280,\n \"height\": 800,\n \"text\": \"import * 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 \"imports\": {\n \"./parts/wheel.glts\": {\n \"min\": [\n -0.5,\n 0,\n -0.5\n ],\n \"max\": [\n 0.5,\n 1,\n 0.5\n ]\n }\n }\n }\n },\n {\n \"tool\": \"write_design_file\",\n \"arguments\": {\n \"project\": \"r6z2n9k4x8m1qc\",\n \"path\": \"/a4z8m2q7v9kcde/parts/wheel.glts\",\n \"text\": \"import * as THREE from \\\"three\\\";\\n\\nexport default class Wheel extends THREE.Mesh {\\n constructor() {\\n super(new THREE.TorusGeometry(0.4, 0.12, 16, 48), new THREE.MeshStandardMaterial({ color: 0x222222 }));\\n }\\n}\\n\"\n }\n },\n {\n \"tool\": \"list_design_files\",\n \"arguments\": {\n \"project\": \"r6z2n9k4x8m1qc\"\n }\n },\n {\n \"tool\": \"read_design_file\",\n \"arguments\": {\n \"project\": \"r6z2n9k4x8m1qc\",\n \"path\": \"/a4z8m2q7v9kcde/index.glts\"\n }\n },\n {\n \"tool\": \"edit_design_file\",\n \"arguments\": {\n \"project\": \"r6z2n9k4x8m1qc\",\n \"path\": \"/a4z8m2q7v9kcde/index.glts\",\n \"oldText\": \"color: 0xffffff\",\n \"newText\": \"color: 0x000000\"\n }\n },\n {\n \"tool\": \"create_design_comment\",\n \"arguments\": {\n \"project\": \"r6z2n9k4x8m1qc\",\n \"frame\": \"a4z8m2q7v9kcde\",\n \"body\": \"The bevel catches the key light here.\",\n \"position\": {\n \"kind\": \"3d\",\n \"x\": 0.2,\n \"y\": 1.1,\n \"z\": -0.4\n },\n \"expectedContentRevision\": 7\n }\n },\n {\n \"tool\": \"reply_to_design_comment\",\n \"arguments\": {\n \"project\": \"r6z2n9k4x8m1qc\",\n \"comment\": \"c4z8m2q7v9kcdf\",\n \"body\": \"Adjusted the material roughness.\"\n }\n },\n {\n \"tool\": \"resolve_design_comment\",\n \"arguments\": {\n \"project\": \"r6z2n9k4x8m1qc\",\n \"comment\": \"c4z8m2q7v9kcdf\"\n }\n },\n {\n \"tool\": \"generate_design_image\",\n \"arguments\": {\n \"project\": \"r6z2n9k4x8m1qc\",\n \"operation\": \"generate\",\n \"prompt\": \"A product photograph of this object\",\n \"references\": [\n \"https://r6z2n9k4x8m1qc.design.drawcallcontent.com/a4z8m2q7v9kcde.webp\"\n ],\n \"result\": \"new\",\n \"name\": \"Product photograph\"\n }\n },\n {\n \"tool\": \"get_design_frame_preview\",\n \"arguments\": {\n \"project\": \"r6z2n9k4x8m1qc\",\n \"frame\": \"a4z8m2q7v9kcde\"\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 mutable labels. In user-facing replies, refer to projects, frames, and other named resources by their current names. Do not expose their IDs unless the user explicitly asks for them; IDs may remain embedded in URLs that link to those resources.\n\nWe recommend using Drawcall Market when a design needs 3D assets such as models, textures, or environments.\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, Markdown for a formatted text document, image for an existing 2D image, and Market only for an exact public asset reference, `name@version`. GLTS and Markdown frames require a viewport size; image and Market frames derive their canvas size. A GLTS or Markdown frame accepts its root file at creation.\n\nRead a file before editing it. Use a narrow edit for one known change and write a complete file when replacing it. GLTS and Markdown frame files may be created or deleted. Image and Market frame files are read-only.\n\n## Frame previews\n\nEvery frame has a canonical public WebP preview in `previewUrl` at `https://<project-id>.design.drawcallcontent.com/<frame-id>.webp`, whether its type is GLTS, Markdown, image, or Market. Use `get_design_frame_preview` to inspect it as image content. Use `get_design_frame_screenshot` only when a fresh PNG render is required. Pass `previewUrl` as a reference URL to `generate_design_image` when one frame's appearance should inform another image.\n\n## Markdown documents\n\nA Markdown frame contains one optional source file at `/<frame-id>/index.md`; without it the frame renders as an empty document. Raw HTML is not rendered. Use ordinary Markdown image syntax with a frame's canonical WebP path to embed its current rendering:\n\n```md\n\n```\n\nAn absolute canonical WebP URL from the same project is equivalent. A Markdown document may embed up to 32 existing GLTS, image, or Market frames. It may not embed itself or another Markdown frame. Use the canonical syntax instead of copying a screenshot URL or source asset so the document follows later frame changes.\n\nPrefer focused Markdown frames. A document that covers separable topics is usually clearer as multiple frames connected with canonical links, `[Related details](/<frame-id>/)`, because readers can navigate directly to the part they need. An embedded frame is useful when its current rendering adds visual context; a link is better when the reader only needs to navigate.\n\n## Comments and annotations\n\nUse comments for review conversations and persistent annotations, including explanations of objects or regions inside 2D and 3D frames. Inspect the current comments before replying, resolving, reopening, or deleting so the action targets the current thread.\n\nA comment without a position applies to its frame. A 2D position is normalized image space and applies only to an image frame. A 3D position is GLTS world space and applies only to a GLTS frame. Add a position only when its coordinates are authoritative; never infer 3D depth from a screenshot. Prefer a frame-level comment when the precise position is unknown.\n\nPositioned comments retain the frame version on which they were placed. If the frame later changes, treat the position as potentially stale and re-inspect the frame before relying on it. Replies belong to the root comment's thread. Resolved threads do not accept replies, so reopen one before continuing it. Resolve a thread when its concern has been addressed. Delete a comment or reply only when explicitly requested because deletion is permanent; deleting a root also deletes its replies. Comment authors come from the authenticated Drawcall account\u2014never invent an author identity.\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\nFor a 3D object, create the frame with its complete `index.glts` first, giving each imported `.glts` file that does not exist yet a rough bounding box in `imports`, then write the imported files one call at a time, the most visible first, and take a screenshot once they all exist. This order shows the whole object early and keeps every write visible. A file that imports further files declares their boxes the same way.\n\n```ts\nimport * as THREE from \"three\";\nimport Chassis from \"./parts/chassis.glts\";\nimport Wheel from \"./parts/wheel.glts\";\n\nexport default class Racecar extends THREE.Group {\n constructor() {\n super();\n this.add(new Chassis());\n for (const [x, z] of [\n [-0.8, 1.3],\n [0.8, 1.3],\n [-0.8, -1.3],\n [0.8, -1.3],\n ]) {\n const wheel = new Wheel();\n wheel.position.set(x, 0.4, z);\n this.add(wheel);\n }\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\nWhen a `.glts` constructor starts resource loading through a Three.js loader, import the current runtime's manager and pass it to that loader. This makes the initial root `loadAsync()` promise or `load()` callback wait for the resource and surface its failure. Use it with `TextureLoader`, `GLTFLoader`, `FileLoader`, and comparable loaders. Reload construction remains synchronous, and arbitrary asynchronous work is not tracked.\n\n```ts\nimport * as THREE from \"three\";\nimport { loadingManager } from \"@drawcall/glts\";\nimport { GLTFLoader } from \"three/addons/loaders/GLTFLoader.js\";\n\nexport default class Car extends THREE.Group {\n constructor() {\n super();\n new GLTFLoader(loadingManager).load(\n new URL(\"./car.glb\", import.meta.url).href,\n ({ scene }) => this.add(scene),\n );\n }\n}\n```\n\nGLTS supports static `.glts`, `three`, Three addons, and bare npm imports. It does not support helper `.ts` modules, dynamic imports, cyclic GLTS graphs, or cross-asset inheritance. Keep the asset self-contained and compose with nested GLTS assets.\n\nKeep preview-only camera and lighting out of the default scene so importing the GLTS composes only reusable content. A root `index.glts` may export `previewCamera` and `previewLighting`; these named exports affect its direct preview and are ignored when another GLTS imports it. `previewLighting` must be a `THREE.Object3D` containing at least one light.\n\n```ts\nimport * as THREE from \"three\";\n\nexport const previewCamera = new THREE.PerspectiveCamera(40, 1, 0.1, 100);\npreviewCamera.position.set(4, 3, 6);\npreviewCamera.lookAt(0, 0, 0);\n\nexport const previewLighting = new THREE.Group();\npreviewLighting.add(new THREE.HemisphereLight(0xffffff, 0x223344, 2));\n\nexport default class Product extends THREE.Group {\n // Reusable scene content only.\n}\n```\n\nWhen `previewCamera` is absent, the viewer uses the first camera found by depth-first traversal, then autofits if the scene has none. A saved frame camera remains the user override. Double-clicking a frame enters orbit from the 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 GLTS scenes, Markdown documents, and image or Market references in Drawcall Design. Use whenever the user names Drawcall Design or one of its projects, canvases, frames, filesystems, GLTS assets, or Markdown frames. Do not use for full games, applications, or unrelated image generation.\n---\n\n# Drawcall Design\n\n## CLI transport\n\nThe commands below are the Drawcall transport in this environment. For Design operations, use only this documented command interface. A failed command does not make the transport unavailable.\n\nImage frame creation and image-generation references accept public HTTP(S) URLs or local PNG, JPEG, and WebP files.\n\nSelect the project with `-p <project-id>`. File commands take project-absolute paths that include the frame ID. Repeat `--reference` to preserve image-generation reference order.\n\n```sh\nnpx drawcall design project list\nnpx drawcall design -p r6z2n9k4x8m1qc frame list\nnpx drawcall design -p r6z2n9k4x8m1qc frame create Racecar --type glts --size 1280x800 --import ./parts/wheel.glts=-0.5,0,-0.5:0.5,1,0.5 --text - <<'GLTS'\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}\nGLTS\nnpx drawcall design -p r6z2n9k4x8m1qc write /a4z8m2q7v9kcde/parts/wheel.glts - <<'GLTS'\nimport * as THREE from \"three\";\n\nexport default class Wheel extends THREE.Mesh {\n constructor() {\n super(new THREE.TorusGeometry(0.4, 0.12, 16, 48), new THREE.MeshStandardMaterial({ color: 0x222222 }));\n }\n}\nGLTS\nnpx drawcall design -p r6z2n9k4x8m1qc frame preview a4z8m2q7v9kcde\nnpx drawcall design -p r6z2n9k4x8m1qc frame screenshot a4z8m2q7v9kcde\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'\nnpx drawcall design -p r6z2n9k4x8m1qc comment list a4z8m2q7v9kcde\nnpx drawcall design -p r6z2n9k4x8m1qc comment show c4z8m2q7v9kcdf\nnpx drawcall design -p r6z2n9k4x8m1qc comment create a4z8m2q7v9kcde 'The bevel catches the key light here.' --position-3d 0.2,1.1,-0.4\nnpx drawcall design -p r6z2n9k4x8m1qc comment reply c4z8m2q7v9kcdf 'Adjusted the material roughness.'\nnpx drawcall design -p r6z2n9k4x8m1qc comment resolve c4z8m2q7v9kcdf\nnpx drawcall design -p r6z2n9k4x8m1qc comment delete c4z8m2q7v9kcdf --yes\nnpx drawcall design -p r6z2n9k4x8m1qc frame generate-image 'Product photograph' --prompt 'A product photograph of this object' --reference https://r6z2n9k4x8m1qc.design.drawcallcontent.com/a4z8m2q7v9kcde.webp\nnpx drawcall design -p r6z2n9k4x8m1qc frame edit-image b4z8m2q7v9kcdf --prompt 'Use warmer light' --name 'Warm product photograph' --reference ./lighting.webp\n```\n\n`frame create --text`, `write`, comment create, and reply text accept `-` to read the text from stdin; a quoted heredoc keeps multi-line source intact. `--import <specifier>=<min>:<max>` declares the bounding box of an imported `.glts` file that does not exist yet, as `x,y,z:x,y,z`, and may repeat. Run one file write per command invocation, never several in one shell command. Use `--position-2d x,y` only for normalized image coordinates and `--position-3d x,y,z` only for authoritative GLTS world coordinates.\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 mutable labels. In user-facing replies, refer to projects, frames, and other named resources by their current names. Do not expose their IDs unless the user explicitly asks for them; IDs may remain embedded in URLs that link to those resources.\n\nWe recommend using Drawcall Market when a design needs 3D assets such as models, textures, or environments.\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, Markdown for a formatted text document, image for an existing 2D image, and Market only for an exact public asset reference, `name@version`. GLTS and Markdown frames require a viewport size; image and Market frames derive their canvas size. A GLTS or Markdown frame accepts its root file at creation.\n\nRead a file before editing it. Use a narrow edit for one known change and write a complete file when replacing it. GLTS and Markdown frame files may be created or deleted. Image and Market frame files are read-only.\n\n## Frame previews\n\nEvery frame has a canonical public WebP preview in `previewUrl` at `https://<project-id>.design.drawcallcontent.com/<frame-id>.webp`, whether its type is GLTS, Markdown, image, or Market. `frame preview <frame-id>` prints that URL. Use `frame screenshot` only when a fresh PNG render is required. Pass a preview URL with `--reference` when one frame's appearance should inform another image. A reference may instead be a local PNG, JPEG, or WebP file.\n\n## Markdown documents\n\nA Markdown frame contains one optional source file at `/<frame-id>/index.md`; without it the frame renders as an empty document. Raw HTML is not rendered. Use ordinary Markdown image syntax with a frame's canonical WebP path to embed its current rendering:\n\n```md\n\n```\n\nAn absolute canonical WebP URL from the same project is equivalent. A Markdown document may embed up to 32 existing GLTS, image, or Market frames. It may not embed itself or another Markdown frame. Use the canonical syntax instead of copying a screenshot URL or source asset so the document follows later frame changes.\n\nPrefer focused Markdown frames. A document that covers separable topics is usually clearer as multiple frames connected with canonical links, `[Related details](/<frame-id>/)`, because readers can navigate directly to the part they need. An embedded frame is useful when its current rendering adds visual context; a link is better when the reader only needs to navigate.\n\n## Comments and annotations\n\nUse comments for review conversations and persistent annotations, including explanations of objects or regions inside 2D and 3D frames. Inspect the current comments before replying, resolving, reopening, or deleting so the action targets the current thread.\n\nA comment without a position applies to its frame. A 2D position is normalized image space and applies only to an image frame. A 3D position is GLTS world space and applies only to a GLTS frame. Add a position only when its coordinates are authoritative; never infer 3D depth from a screenshot. Prefer a frame-level comment when the precise position is unknown.\n\nPositioned comments retain the frame version on which they were placed. If the frame later changes, treat the position as potentially stale and re-inspect the frame before relying on it. Replies belong to the root comment's thread. Resolved threads do not accept replies, so reopen one before continuing it. Resolve a thread when its concern has been addressed. Delete a comment or reply only when explicitly requested because deletion is permanent; deleting a root also deletes its replies. Comment authors come from the authenticated Drawcall account\u2014never invent an author identity.\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\nFor a 3D object, create the frame with its complete `index.glts` first, giving each imported `.glts` file that does not exist yet a rough bounding box in `imports`, then write the imported files one call at a time, the most visible first, and take a screenshot once they all exist. This order shows the whole object early and keeps every write visible. A file that imports further files declares their boxes the same way.\n\n```ts\nimport * as THREE from \"three\";\nimport Chassis from \"./parts/chassis.glts\";\nimport Wheel from \"./parts/wheel.glts\";\n\nexport default class Racecar extends THREE.Group {\n constructor() {\n super();\n this.add(new Chassis());\n for (const [x, z] of [\n [-0.8, 1.3],\n [0.8, 1.3],\n [-0.8, -1.3],\n [0.8, -1.3],\n ]) {\n const wheel = new Wheel();\n wheel.position.set(x, 0.4, z);\n this.add(wheel);\n }\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\nWhen a `.glts` constructor starts resource loading through a Three.js loader, import the current runtime's manager and pass it to that loader. This makes the initial root `loadAsync()` promise or `load()` callback wait for the resource and surface its failure. Use it with `TextureLoader`, `GLTFLoader`, `FileLoader`, and comparable loaders. Reload construction remains synchronous, and arbitrary asynchronous work is not tracked.\n\n```ts\nimport * as THREE from \"three\";\nimport { loadingManager } from \"@drawcall/glts\";\nimport { GLTFLoader } from \"three/addons/loaders/GLTFLoader.js\";\n\nexport default class Car extends THREE.Group {\n constructor() {\n super();\n new GLTFLoader(loadingManager).load(\n new URL(\"./car.glb\", import.meta.url).href,\n ({ scene }) => this.add(scene),\n );\n }\n}\n```\n\nGLTS supports static `.glts`, `three`, Three addons, and bare npm imports. It does not support helper `.ts` modules, dynamic imports, cyclic GLTS graphs, or cross-asset inheritance. Keep the asset self-contained and compose with nested GLTS assets.\n\nKeep preview-only camera and lighting out of the default scene so importing the GLTS composes only reusable content. A root `index.glts` may export `previewCamera` and `previewLighting`; these named exports affect its direct preview and are ignored when another GLTS imports it. `previewLighting` must be a `THREE.Object3D` containing at least one light.\n\n```ts\nimport * as THREE from \"three\";\n\nexport const previewCamera = new THREE.PerspectiveCamera(40, 1, 0.1, 100);\npreviewCamera.position.set(4, 3, 6);\npreviewCamera.lookAt(0, 0, 0);\n\nexport const previewLighting = new THREE.Group();\npreviewLighting.add(new THREE.HemisphereLight(0xffffff, 0x223344, 2));\n\nexport default class Product extends THREE.Group {\n // Reusable scene content only.\n}\n```\n\nWhen `previewCamera` is absent, the viewer uses the first camera found by depth-first traversal, then autofits if the scene has none. A saved frame camera remains the user override. Double-clicking a frame enters orbit from the 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
|
+
export declare const mcpDesignSkill = "---\nname: drawcall-design\ndescription: Create, modify, inspect, compose, and reuse GLTS scenes, Markdown documents, and image or Market references in Drawcall Design. Use whenever the user names Drawcall Design or one of its projects, canvases, frames, filesystems, GLTS assets, or Markdown frames. 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 Drawcall transport in this environment. For Design operations, use only the tools documented here. A failed tool call does not make the transport unavailable.\n\nImage frame creation uses a public HTTP(S) image URL.\n\nUse `generate_design_image` only when the user asks for a 2D image or reference. Its references must be public HTTP(S) URLs. 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. `create_design_frame` takes the root file of a glts or markdown frame as `text`, and `create_design_frame`, `write_design_file`, and `edit_design_file` take `imports`, the bounding box of each contextually loaded `.glts` file that does not exist yet, keyed by its URL specifier as written. The create result includes the new frame ID that later paths start with. File tools identify their target with `project` and a project-absolute `path`; they do not accept a separate `frame` argument. Call `list_design_files` and pass one of its returned paths unchanged.\n\nFor comments, call `list_design_comments` and, when needed, `get_design_comment` before changing a thread. Use `create_design_comment`, `reply_to_design_comment`, `resolve_design_comment`, `reopen_design_comment`, and `delete_design_comment` for their named operations. Structured tool calls use `body` for comment text. A positioned create requires the target frame's current `contentRevision` as `expectedContentRevision`; list frames again and re-inspect the position after a conflict.\n\n```json\n[\n {\n \"tool\": \"list_design_projects\",\n \"arguments\": {}\n },\n {\n \"tool\": \"list_design_frames\",\n \"arguments\": {\n \"project\": \"r6z2n9k4x8m1qc\"\n }\n },\n {\n \"tool\": \"create_design_frame\",\n \"arguments\": {\n \"project\": \"r6z2n9k4x8m1qc\",\n \"name\": \"Racecar\",\n \"type\": \"glts\",\n \"width\": 1280,\n \"height\": 800,\n \"text\": \"import { gltsLoader, scene } from \\\"@drawcall/glts\\\";\\n\\nconst wheel = await gltsLoader.loadAsync(\\n new URL(\\\"./parts/wheel.glts\\\", import.meta.url),\\n);\\nscene.add(wheel);\\n\",\n \"imports\": {\n \"./parts/wheel.glts\": {\n \"min\": [\n -0.5,\n 0,\n -0.5\n ],\n \"max\": [\n 0.5,\n 1,\n 0.5\n ]\n }\n }\n }\n },\n {\n \"tool\": \"write_design_file\",\n \"arguments\": {\n \"project\": \"r6z2n9k4x8m1qc\",\n \"path\": \"/a4z8m2q7v9kcde/parts/wheel.glts\",\n \"text\": \"import * as THREE from \\\"three\\\";\\nimport { onDispose, scene } from \\\"@drawcall/glts\\\";\\n\\nconst geometry = new THREE.TorusGeometry(0.4, 0.12, 16, 48);\\nconst material = new THREE.MeshStandardMaterial({ color: 0x222222 });\\nscene.add(new THREE.Mesh(geometry, material));\\n\\nonDispose(() => {\\n geometry.dispose();\\n material.dispose();\\n});\\n\"\n }\n },\n {\n \"tool\": \"list_design_files\",\n \"arguments\": {\n \"project\": \"r6z2n9k4x8m1qc\"\n }\n },\n {\n \"tool\": \"read_design_file\",\n \"arguments\": {\n \"project\": \"r6z2n9k4x8m1qc\",\n \"path\": \"/a4z8m2q7v9kcde/index.glts\"\n }\n },\n {\n \"tool\": \"edit_design_file\",\n \"arguments\": {\n \"project\": \"r6z2n9k4x8m1qc\",\n \"path\": \"/a4z8m2q7v9kcde/index.glts\",\n \"oldText\": \"color: 0xffffff\",\n \"newText\": \"color: 0x000000\"\n }\n },\n {\n \"tool\": \"create_design_comment\",\n \"arguments\": {\n \"project\": \"r6z2n9k4x8m1qc\",\n \"frame\": \"a4z8m2q7v9kcde\",\n \"body\": \"The bevel catches the key light here.\",\n \"position\": {\n \"kind\": \"3d\",\n \"x\": 0.2,\n \"y\": 1.1,\n \"z\": -0.4\n },\n \"expectedContentRevision\": 7\n }\n },\n {\n \"tool\": \"reply_to_design_comment\",\n \"arguments\": {\n \"project\": \"r6z2n9k4x8m1qc\",\n \"comment\": \"c4z8m2q7v9kcdf\",\n \"body\": \"Adjusted the material roughness.\"\n }\n },\n {\n \"tool\": \"resolve_design_comment\",\n \"arguments\": {\n \"project\": \"r6z2n9k4x8m1qc\",\n \"comment\": \"c4z8m2q7v9kcdf\"\n }\n },\n {\n \"tool\": \"generate_design_image\",\n \"arguments\": {\n \"project\": \"r6z2n9k4x8m1qc\",\n \"operation\": \"generate\",\n \"prompt\": \"A product photograph of this object\",\n \"references\": [\n \"https://r6z2n9k4x8m1qc.design.drawcallcontent.com/a4z8m2q7v9kcde.webp\"\n ],\n \"result\": \"new\",\n \"name\": \"Product photograph\"\n }\n },\n {\n \"tool\": \"get_design_frame_preview\",\n \"arguments\": {\n \"project\": \"r6z2n9k4x8m1qc\",\n \"frame\": \"a4z8m2q7v9kcde\"\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 mutable labels. In user-facing replies, refer to projects, frames, and other named resources by their current names. Do not expose their IDs unless the user explicitly asks for them; IDs may remain embedded in URLs that link to those resources.\n\nWe recommend using Drawcall Market when a design needs 3D assets such as models, textures, or environments.\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, Markdown for a formatted text document, image for an existing 2D image, and Market only for an exact public asset reference, `name@version`. GLTS and Markdown frames require a viewport size; image and Market frames derive their canvas size. A GLTS or Markdown frame accepts its root file at creation.\n\nRead a file before editing it. Use a narrow edit for one known change and write a complete file when replacing it. GLTS and Markdown frame files may be created or deleted. Image and Market frame files are read-only.\n\n## Frame previews\n\nEvery frame has a canonical public WebP preview in `previewUrl` at `https://<project-id>.design.drawcallcontent.com/<frame-id>.webp`, whether its type is GLTS, Markdown, image, or Market. Use `get_design_frame_preview` to inspect it as image content. Use `get_design_frame_screenshot` only when a fresh PNG render is required. Pass `previewUrl` as a reference URL to `generate_design_image` when one frame's appearance should inform another image.\n\n## Markdown documents\n\nA Markdown frame contains one optional source file at `/<frame-id>/index.md`; without it the frame renders as an empty document. Raw HTML is not rendered. Use ordinary Markdown image syntax with a frame's canonical WebP path to embed its current rendering:\n\n```md\n\n```\n\nAn absolute canonical WebP URL from the same project is equivalent. A Markdown document may embed up to 32 existing GLTS, image, or Market frames. It may not embed itself or another Markdown frame. Use the canonical syntax instead of copying a screenshot URL or source asset so the document follows later frame changes.\n\nPrefer focused Markdown frames. A document that covers separable topics is usually clearer as multiple frames connected with canonical links, `[Related details](/<frame-id>/)`, because readers can navigate directly to the part they need. An embedded frame is useful when its current rendering adds visual context; a link is better when the reader only needs to navigate.\n\n## Comments and annotations\n\nUse comments for review conversations and persistent annotations, including explanations of objects or regions inside 2D and 3D frames. Inspect the current comments before replying, resolving, reopening, or deleting so the action targets the current thread.\n\nA comment without a position applies to its frame. A 2D position is normalized image space and applies only to an image frame. A 3D position is GLTS world space and applies only to a GLTS frame. Add a position only when its coordinates are authoritative; never infer 3D depth from a screenshot. Prefer a frame-level comment when the precise position is unknown.\n\nPositioned comments retain the frame version on which they were placed. If the frame later changes, treat the position as potentially stale and re-inspect the frame before relying on it. Replies belong to the root comment's thread. Resolved threads do not accept replies, so reopen one before continuing it. Resolve a thread when its concern has been addressed. Delete a comment or reply only when explicitly requested because deletion is permanent; deleting a root also deletes its replies. Comment authors come from the authenticated Drawcall account\u2014never invent an author identity.\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, exportless TypeScript ESM script that builds a native `THREE.Scene` through contextual values from `@drawcall/glts`:\n\n```ts\nimport * as THREE from \"three\";\nimport { onDispose, scene } from \"@drawcall/glts\";\n\nconst geometry = new THREE.BoxGeometry();\nconst material = new THREE.MeshStandardMaterial({ color: \"orange\" });\nscene.add(new THREE.Mesh(geometry, material));\n\nonDispose(() => {\n geometry.dispose();\n material.dispose();\n});\n```\n\nUse named contextual imports: `gltsLoader`, `instanceCount`, `isPreview`, `loadingManager`, `onDispose`, `onFrame`, `onMatrixUpdateAt`, and `scene`. Do not export anything or import `GLTSLoader` or `GLTSRenderer`; the host owns loading and rendering. The script may import `three`, Three addons, and browser-compatible npm packages, but not static `.glts` imports, dynamic imports, import attributes, or sibling `.ts` helpers.\n\nThe host owns the root `scene` transform. Put authored placement and animation under child objects instead of changing the root scene's transform.\n\n### Composition and placeholders\n\nCompose another `.glts` file with the contextual loader and an explicit URL. Every loaded child must be added beneath `scene` before the script finishes:\n\n```ts\nimport * as THREE from \"three\";\nimport { gltsLoader, scene } from \"@drawcall/glts\";\n\nconst wheel = await gltsLoader.loadAsync(\n new URL(\"./parts/wheel.glts\", import.meta.url),\n);\nwheel.position.set(0.8, 0.4, 1.3);\nscene.add(wheel);\n```\n\nFor a 3D object, create the frame with its complete `index.glts` first. When a referenced `.glts` file does not exist yet, give its URL specifier a rough bounding box in `imports`; Design creates a visible placeholder at that path. Then write each placeholder file one call at a time, the most visible first, and take a screenshot once none remain. A nested file that loads another missing file declares that file's box on its own write.\n\nUse relative URLs within a frame. A reusable 3D asset belongs in another frame; load its root by project-absolute URL instead of copying its source:\n\n```ts\nconst chassis = await gltsLoader.loadAsync(\n new URL(\"/other-frame-id/index.glts\", import.meta.url),\n);\nscene.add(chassis);\n```\n\nDo not register `child.dispose()` with `onDispose`; attached GLTS children are owned and disposed recursively. Avoid cyclic loads. Use `loadInstancesAsync(url, count)` for a static mesh hierarchy when repeated copies matter; animated, nested, skinned, or already-instanced content needs native instancing with `instanceCount` and `onMatrixUpdateAt`.\n\n### Resources, updates, and cleanup\n\nFor a non-GLTS file from an image or Market frame, resolve its 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\nPass the contextual `loadingManager` to Three.js loaders during script evaluation so the frame waits for their requests and surfaces failures. Three.js loaders take URL strings; GLTS loader methods accept the `URL` itself. Top-level `await` is supported. Do not start loads from frame, matrix, timer, event, or effect callbacks because the loading scope has closed.\n\n```ts\nimport * as THREE from \"three\";\nimport { loadingManager, scene } from \"@drawcall/glts\";\nimport { GLTFLoader } from \"three/addons/loaders/GLTFLoader.js\";\n\nconst model = await new GLTFLoader(loadingManager).loadAsync(\n new URL(\"./car.glb\", import.meta.url).href,\n);\nscene.add(model.scene);\n```\n\nRelease only resources the script creates. GLTS recursively disposes managed child scenes but does not infer geometry, material, texture, or listener ownership. Close disposal callbacks over the owned values rather than traversing the imported `scene`, whose live binding follows the new revision during reload.\n\nUse `onFrame((delta) => ...)` for animation. Design advances the loaded root every frame, including managed descendants. A failed reload leaves the previous scene mounted.\n\n### Root presentation\n\nNative scene properties such as `scene.background`, `scene.environment`, `scene.fog`, and `scene.overrideMaterial` describe the asset when it is the render root. Assign `scene.defaultCamera` to recommend an authored view; a saved Design frame camera still overrides it. Design autofits the scene when neither exists.\n\nUse `isPreview` for staging that belongs only in the standalone Design frame, such as a floor, light rig, background, fog, or presentation effects. Design loads each displayed root in preview mode; nested GLTS scenes always receive `isPreview === false`, so their presentation does not leak into composition. Keep intrinsic content and each mesh's `castShadow` setting outside this block.\n\n```ts\nimport * as THREE from \"three\";\nimport { isPreview, onDispose, scene } from \"@drawcall/glts\";\nimport { UnrealBloomPass } from \"three/addons/postprocessing/UnrealBloomPass.js\";\n\nscene.defaultCamera = new THREE.PerspectiveCamera(35, 1, 0.1, 100);\nscene.defaultCamera.position.set(4, 3, 6);\nscene.defaultCamera.lookAt(0, 1, 0);\n\nif (isPreview) {\n const floor = new THREE.Mesh(\n new THREE.CircleGeometry(20),\n new THREE.MeshStandardMaterial({ color: \"#333333\" }),\n );\n floor.rotation.x = -Math.PI / 2;\n floor.receiveShadow = true;\n const light = new THREE.DirectionalLight(\"white\", 3);\n light.position.set(4, 6, 3);\n light.castShadow = true;\n\n scene.background = new THREE.Color(\"#171b2b\");\n scene.add(light, light.target, floor);\n scene.rendering.shadows = true;\n scene.rendering.toneMapping = THREE.ACESFilmicToneMapping;\n scene.rendering.toneMappingExposure = 1.1;\n scene.rendering.effects.push(\n ({ height, width }) =>\n new UnrealBloomPass(new THREE.Vector2(width, height), 0.3, 0.4, 0.85),\n );\n\n onDispose(() => {\n light.dispose();\n floor.geometry.dispose();\n floor.material.dispose();\n });\n}\n```\n\n`scene.rendering` supports shadows, clipping planes, tone mapping, exposure, and post-processing effect factories. A factory returns a fresh Three.js `Pass`; do not add `RenderPass` or `OutputPass`, load resources there, or dispose the returned pass yourself. The host renderer owns those passes. Visible shadows require renderer shadows plus a shadow-casting light, casting meshes, and receiving surfaces.\n\nPresentation belongs only to the root. A nested scene's background, environment, fog, default camera, and rendering profile do not override its parent.\n\n### Verification\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 GLTS scenes, Markdown documents, and image or Market references in Drawcall Design. Use whenever the user names Drawcall Design or one of its projects, canvases, frames, filesystems, GLTS assets, or Markdown frames. Do not use for full games, applications, or unrelated image generation.\n---\n\n# Drawcall Design\n\n## CLI transport\n\nThe commands below are the Drawcall transport in this environment. For Design operations, use only this documented command interface. A failed command does not make the transport unavailable.\n\nImage frame creation and image-generation references accept public HTTP(S) URLs or local PNG, JPEG, and WebP files.\n\nSelect the project with `-p <project-id>`. File commands take project-absolute paths that include the frame ID. Repeat `--reference` to preserve image-generation reference order.\n\n```sh\nnpx drawcall design project list\nnpx drawcall design -p r6z2n9k4x8m1qc frame list\nnpx drawcall design -p r6z2n9k4x8m1qc frame create Racecar --type glts --size 1280x800 --import ./parts/wheel.glts=-0.5,0,-0.5:0.5,1,0.5 --text - <<'GLTS'\nimport { gltsLoader, scene } from \"@drawcall/glts\";\n\nconst wheel = await gltsLoader.loadAsync(\n new URL(\"./parts/wheel.glts\", import.meta.url),\n);\nscene.add(wheel);\nGLTS\nnpx drawcall design -p r6z2n9k4x8m1qc write /a4z8m2q7v9kcde/parts/wheel.glts - <<'GLTS'\nimport * as THREE from \"three\";\nimport { onDispose, scene } from \"@drawcall/glts\";\n\nconst geometry = new THREE.TorusGeometry(0.4, 0.12, 16, 48);\nconst material = new THREE.MeshStandardMaterial({ color: 0x222222 });\nscene.add(new THREE.Mesh(geometry, material));\n\nonDispose(() => {\n geometry.dispose();\n material.dispose();\n});\nGLTS\nnpx drawcall design -p r6z2n9k4x8m1qc frame preview a4z8m2q7v9kcde\nnpx drawcall design -p r6z2n9k4x8m1qc frame screenshot a4z8m2q7v9kcde\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'\nnpx drawcall design -p r6z2n9k4x8m1qc comment list a4z8m2q7v9kcde\nnpx drawcall design -p r6z2n9k4x8m1qc comment show c4z8m2q7v9kcdf\nnpx drawcall design -p r6z2n9k4x8m1qc comment create a4z8m2q7v9kcde 'The bevel catches the key light here.' --position-3d 0.2,1.1,-0.4\nnpx drawcall design -p r6z2n9k4x8m1qc comment reply c4z8m2q7v9kcdf 'Adjusted the material roughness.'\nnpx drawcall design -p r6z2n9k4x8m1qc comment resolve c4z8m2q7v9kcdf\nnpx drawcall design -p r6z2n9k4x8m1qc comment delete c4z8m2q7v9kcdf --yes\nnpx drawcall design -p r6z2n9k4x8m1qc frame generate-image 'Product photograph' --prompt 'A product photograph of this object' --reference https://r6z2n9k4x8m1qc.design.drawcallcontent.com/a4z8m2q7v9kcde.webp\nnpx drawcall design -p r6z2n9k4x8m1qc frame edit-image b4z8m2q7v9kcdf --prompt 'Use warmer light' --name 'Warm product photograph' --reference ./lighting.webp\n```\n\n`frame create --text`, `write`, comment create, and reply text accept `-` to read the text from stdin; a quoted heredoc keeps multi-line source intact. `--import <specifier>=<min>:<max>` declares the bounding box of a contextually loaded `.glts` file that does not exist yet, as `x,y,z:x,y,z`, and may repeat. Run one file write per command invocation, never several in one shell command. Use `--position-2d x,y` only for normalized image coordinates and `--position-3d x,y,z` only for authoritative GLTS world coordinates.\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 mutable labels. In user-facing replies, refer to projects, frames, and other named resources by their current names. Do not expose their IDs unless the user explicitly asks for them; IDs may remain embedded in URLs that link to those resources.\n\nWe recommend using Drawcall Market when a design needs 3D assets such as models, textures, or environments.\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, Markdown for a formatted text document, image for an existing 2D image, and Market only for an exact public asset reference, `name@version`. GLTS and Markdown frames require a viewport size; image and Market frames derive their canvas size. A GLTS or Markdown frame accepts its root file at creation.\n\nRead a file before editing it. Use a narrow edit for one known change and write a complete file when replacing it. GLTS and Markdown frame files may be created or deleted. Image and Market frame files are read-only.\n\n## Frame previews\n\nEvery frame has a canonical public WebP preview in `previewUrl` at `https://<project-id>.design.drawcallcontent.com/<frame-id>.webp`, whether its type is GLTS, Markdown, image, or Market. `frame preview <frame-id>` prints that URL. Use `frame screenshot` only when a fresh PNG render is required. Pass a preview URL with `--reference` when one frame's appearance should inform another image. A reference may instead be a local PNG, JPEG, or WebP file.\n\n## Markdown documents\n\nA Markdown frame contains one optional source file at `/<frame-id>/index.md`; without it the frame renders as an empty document. Raw HTML is not rendered. Use ordinary Markdown image syntax with a frame's canonical WebP path to embed its current rendering:\n\n```md\n\n```\n\nAn absolute canonical WebP URL from the same project is equivalent. A Markdown document may embed up to 32 existing GLTS, image, or Market frames. It may not embed itself or another Markdown frame. Use the canonical syntax instead of copying a screenshot URL or source asset so the document follows later frame changes.\n\nPrefer focused Markdown frames. A document that covers separable topics is usually clearer as multiple frames connected with canonical links, `[Related details](/<frame-id>/)`, because readers can navigate directly to the part they need. An embedded frame is useful when its current rendering adds visual context; a link is better when the reader only needs to navigate.\n\n## Comments and annotations\n\nUse comments for review conversations and persistent annotations, including explanations of objects or regions inside 2D and 3D frames. Inspect the current comments before replying, resolving, reopening, or deleting so the action targets the current thread.\n\nA comment without a position applies to its frame. A 2D position is normalized image space and applies only to an image frame. A 3D position is GLTS world space and applies only to a GLTS frame. Add a position only when its coordinates are authoritative; never infer 3D depth from a screenshot. Prefer a frame-level comment when the precise position is unknown.\n\nPositioned comments retain the frame version on which they were placed. If the frame later changes, treat the position as potentially stale and re-inspect the frame before relying on it. Replies belong to the root comment's thread. Resolved threads do not accept replies, so reopen one before continuing it. Resolve a thread when its concern has been addressed. Delete a comment or reply only when explicitly requested because deletion is permanent; deleting a root also deletes its replies. Comment authors come from the authenticated Drawcall account\u2014never invent an author identity.\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, exportless TypeScript ESM script that builds a native `THREE.Scene` through contextual values from `@drawcall/glts`:\n\n```ts\nimport * as THREE from \"three\";\nimport { onDispose, scene } from \"@drawcall/glts\";\n\nconst geometry = new THREE.BoxGeometry();\nconst material = new THREE.MeshStandardMaterial({ color: \"orange\" });\nscene.add(new THREE.Mesh(geometry, material));\n\nonDispose(() => {\n geometry.dispose();\n material.dispose();\n});\n```\n\nUse named contextual imports: `gltsLoader`, `instanceCount`, `isPreview`, `loadingManager`, `onDispose`, `onFrame`, `onMatrixUpdateAt`, and `scene`. Do not export anything or import `GLTSLoader` or `GLTSRenderer`; the host owns loading and rendering. The script may import `three`, Three addons, and browser-compatible npm packages, but not static `.glts` imports, dynamic imports, import attributes, or sibling `.ts` helpers.\n\nThe host owns the root `scene` transform. Put authored placement and animation under child objects instead of changing the root scene's transform.\n\n### Composition and placeholders\n\nCompose another `.glts` file with the contextual loader and an explicit URL. Every loaded child must be added beneath `scene` before the script finishes:\n\n```ts\nimport * as THREE from \"three\";\nimport { gltsLoader, scene } from \"@drawcall/glts\";\n\nconst wheel = await gltsLoader.loadAsync(\n new URL(\"./parts/wheel.glts\", import.meta.url),\n);\nwheel.position.set(0.8, 0.4, 1.3);\nscene.add(wheel);\n```\n\nFor a 3D object, create the frame with its complete `index.glts` first. When a referenced `.glts` file does not exist yet, give its URL specifier a rough bounding box in `imports`; Design creates a visible placeholder at that path. Then write each placeholder file one call at a time, the most visible first, and take a screenshot once none remain. A nested file that loads another missing file declares that file's box on its own write.\n\nUse relative URLs within a frame. A reusable 3D asset belongs in another frame; load its root by project-absolute URL instead of copying its source:\n\n```ts\nconst chassis = await gltsLoader.loadAsync(\n new URL(\"/other-frame-id/index.glts\", import.meta.url),\n);\nscene.add(chassis);\n```\n\nDo not register `child.dispose()` with `onDispose`; attached GLTS children are owned and disposed recursively. Avoid cyclic loads. Use `loadInstancesAsync(url, count)` for a static mesh hierarchy when repeated copies matter; animated, nested, skinned, or already-instanced content needs native instancing with `instanceCount` and `onMatrixUpdateAt`.\n\n### Resources, updates, and cleanup\n\nFor a non-GLTS file from an image or Market frame, resolve its 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\nPass the contextual `loadingManager` to Three.js loaders during script evaluation so the frame waits for their requests and surfaces failures. Three.js loaders take URL strings; GLTS loader methods accept the `URL` itself. Top-level `await` is supported. Do not start loads from frame, matrix, timer, event, or effect callbacks because the loading scope has closed.\n\n```ts\nimport * as THREE from \"three\";\nimport { loadingManager, scene } from \"@drawcall/glts\";\nimport { GLTFLoader } from \"three/addons/loaders/GLTFLoader.js\";\n\nconst model = await new GLTFLoader(loadingManager).loadAsync(\n new URL(\"./car.glb\", import.meta.url).href,\n);\nscene.add(model.scene);\n```\n\nRelease only resources the script creates. GLTS recursively disposes managed child scenes but does not infer geometry, material, texture, or listener ownership. Close disposal callbacks over the owned values rather than traversing the imported `scene`, whose live binding follows the new revision during reload.\n\nUse `onFrame((delta) => ...)` for animation. Design advances the loaded root every frame, including managed descendants. A failed reload leaves the previous scene mounted.\n\n### Root presentation\n\nNative scene properties such as `scene.background`, `scene.environment`, `scene.fog`, and `scene.overrideMaterial` describe the asset when it is the render root. Assign `scene.defaultCamera` to recommend an authored view; a saved Design frame camera still overrides it. Design autofits the scene when neither exists.\n\nUse `isPreview` for staging that belongs only in the standalone Design frame, such as a floor, light rig, background, fog, or presentation effects. Design loads each displayed root in preview mode; nested GLTS scenes always receive `isPreview === false`, so their presentation does not leak into composition. Keep intrinsic content and each mesh's `castShadow` setting outside this block.\n\n```ts\nimport * as THREE from \"three\";\nimport { isPreview, onDispose, scene } from \"@drawcall/glts\";\nimport { UnrealBloomPass } from \"three/addons/postprocessing/UnrealBloomPass.js\";\n\nscene.defaultCamera = new THREE.PerspectiveCamera(35, 1, 0.1, 100);\nscene.defaultCamera.position.set(4, 3, 6);\nscene.defaultCamera.lookAt(0, 1, 0);\n\nif (isPreview) {\n const floor = new THREE.Mesh(\n new THREE.CircleGeometry(20),\n new THREE.MeshStandardMaterial({ color: \"#333333\" }),\n );\n floor.rotation.x = -Math.PI / 2;\n floor.receiveShadow = true;\n const light = new THREE.DirectionalLight(\"white\", 3);\n light.position.set(4, 6, 3);\n light.castShadow = true;\n\n scene.background = new THREE.Color(\"#171b2b\");\n scene.add(light, light.target, floor);\n scene.rendering.shadows = true;\n scene.rendering.toneMapping = THREE.ACESFilmicToneMapping;\n scene.rendering.toneMappingExposure = 1.1;\n scene.rendering.effects.push(\n ({ height, width }) =>\n new UnrealBloomPass(new THREE.Vector2(width, height), 0.3, 0.4, 0.85),\n );\n\n onDispose(() => {\n light.dispose();\n floor.geometry.dispose();\n floor.material.dispose();\n });\n}\n```\n\n`scene.rendering` supports shadows, clipping planes, tone mapping, exposure, and post-processing effect factories. A factory returns a fresh Three.js `Pass`; do not add `RenderPass` or `OutputPass`, load resources there, or dispose the returned pass yourself. The host renderer owns those passes. Visible shadows require renderer shadows plus a shadow-casting light, casting meshes, and receiving surfaces.\n\nPresentation belongs only to the root. A nested scene's background, environment, fog, default camera, and rendering profile do not override its parent.\n\n### Verification\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";
|
package/dist/skill.generated.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// Generated from skill/SKILL.template.md.
|
|
2
|
-
export const mcpDesignSkill = '---\nname: drawcall-design\ndescription: Create, modify, inspect, compose, and reuse GLTS scenes, Markdown documents, and image or Market references in Drawcall Design. Use whenever the user names Drawcall Design or one of its projects, canvases, frames, filesystems, GLTS assets, or Markdown frames. 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 Drawcall transport in this environment. For Design operations, use only the tools documented here. A failed tool call does not make the transport unavailable.\n\nImage frame creation uses a public HTTP(S) image URL.\n\nUse `generate_design_image` only when the user asks for a 2D image or reference. Its references must be public HTTP(S) URLs. 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. `create_design_frame` takes the root file of a glts or markdown frame as `text`, and `create_design_frame`, `write_design_file`, and `edit_design_file` take `imports`, the bounding box of each imported `.glts` file that does not exist yet, keyed by the import specifier as written. The create result includes the new frame ID that later paths start with. File tools identify their target with `project` and a project-absolute `path`; they do not accept a separate `frame` argument. Call `list_design_files` and pass one of its returned paths unchanged.\n\nFor comments, call `list_design_comments` and, when needed, `get_design_comment` before changing a thread. Use `create_design_comment`, `reply_to_design_comment`, `resolve_design_comment`, `reopen_design_comment`, and `delete_design_comment` for their named operations. Structured tool calls use `body` for comment text. A positioned create requires the target frame\'s current `contentRevision` as `expectedContentRevision`; list frames again and re-inspect the position after a conflict.\n\n```json\n[\n {\n "tool": "list_design_projects",\n "arguments": {}\n },\n {\n "tool": "list_design_frames",\n "arguments": {\n "project": "r6z2n9k4x8m1qc"\n }\n },\n {\n "tool": "create_design_frame",\n "arguments": {\n "project": "r6z2n9k4x8m1qc",\n "name": "Racecar",\n "type": "glts",\n "width": 1280,\n "height": 800,\n "text": "import * 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 "imports": {\n "./parts/wheel.glts": {\n "min": [\n -0.5,\n 0,\n -0.5\n ],\n "max": [\n 0.5,\n 1,\n 0.5\n ]\n }\n }\n }\n },\n {\n "tool": "write_design_file",\n "arguments": {\n "project": "r6z2n9k4x8m1qc",\n "path": "/a4z8m2q7v9kcde/parts/wheel.glts",\n "text": "import * as THREE from \\"three\\";\\n\\nexport default class Wheel extends THREE.Mesh {\\n constructor() {\\n super(new THREE.TorusGeometry(0.4, 0.12, 16, 48), new THREE.MeshStandardMaterial({ color: 0x222222 }));\\n }\\n}\\n"\n }\n },\n {\n "tool": "list_design_files",\n "arguments": {\n "project": "r6z2n9k4x8m1qc"\n }\n },\n {\n "tool": "read_design_file",\n "arguments": {\n "project": "r6z2n9k4x8m1qc",\n "path": "/a4z8m2q7v9kcde/index.glts"\n }\n },\n {\n "tool": "edit_design_file",\n "arguments": {\n "project": "r6z2n9k4x8m1qc",\n "path": "/a4z8m2q7v9kcde/index.glts",\n "oldText": "color: 0xffffff",\n "newText": "color: 0x000000"\n }\n },\n {\n "tool": "create_design_comment",\n "arguments": {\n "project": "r6z2n9k4x8m1qc",\n "frame": "a4z8m2q7v9kcde",\n "body": "The bevel catches the key light here.",\n "position": {\n "kind": "3d",\n "x": 0.2,\n "y": 1.1,\n "z": -0.4\n },\n "expectedContentRevision": 7\n }\n },\n {\n "tool": "reply_to_design_comment",\n "arguments": {\n "project": "r6z2n9k4x8m1qc",\n "comment": "c4z8m2q7v9kcdf",\n "body": "Adjusted the material roughness."\n }\n },\n {\n "tool": "resolve_design_comment",\n "arguments": {\n "project": "r6z2n9k4x8m1qc",\n "comment": "c4z8m2q7v9kcdf"\n }\n },\n {\n "tool": "generate_design_image",\n "arguments": {\n "project": "r6z2n9k4x8m1qc",\n "operation": "generate",\n "prompt": "A product photograph of this object",\n "references": [\n "https://r6z2n9k4x8m1qc.design.drawcallcontent.com/a4z8m2q7v9kcde.webp"\n ],\n "result": "new",\n "name": "Product photograph"\n }\n },\n {\n "tool": "get_design_frame_preview",\n "arguments": {\n "project": "r6z2n9k4x8m1qc",\n "frame": "a4z8m2q7v9kcde"\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 mutable labels. In user-facing replies, refer to projects, frames, and other named resources by their current names. Do not expose their IDs unless the user explicitly asks for them; IDs may remain embedded in URLs that link to those resources.\n\nWe recommend using Drawcall Market when a design needs 3D assets such as models, textures, or environments.\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, Markdown for a formatted text document, image for an existing 2D image, and Market only for an exact public asset reference, `name@version`. GLTS and Markdown frames require a viewport size; image and Market frames derive their canvas size. A GLTS or Markdown frame accepts its root file at creation.\n\nRead a file before editing it. Use a narrow edit for one known change and write a complete file when replacing it. GLTS and Markdown frame files may be created or deleted. Image and Market frame files are read-only.\n\n## Frame previews\n\nEvery frame has a canonical public WebP preview in `previewUrl` at `https://<project-id>.design.drawcallcontent.com/<frame-id>.webp`, whether its type is GLTS, Markdown, image, or Market. Use `get_design_frame_preview` to inspect it as image content. Use `get_design_frame_screenshot` only when a fresh PNG render is required. Pass `previewUrl` as a reference URL to `generate_design_image` when one frame\'s appearance should inform another image.\n\n## Markdown documents\n\nA Markdown frame contains one optional source file at `/<frame-id>/index.md`; without it the frame renders as an empty document. Raw HTML is not rendered. Use ordinary Markdown image syntax with a frame\'s canonical WebP path to embed its current rendering:\n\n```md\n\n```\n\nAn absolute canonical WebP URL from the same project is equivalent. A Markdown document may embed up to 32 existing GLTS, image, or Market frames. It may not embed itself or another Markdown frame. Use the canonical syntax instead of copying a screenshot URL or source asset so the document follows later frame changes.\n\nPrefer focused Markdown frames. A document that covers separable topics is usually clearer as multiple frames connected with canonical links, `[Related details](/<frame-id>/)`, because readers can navigate directly to the part they need. An embedded frame is useful when its current rendering adds visual context; a link is better when the reader only needs to navigate.\n\n## Comments and annotations\n\nUse comments for review conversations and persistent annotations, including explanations of objects or regions inside 2D and 3D frames. Inspect the current comments before replying, resolving, reopening, or deleting so the action targets the current thread.\n\nA comment without a position applies to its frame. A 2D position is normalized image space and applies only to an image frame. A 3D position is GLTS world space and applies only to a GLTS frame. Add a position only when its coordinates are authoritative; never infer 3D depth from a screenshot. Prefer a frame-level comment when the precise position is unknown.\n\nPositioned comments retain the frame version on which they were placed. If the frame later changes, treat the position as potentially stale and re-inspect the frame before relying on it. Replies belong to the root comment\'s thread. Resolved threads do not accept replies, so reopen one before continuing it. Resolve a thread when its concern has been addressed. Delete a comment or reply only when explicitly requested because deletion is permanent; deleting a root also deletes its replies. Comment authors come from the authenticated Drawcall account—never invent an author identity.\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\nFor a 3D object, create the frame with its complete `index.glts` first, giving each imported `.glts` file that does not exist yet a rough bounding box in `imports`, then write the imported files one call at a time, the most visible first, and take a screenshot once they all exist. This order shows the whole object early and keeps every write visible. A file that imports further files declares their boxes the same way.\n\n```ts\nimport * as THREE from "three";\nimport Chassis from "./parts/chassis.glts";\nimport Wheel from "./parts/wheel.glts";\n\nexport default class Racecar extends THREE.Group {\n constructor() {\n super();\n this.add(new Chassis());\n for (const [x, z] of [\n [-0.8, 1.3],\n [0.8, 1.3],\n [-0.8, -1.3],\n [0.8, -1.3],\n ]) {\n const wheel = new Wheel();\n wheel.position.set(x, 0.4, z);\n this.add(wheel);\n }\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\nWhen a `.glts` constructor starts resource loading through a Three.js loader, import the current runtime\'s manager and pass it to that loader. This makes the initial root `loadAsync()` promise or `load()` callback wait for the resource and surface its failure. Use it with `TextureLoader`, `GLTFLoader`, `FileLoader`, and comparable loaders. Reload construction remains synchronous, and arbitrary asynchronous work is not tracked.\n\n```ts\nimport * as THREE from "three";\nimport { loadingManager } from "@drawcall/glts";\nimport { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";\n\nexport default class Car extends THREE.Group {\n constructor() {\n super();\n new GLTFLoader(loadingManager).load(\n new URL("./car.glb", import.meta.url).href,\n ({ scene }) => this.add(scene),\n );\n }\n}\n```\n\nGLTS supports static `.glts`, `three`, Three addons, and bare npm imports. It does not support helper `.ts` modules, dynamic imports, cyclic GLTS graphs, or cross-asset inheritance. Keep the asset self-contained and compose with nested GLTS assets.\n\nKeep preview-only camera and lighting out of the default scene so importing the GLTS composes only reusable content. A root `index.glts` may export `previewCamera` and `previewLighting`; these named exports affect its direct preview and are ignored when another GLTS imports it. `previewLighting` must be a `THREE.Object3D` containing at least one light.\n\n```ts\nimport * as THREE from "three";\n\nexport const previewCamera = new THREE.PerspectiveCamera(40, 1, 0.1, 100);\npreviewCamera.position.set(4, 3, 6);\npreviewCamera.lookAt(0, 0, 0);\n\nexport const previewLighting = new THREE.Group();\npreviewLighting.add(new THREE.HemisphereLight(0xffffff, 0x223344, 2));\n\nexport default class Product extends THREE.Group {\n // Reusable scene content only.\n}\n```\n\nWhen `previewCamera` is absent, the viewer uses the first camera found by depth-first traversal, then autofits if the scene has none. A saved frame camera remains the user override. Double-clicking a frame enters orbit from the 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 GLTS scenes, Markdown documents, and image or Market references in Drawcall Design. Use whenever the user names Drawcall Design or one of its projects, canvases, frames, filesystems, GLTS assets, or Markdown frames. Do not use for full games, applications, or unrelated image generation.\n---\n\n# Drawcall Design\n\n## CLI transport\n\nThe commands below are the Drawcall transport in this environment. For Design operations, use only this documented command interface. A failed command does not make the transport unavailable.\n\nImage frame creation and image-generation references accept public HTTP(S) URLs or local PNG, JPEG, and WebP files.\n\nSelect the project with `-p <project-id>`. File commands take project-absolute paths that include the frame ID. Repeat `--reference` to preserve image-generation reference order.\n\n```sh\nnpx drawcall design project list\nnpx drawcall design -p r6z2n9k4x8m1qc frame list\nnpx drawcall design -p r6z2n9k4x8m1qc frame create Racecar --type glts --size 1280x800 --import ./parts/wheel.glts=-0.5,0,-0.5:0.5,1,0.5 --text - <<\'GLTS\'\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}\nGLTS\nnpx drawcall design -p r6z2n9k4x8m1qc write /a4z8m2q7v9kcde/parts/wheel.glts - <<\'GLTS\'\nimport * as THREE from "three";\n\nexport default class Wheel extends THREE.Mesh {\n constructor() {\n super(new THREE.TorusGeometry(0.4, 0.12, 16, 48), new THREE.MeshStandardMaterial({ color: 0x222222 }));\n }\n}\nGLTS\nnpx drawcall design -p r6z2n9k4x8m1qc frame preview a4z8m2q7v9kcde\nnpx drawcall design -p r6z2n9k4x8m1qc frame screenshot a4z8m2q7v9kcde\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\'\nnpx drawcall design -p r6z2n9k4x8m1qc comment list a4z8m2q7v9kcde\nnpx drawcall design -p r6z2n9k4x8m1qc comment show c4z8m2q7v9kcdf\nnpx drawcall design -p r6z2n9k4x8m1qc comment create a4z8m2q7v9kcde \'The bevel catches the key light here.\' --position-3d 0.2,1.1,-0.4\nnpx drawcall design -p r6z2n9k4x8m1qc comment reply c4z8m2q7v9kcdf \'Adjusted the material roughness.\'\nnpx drawcall design -p r6z2n9k4x8m1qc comment resolve c4z8m2q7v9kcdf\nnpx drawcall design -p r6z2n9k4x8m1qc comment delete c4z8m2q7v9kcdf --yes\nnpx drawcall design -p r6z2n9k4x8m1qc frame generate-image \'Product photograph\' --prompt \'A product photograph of this object\' --reference https://r6z2n9k4x8m1qc.design.drawcallcontent.com/a4z8m2q7v9kcde.webp\nnpx drawcall design -p r6z2n9k4x8m1qc frame edit-image b4z8m2q7v9kcdf --prompt \'Use warmer light\' --name \'Warm product photograph\' --reference ./lighting.webp\n```\n\n`frame create --text`, `write`, comment create, and reply text accept `-` to read the text from stdin; a quoted heredoc keeps multi-line source intact. `--import <specifier>=<min>:<max>` declares the bounding box of an imported `.glts` file that does not exist yet, as `x,y,z:x,y,z`, and may repeat. Run one file write per command invocation, never several in one shell command. Use `--position-2d x,y` only for normalized image coordinates and `--position-3d x,y,z` only for authoritative GLTS world coordinates.\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 mutable labels. In user-facing replies, refer to projects, frames, and other named resources by their current names. Do not expose their IDs unless the user explicitly asks for them; IDs may remain embedded in URLs that link to those resources.\n\nWe recommend using Drawcall Market when a design needs 3D assets such as models, textures, or environments.\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, Markdown for a formatted text document, image for an existing 2D image, and Market only for an exact public asset reference, `name@version`. GLTS and Markdown frames require a viewport size; image and Market frames derive their canvas size. A GLTS or Markdown frame accepts its root file at creation.\n\nRead a file before editing it. Use a narrow edit for one known change and write a complete file when replacing it. GLTS and Markdown frame files may be created or deleted. Image and Market frame files are read-only.\n\n## Frame previews\n\nEvery frame has a canonical public WebP preview in `previewUrl` at `https://<project-id>.design.drawcallcontent.com/<frame-id>.webp`, whether its type is GLTS, Markdown, image, or Market. `frame preview <frame-id>` prints that URL. Use `frame screenshot` only when a fresh PNG render is required. Pass a preview URL with `--reference` when one frame\'s appearance should inform another image. A reference may instead be a local PNG, JPEG, or WebP file.\n\n## Markdown documents\n\nA Markdown frame contains one optional source file at `/<frame-id>/index.md`; without it the frame renders as an empty document. Raw HTML is not rendered. Use ordinary Markdown image syntax with a frame\'s canonical WebP path to embed its current rendering:\n\n```md\n\n```\n\nAn absolute canonical WebP URL from the same project is equivalent. A Markdown document may embed up to 32 existing GLTS, image, or Market frames. It may not embed itself or another Markdown frame. Use the canonical syntax instead of copying a screenshot URL or source asset so the document follows later frame changes.\n\nPrefer focused Markdown frames. A document that covers separable topics is usually clearer as multiple frames connected with canonical links, `[Related details](/<frame-id>/)`, because readers can navigate directly to the part they need. An embedded frame is useful when its current rendering adds visual context; a link is better when the reader only needs to navigate.\n\n## Comments and annotations\n\nUse comments for review conversations and persistent annotations, including explanations of objects or regions inside 2D and 3D frames. Inspect the current comments before replying, resolving, reopening, or deleting so the action targets the current thread.\n\nA comment without a position applies to its frame. A 2D position is normalized image space and applies only to an image frame. A 3D position is GLTS world space and applies only to a GLTS frame. Add a position only when its coordinates are authoritative; never infer 3D depth from a screenshot. Prefer a frame-level comment when the precise position is unknown.\n\nPositioned comments retain the frame version on which they were placed. If the frame later changes, treat the position as potentially stale and re-inspect the frame before relying on it. Replies belong to the root comment\'s thread. Resolved threads do not accept replies, so reopen one before continuing it. Resolve a thread when its concern has been addressed. Delete a comment or reply only when explicitly requested because deletion is permanent; deleting a root also deletes its replies. Comment authors come from the authenticated Drawcall account—never invent an author identity.\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\nFor a 3D object, create the frame with its complete `index.glts` first, giving each imported `.glts` file that does not exist yet a rough bounding box in `imports`, then write the imported files one call at a time, the most visible first, and take a screenshot once they all exist. This order shows the whole object early and keeps every write visible. A file that imports further files declares their boxes the same way.\n\n```ts\nimport * as THREE from "three";\nimport Chassis from "./parts/chassis.glts";\nimport Wheel from "./parts/wheel.glts";\n\nexport default class Racecar extends THREE.Group {\n constructor() {\n super();\n this.add(new Chassis());\n for (const [x, z] of [\n [-0.8, 1.3],\n [0.8, 1.3],\n [-0.8, -1.3],\n [0.8, -1.3],\n ]) {\n const wheel = new Wheel();\n wheel.position.set(x, 0.4, z);\n this.add(wheel);\n }\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\nWhen a `.glts` constructor starts resource loading through a Three.js loader, import the current runtime\'s manager and pass it to that loader. This makes the initial root `loadAsync()` promise or `load()` callback wait for the resource and surface its failure. Use it with `TextureLoader`, `GLTFLoader`, `FileLoader`, and comparable loaders. Reload construction remains synchronous, and arbitrary asynchronous work is not tracked.\n\n```ts\nimport * as THREE from "three";\nimport { loadingManager } from "@drawcall/glts";\nimport { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";\n\nexport default class Car extends THREE.Group {\n constructor() {\n super();\n new GLTFLoader(loadingManager).load(\n new URL("./car.glb", import.meta.url).href,\n ({ scene }) => this.add(scene),\n );\n }\n}\n```\n\nGLTS supports static `.glts`, `three`, Three addons, and bare npm imports. It does not support helper `.ts` modules, dynamic imports, cyclic GLTS graphs, or cross-asset inheritance. Keep the asset self-contained and compose with nested GLTS assets.\n\nKeep preview-only camera and lighting out of the default scene so importing the GLTS composes only reusable content. A root `index.glts` may export `previewCamera` and `previewLighting`; these named exports affect its direct preview and are ignored when another GLTS imports it. `previewLighting` must be a `THREE.Object3D` containing at least one light.\n\n```ts\nimport * as THREE from "three";\n\nexport const previewCamera = new THREE.PerspectiveCamera(40, 1, 0.1, 100);\npreviewCamera.position.set(4, 3, 6);\npreviewCamera.lookAt(0, 0, 0);\n\nexport const previewLighting = new THREE.Group();\npreviewLighting.add(new THREE.HemisphereLight(0xffffff, 0x223344, 2));\n\nexport default class Product extends THREE.Group {\n // Reusable scene content only.\n}\n```\n\nWhen `previewCamera` is absent, the viewer uses the first camera found by depth-first traversal, then autofits if the scene has none. A saved frame camera remains the user override. Double-clicking a frame enters orbit from the 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 const mcpDesignSkill = '---\nname: drawcall-design\ndescription: Create, modify, inspect, compose, and reuse GLTS scenes, Markdown documents, and image or Market references in Drawcall Design. Use whenever the user names Drawcall Design or one of its projects, canvases, frames, filesystems, GLTS assets, or Markdown frames. 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 Drawcall transport in this environment. For Design operations, use only the tools documented here. A failed tool call does not make the transport unavailable.\n\nImage frame creation uses a public HTTP(S) image URL.\n\nUse `generate_design_image` only when the user asks for a 2D image or reference. Its references must be public HTTP(S) URLs. 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. `create_design_frame` takes the root file of a glts or markdown frame as `text`, and `create_design_frame`, `write_design_file`, and `edit_design_file` take `imports`, the bounding box of each contextually loaded `.glts` file that does not exist yet, keyed by its URL specifier as written. The create result includes the new frame ID that later paths start with. File tools identify their target with `project` and a project-absolute `path`; they do not accept a separate `frame` argument. Call `list_design_files` and pass one of its returned paths unchanged.\n\nFor comments, call `list_design_comments` and, when needed, `get_design_comment` before changing a thread. Use `create_design_comment`, `reply_to_design_comment`, `resolve_design_comment`, `reopen_design_comment`, and `delete_design_comment` for their named operations. Structured tool calls use `body` for comment text. A positioned create requires the target frame\'s current `contentRevision` as `expectedContentRevision`; list frames again and re-inspect the position after a conflict.\n\n```json\n[\n {\n "tool": "list_design_projects",\n "arguments": {}\n },\n {\n "tool": "list_design_frames",\n "arguments": {\n "project": "r6z2n9k4x8m1qc"\n }\n },\n {\n "tool": "create_design_frame",\n "arguments": {\n "project": "r6z2n9k4x8m1qc",\n "name": "Racecar",\n "type": "glts",\n "width": 1280,\n "height": 800,\n "text": "import { gltsLoader, scene } from \\"@drawcall/glts\\";\\n\\nconst wheel = await gltsLoader.loadAsync(\\n new URL(\\"./parts/wheel.glts\\", import.meta.url),\\n);\\nscene.add(wheel);\\n",\n "imports": {\n "./parts/wheel.glts": {\n "min": [\n -0.5,\n 0,\n -0.5\n ],\n "max": [\n 0.5,\n 1,\n 0.5\n ]\n }\n }\n }\n },\n {\n "tool": "write_design_file",\n "arguments": {\n "project": "r6z2n9k4x8m1qc",\n "path": "/a4z8m2q7v9kcde/parts/wheel.glts",\n "text": "import * as THREE from \\"three\\";\\nimport { onDispose, scene } from \\"@drawcall/glts\\";\\n\\nconst geometry = new THREE.TorusGeometry(0.4, 0.12, 16, 48);\\nconst material = new THREE.MeshStandardMaterial({ color: 0x222222 });\\nscene.add(new THREE.Mesh(geometry, material));\\n\\nonDispose(() => {\\n geometry.dispose();\\n material.dispose();\\n});\\n"\n }\n },\n {\n "tool": "list_design_files",\n "arguments": {\n "project": "r6z2n9k4x8m1qc"\n }\n },\n {\n "tool": "read_design_file",\n "arguments": {\n "project": "r6z2n9k4x8m1qc",\n "path": "/a4z8m2q7v9kcde/index.glts"\n }\n },\n {\n "tool": "edit_design_file",\n "arguments": {\n "project": "r6z2n9k4x8m1qc",\n "path": "/a4z8m2q7v9kcde/index.glts",\n "oldText": "color: 0xffffff",\n "newText": "color: 0x000000"\n }\n },\n {\n "tool": "create_design_comment",\n "arguments": {\n "project": "r6z2n9k4x8m1qc",\n "frame": "a4z8m2q7v9kcde",\n "body": "The bevel catches the key light here.",\n "position": {\n "kind": "3d",\n "x": 0.2,\n "y": 1.1,\n "z": -0.4\n },\n "expectedContentRevision": 7\n }\n },\n {\n "tool": "reply_to_design_comment",\n "arguments": {\n "project": "r6z2n9k4x8m1qc",\n "comment": "c4z8m2q7v9kcdf",\n "body": "Adjusted the material roughness."\n }\n },\n {\n "tool": "resolve_design_comment",\n "arguments": {\n "project": "r6z2n9k4x8m1qc",\n "comment": "c4z8m2q7v9kcdf"\n }\n },\n {\n "tool": "generate_design_image",\n "arguments": {\n "project": "r6z2n9k4x8m1qc",\n "operation": "generate",\n "prompt": "A product photograph of this object",\n "references": [\n "https://r6z2n9k4x8m1qc.design.drawcallcontent.com/a4z8m2q7v9kcde.webp"\n ],\n "result": "new",\n "name": "Product photograph"\n }\n },\n {\n "tool": "get_design_frame_preview",\n "arguments": {\n "project": "r6z2n9k4x8m1qc",\n "frame": "a4z8m2q7v9kcde"\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 mutable labels. In user-facing replies, refer to projects, frames, and other named resources by their current names. Do not expose their IDs unless the user explicitly asks for them; IDs may remain embedded in URLs that link to those resources.\n\nWe recommend using Drawcall Market when a design needs 3D assets such as models, textures, or environments.\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, Markdown for a formatted text document, image for an existing 2D image, and Market only for an exact public asset reference, `name@version`. GLTS and Markdown frames require a viewport size; image and Market frames derive their canvas size. A GLTS or Markdown frame accepts its root file at creation.\n\nRead a file before editing it. Use a narrow edit for one known change and write a complete file when replacing it. GLTS and Markdown frame files may be created or deleted. Image and Market frame files are read-only.\n\n## Frame previews\n\nEvery frame has a canonical public WebP preview in `previewUrl` at `https://<project-id>.design.drawcallcontent.com/<frame-id>.webp`, whether its type is GLTS, Markdown, image, or Market. Use `get_design_frame_preview` to inspect it as image content. Use `get_design_frame_screenshot` only when a fresh PNG render is required. Pass `previewUrl` as a reference URL to `generate_design_image` when one frame\'s appearance should inform another image.\n\n## Markdown documents\n\nA Markdown frame contains one optional source file at `/<frame-id>/index.md`; without it the frame renders as an empty document. Raw HTML is not rendered. Use ordinary Markdown image syntax with a frame\'s canonical WebP path to embed its current rendering:\n\n```md\n\n```\n\nAn absolute canonical WebP URL from the same project is equivalent. A Markdown document may embed up to 32 existing GLTS, image, or Market frames. It may not embed itself or another Markdown frame. Use the canonical syntax instead of copying a screenshot URL or source asset so the document follows later frame changes.\n\nPrefer focused Markdown frames. A document that covers separable topics is usually clearer as multiple frames connected with canonical links, `[Related details](/<frame-id>/)`, because readers can navigate directly to the part they need. An embedded frame is useful when its current rendering adds visual context; a link is better when the reader only needs to navigate.\n\n## Comments and annotations\n\nUse comments for review conversations and persistent annotations, including explanations of objects or regions inside 2D and 3D frames. Inspect the current comments before replying, resolving, reopening, or deleting so the action targets the current thread.\n\nA comment without a position applies to its frame. A 2D position is normalized image space and applies only to an image frame. A 3D position is GLTS world space and applies only to a GLTS frame. Add a position only when its coordinates are authoritative; never infer 3D depth from a screenshot. Prefer a frame-level comment when the precise position is unknown.\n\nPositioned comments retain the frame version on which they were placed. If the frame later changes, treat the position as potentially stale and re-inspect the frame before relying on it. Replies belong to the root comment\'s thread. Resolved threads do not accept replies, so reopen one before continuing it. Resolve a thread when its concern has been addressed. Delete a comment or reply only when explicitly requested because deletion is permanent; deleting a root also deletes its replies. Comment authors come from the authenticated Drawcall account—never invent an author identity.\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, exportless TypeScript ESM script that builds a native `THREE.Scene` through contextual values from `@drawcall/glts`:\n\n```ts\nimport * as THREE from "three";\nimport { onDispose, scene } from "@drawcall/glts";\n\nconst geometry = new THREE.BoxGeometry();\nconst material = new THREE.MeshStandardMaterial({ color: "orange" });\nscene.add(new THREE.Mesh(geometry, material));\n\nonDispose(() => {\n geometry.dispose();\n material.dispose();\n});\n```\n\nUse named contextual imports: `gltsLoader`, `instanceCount`, `isPreview`, `loadingManager`, `onDispose`, `onFrame`, `onMatrixUpdateAt`, and `scene`. Do not export anything or import `GLTSLoader` or `GLTSRenderer`; the host owns loading and rendering. The script may import `three`, Three addons, and browser-compatible npm packages, but not static `.glts` imports, dynamic imports, import attributes, or sibling `.ts` helpers.\n\nThe host owns the root `scene` transform. Put authored placement and animation under child objects instead of changing the root scene\'s transform.\n\n### Composition and placeholders\n\nCompose another `.glts` file with the contextual loader and an explicit URL. Every loaded child must be added beneath `scene` before the script finishes:\n\n```ts\nimport * as THREE from "three";\nimport { gltsLoader, scene } from "@drawcall/glts";\n\nconst wheel = await gltsLoader.loadAsync(\n new URL("./parts/wheel.glts", import.meta.url),\n);\nwheel.position.set(0.8, 0.4, 1.3);\nscene.add(wheel);\n```\n\nFor a 3D object, create the frame with its complete `index.glts` first. When a referenced `.glts` file does not exist yet, give its URL specifier a rough bounding box in `imports`; Design creates a visible placeholder at that path. Then write each placeholder file one call at a time, the most visible first, and take a screenshot once none remain. A nested file that loads another missing file declares that file\'s box on its own write.\n\nUse relative URLs within a frame. A reusable 3D asset belongs in another frame; load its root by project-absolute URL instead of copying its source:\n\n```ts\nconst chassis = await gltsLoader.loadAsync(\n new URL("/other-frame-id/index.glts", import.meta.url),\n);\nscene.add(chassis);\n```\n\nDo not register `child.dispose()` with `onDispose`; attached GLTS children are owned and disposed recursively. Avoid cyclic loads. Use `loadInstancesAsync(url, count)` for a static mesh hierarchy when repeated copies matter; animated, nested, skinned, or already-instanced content needs native instancing with `instanceCount` and `onMatrixUpdateAt`.\n\n### Resources, updates, and cleanup\n\nFor a non-GLTS file from an image or Market frame, resolve its 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\nPass the contextual `loadingManager` to Three.js loaders during script evaluation so the frame waits for their requests and surfaces failures. Three.js loaders take URL strings; GLTS loader methods accept the `URL` itself. Top-level `await` is supported. Do not start loads from frame, matrix, timer, event, or effect callbacks because the loading scope has closed.\n\n```ts\nimport * as THREE from "three";\nimport { loadingManager, scene } from "@drawcall/glts";\nimport { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";\n\nconst model = await new GLTFLoader(loadingManager).loadAsync(\n new URL("./car.glb", import.meta.url).href,\n);\nscene.add(model.scene);\n```\n\nRelease only resources the script creates. GLTS recursively disposes managed child scenes but does not infer geometry, material, texture, or listener ownership. Close disposal callbacks over the owned values rather than traversing the imported `scene`, whose live binding follows the new revision during reload.\n\nUse `onFrame((delta) => ...)` for animation. Design advances the loaded root every frame, including managed descendants. A failed reload leaves the previous scene mounted.\n\n### Root presentation\n\nNative scene properties such as `scene.background`, `scene.environment`, `scene.fog`, and `scene.overrideMaterial` describe the asset when it is the render root. Assign `scene.defaultCamera` to recommend an authored view; a saved Design frame camera still overrides it. Design autofits the scene when neither exists.\n\nUse `isPreview` for staging that belongs only in the standalone Design frame, such as a floor, light rig, background, fog, or presentation effects. Design loads each displayed root in preview mode; nested GLTS scenes always receive `isPreview === false`, so their presentation does not leak into composition. Keep intrinsic content and each mesh\'s `castShadow` setting outside this block.\n\n```ts\nimport * as THREE from "three";\nimport { isPreview, onDispose, scene } from "@drawcall/glts";\nimport { UnrealBloomPass } from "three/addons/postprocessing/UnrealBloomPass.js";\n\nscene.defaultCamera = new THREE.PerspectiveCamera(35, 1, 0.1, 100);\nscene.defaultCamera.position.set(4, 3, 6);\nscene.defaultCamera.lookAt(0, 1, 0);\n\nif (isPreview) {\n const floor = new THREE.Mesh(\n new THREE.CircleGeometry(20),\n new THREE.MeshStandardMaterial({ color: "#333333" }),\n );\n floor.rotation.x = -Math.PI / 2;\n floor.receiveShadow = true;\n const light = new THREE.DirectionalLight("white", 3);\n light.position.set(4, 6, 3);\n light.castShadow = true;\n\n scene.background = new THREE.Color("#171b2b");\n scene.add(light, light.target, floor);\n scene.rendering.shadows = true;\n scene.rendering.toneMapping = THREE.ACESFilmicToneMapping;\n scene.rendering.toneMappingExposure = 1.1;\n scene.rendering.effects.push(\n ({ height, width }) =>\n new UnrealBloomPass(new THREE.Vector2(width, height), 0.3, 0.4, 0.85),\n );\n\n onDispose(() => {\n light.dispose();\n floor.geometry.dispose();\n floor.material.dispose();\n });\n}\n```\n\n`scene.rendering` supports shadows, clipping planes, tone mapping, exposure, and post-processing effect factories. A factory returns a fresh Three.js `Pass`; do not add `RenderPass` or `OutputPass`, load resources there, or dispose the returned pass yourself. The host renderer owns those passes. Visible shadows require renderer shadows plus a shadow-casting light, casting meshes, and receiving surfaces.\n\nPresentation belongs only to the root. A nested scene\'s background, environment, fog, default camera, and rendering profile do not override its parent.\n\n### Verification\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 GLTS scenes, Markdown documents, and image or Market references in Drawcall Design. Use whenever the user names Drawcall Design or one of its projects, canvases, frames, filesystems, GLTS assets, or Markdown frames. Do not use for full games, applications, or unrelated image generation.\n---\n\n# Drawcall Design\n\n## CLI transport\n\nThe commands below are the Drawcall transport in this environment. For Design operations, use only this documented command interface. A failed command does not make the transport unavailable.\n\nImage frame creation and image-generation references accept public HTTP(S) URLs or local PNG, JPEG, and WebP files.\n\nSelect the project with `-p <project-id>`. File commands take project-absolute paths that include the frame ID. Repeat `--reference` to preserve image-generation reference order.\n\n```sh\nnpx drawcall design project list\nnpx drawcall design -p r6z2n9k4x8m1qc frame list\nnpx drawcall design -p r6z2n9k4x8m1qc frame create Racecar --type glts --size 1280x800 --import ./parts/wheel.glts=-0.5,0,-0.5:0.5,1,0.5 --text - <<\'GLTS\'\nimport { gltsLoader, scene } from "@drawcall/glts";\n\nconst wheel = await gltsLoader.loadAsync(\n new URL("./parts/wheel.glts", import.meta.url),\n);\nscene.add(wheel);\nGLTS\nnpx drawcall design -p r6z2n9k4x8m1qc write /a4z8m2q7v9kcde/parts/wheel.glts - <<\'GLTS\'\nimport * as THREE from "three";\nimport { onDispose, scene } from "@drawcall/glts";\n\nconst geometry = new THREE.TorusGeometry(0.4, 0.12, 16, 48);\nconst material = new THREE.MeshStandardMaterial({ color: 0x222222 });\nscene.add(new THREE.Mesh(geometry, material));\n\nonDispose(() => {\n geometry.dispose();\n material.dispose();\n});\nGLTS\nnpx drawcall design -p r6z2n9k4x8m1qc frame preview a4z8m2q7v9kcde\nnpx drawcall design -p r6z2n9k4x8m1qc frame screenshot a4z8m2q7v9kcde\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\'\nnpx drawcall design -p r6z2n9k4x8m1qc comment list a4z8m2q7v9kcde\nnpx drawcall design -p r6z2n9k4x8m1qc comment show c4z8m2q7v9kcdf\nnpx drawcall design -p r6z2n9k4x8m1qc comment create a4z8m2q7v9kcde \'The bevel catches the key light here.\' --position-3d 0.2,1.1,-0.4\nnpx drawcall design -p r6z2n9k4x8m1qc comment reply c4z8m2q7v9kcdf \'Adjusted the material roughness.\'\nnpx drawcall design -p r6z2n9k4x8m1qc comment resolve c4z8m2q7v9kcdf\nnpx drawcall design -p r6z2n9k4x8m1qc comment delete c4z8m2q7v9kcdf --yes\nnpx drawcall design -p r6z2n9k4x8m1qc frame generate-image \'Product photograph\' --prompt \'A product photograph of this object\' --reference https://r6z2n9k4x8m1qc.design.drawcallcontent.com/a4z8m2q7v9kcde.webp\nnpx drawcall design -p r6z2n9k4x8m1qc frame edit-image b4z8m2q7v9kcdf --prompt \'Use warmer light\' --name \'Warm product photograph\' --reference ./lighting.webp\n```\n\n`frame create --text`, `write`, comment create, and reply text accept `-` to read the text from stdin; a quoted heredoc keeps multi-line source intact. `--import <specifier>=<min>:<max>` declares the bounding box of a contextually loaded `.glts` file that does not exist yet, as `x,y,z:x,y,z`, and may repeat. Run one file write per command invocation, never several in one shell command. Use `--position-2d x,y` only for normalized image coordinates and `--position-3d x,y,z` only for authoritative GLTS world coordinates.\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 mutable labels. In user-facing replies, refer to projects, frames, and other named resources by their current names. Do not expose their IDs unless the user explicitly asks for them; IDs may remain embedded in URLs that link to those resources.\n\nWe recommend using Drawcall Market when a design needs 3D assets such as models, textures, or environments.\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, Markdown for a formatted text document, image for an existing 2D image, and Market only for an exact public asset reference, `name@version`. GLTS and Markdown frames require a viewport size; image and Market frames derive their canvas size. A GLTS or Markdown frame accepts its root file at creation.\n\nRead a file before editing it. Use a narrow edit for one known change and write a complete file when replacing it. GLTS and Markdown frame files may be created or deleted. Image and Market frame files are read-only.\n\n## Frame previews\n\nEvery frame has a canonical public WebP preview in `previewUrl` at `https://<project-id>.design.drawcallcontent.com/<frame-id>.webp`, whether its type is GLTS, Markdown, image, or Market. `frame preview <frame-id>` prints that URL. Use `frame screenshot` only when a fresh PNG render is required. Pass a preview URL with `--reference` when one frame\'s appearance should inform another image. A reference may instead be a local PNG, JPEG, or WebP file.\n\n## Markdown documents\n\nA Markdown frame contains one optional source file at `/<frame-id>/index.md`; without it the frame renders as an empty document. Raw HTML is not rendered. Use ordinary Markdown image syntax with a frame\'s canonical WebP path to embed its current rendering:\n\n```md\n\n```\n\nAn absolute canonical WebP URL from the same project is equivalent. A Markdown document may embed up to 32 existing GLTS, image, or Market frames. It may not embed itself or another Markdown frame. Use the canonical syntax instead of copying a screenshot URL or source asset so the document follows later frame changes.\n\nPrefer focused Markdown frames. A document that covers separable topics is usually clearer as multiple frames connected with canonical links, `[Related details](/<frame-id>/)`, because readers can navigate directly to the part they need. An embedded frame is useful when its current rendering adds visual context; a link is better when the reader only needs to navigate.\n\n## Comments and annotations\n\nUse comments for review conversations and persistent annotations, including explanations of objects or regions inside 2D and 3D frames. Inspect the current comments before replying, resolving, reopening, or deleting so the action targets the current thread.\n\nA comment without a position applies to its frame. A 2D position is normalized image space and applies only to an image frame. A 3D position is GLTS world space and applies only to a GLTS frame. Add a position only when its coordinates are authoritative; never infer 3D depth from a screenshot. Prefer a frame-level comment when the precise position is unknown.\n\nPositioned comments retain the frame version on which they were placed. If the frame later changes, treat the position as potentially stale and re-inspect the frame before relying on it. Replies belong to the root comment\'s thread. Resolved threads do not accept replies, so reopen one before continuing it. Resolve a thread when its concern has been addressed. Delete a comment or reply only when explicitly requested because deletion is permanent; deleting a root also deletes its replies. Comment authors come from the authenticated Drawcall account—never invent an author identity.\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, exportless TypeScript ESM script that builds a native `THREE.Scene` through contextual values from `@drawcall/glts`:\n\n```ts\nimport * as THREE from "three";\nimport { onDispose, scene } from "@drawcall/glts";\n\nconst geometry = new THREE.BoxGeometry();\nconst material = new THREE.MeshStandardMaterial({ color: "orange" });\nscene.add(new THREE.Mesh(geometry, material));\n\nonDispose(() => {\n geometry.dispose();\n material.dispose();\n});\n```\n\nUse named contextual imports: `gltsLoader`, `instanceCount`, `isPreview`, `loadingManager`, `onDispose`, `onFrame`, `onMatrixUpdateAt`, and `scene`. Do not export anything or import `GLTSLoader` or `GLTSRenderer`; the host owns loading and rendering. The script may import `three`, Three addons, and browser-compatible npm packages, but not static `.glts` imports, dynamic imports, import attributes, or sibling `.ts` helpers.\n\nThe host owns the root `scene` transform. Put authored placement and animation under child objects instead of changing the root scene\'s transform.\n\n### Composition and placeholders\n\nCompose another `.glts` file with the contextual loader and an explicit URL. Every loaded child must be added beneath `scene` before the script finishes:\n\n```ts\nimport * as THREE from "three";\nimport { gltsLoader, scene } from "@drawcall/glts";\n\nconst wheel = await gltsLoader.loadAsync(\n new URL("./parts/wheel.glts", import.meta.url),\n);\nwheel.position.set(0.8, 0.4, 1.3);\nscene.add(wheel);\n```\n\nFor a 3D object, create the frame with its complete `index.glts` first. When a referenced `.glts` file does not exist yet, give its URL specifier a rough bounding box in `imports`; Design creates a visible placeholder at that path. Then write each placeholder file one call at a time, the most visible first, and take a screenshot once none remain. A nested file that loads another missing file declares that file\'s box on its own write.\n\nUse relative URLs within a frame. A reusable 3D asset belongs in another frame; load its root by project-absolute URL instead of copying its source:\n\n```ts\nconst chassis = await gltsLoader.loadAsync(\n new URL("/other-frame-id/index.glts", import.meta.url),\n);\nscene.add(chassis);\n```\n\nDo not register `child.dispose()` with `onDispose`; attached GLTS children are owned and disposed recursively. Avoid cyclic loads. Use `loadInstancesAsync(url, count)` for a static mesh hierarchy when repeated copies matter; animated, nested, skinned, or already-instanced content needs native instancing with `instanceCount` and `onMatrixUpdateAt`.\n\n### Resources, updates, and cleanup\n\nFor a non-GLTS file from an image or Market frame, resolve its 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\nPass the contextual `loadingManager` to Three.js loaders during script evaluation so the frame waits for their requests and surfaces failures. Three.js loaders take URL strings; GLTS loader methods accept the `URL` itself. Top-level `await` is supported. Do not start loads from frame, matrix, timer, event, or effect callbacks because the loading scope has closed.\n\n```ts\nimport * as THREE from "three";\nimport { loadingManager, scene } from "@drawcall/glts";\nimport { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";\n\nconst model = await new GLTFLoader(loadingManager).loadAsync(\n new URL("./car.glb", import.meta.url).href,\n);\nscene.add(model.scene);\n```\n\nRelease only resources the script creates. GLTS recursively disposes managed child scenes but does not infer geometry, material, texture, or listener ownership. Close disposal callbacks over the owned values rather than traversing the imported `scene`, whose live binding follows the new revision during reload.\n\nUse `onFrame((delta) => ...)` for animation. Design advances the loaded root every frame, including managed descendants. A failed reload leaves the previous scene mounted.\n\n### Root presentation\n\nNative scene properties such as `scene.background`, `scene.environment`, `scene.fog`, and `scene.overrideMaterial` describe the asset when it is the render root. Assign `scene.defaultCamera` to recommend an authored view; a saved Design frame camera still overrides it. Design autofits the scene when neither exists.\n\nUse `isPreview` for staging that belongs only in the standalone Design frame, such as a floor, light rig, background, fog, or presentation effects. Design loads each displayed root in preview mode; nested GLTS scenes always receive `isPreview === false`, so their presentation does not leak into composition. Keep intrinsic content and each mesh\'s `castShadow` setting outside this block.\n\n```ts\nimport * as THREE from "three";\nimport { isPreview, onDispose, scene } from "@drawcall/glts";\nimport { UnrealBloomPass } from "three/addons/postprocessing/UnrealBloomPass.js";\n\nscene.defaultCamera = new THREE.PerspectiveCamera(35, 1, 0.1, 100);\nscene.defaultCamera.position.set(4, 3, 6);\nscene.defaultCamera.lookAt(0, 1, 0);\n\nif (isPreview) {\n const floor = new THREE.Mesh(\n new THREE.CircleGeometry(20),\n new THREE.MeshStandardMaterial({ color: "#333333" }),\n );\n floor.rotation.x = -Math.PI / 2;\n floor.receiveShadow = true;\n const light = new THREE.DirectionalLight("white", 3);\n light.position.set(4, 6, 3);\n light.castShadow = true;\n\n scene.background = new THREE.Color("#171b2b");\n scene.add(light, light.target, floor);\n scene.rendering.shadows = true;\n scene.rendering.toneMapping = THREE.ACESFilmicToneMapping;\n scene.rendering.toneMappingExposure = 1.1;\n scene.rendering.effects.push(\n ({ height, width }) =>\n new UnrealBloomPass(new THREE.Vector2(width, height), 0.3, 0.4, 0.85),\n );\n\n onDispose(() => {\n light.dispose();\n floor.geometry.dispose();\n floor.material.dispose();\n });\n}\n```\n\n`scene.rendering` supports shadows, clipping planes, tone mapping, exposure, and post-processing effect factories. A factory returns a fresh Three.js `Pass`; do not add `RenderPass` or `OutputPass`, load resources there, or dispose the returned pass yourself. The host renderer owns those passes. Visible shadows require renderer shadows plus a shadow-casting light, casting meshes, and receiving surfaces.\n\nPresentation belongs only to the root. A nested scene\'s background, environment, fog, default camera, and rendering profile do not override its parent.\n\n### Verification\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';
|
package/package.json
CHANGED
|
@@ -17,24 +17,25 @@ Select the project with `-p <project-id>`. File commands take project-absolute p
|
|
|
17
17
|
npx drawcall design project list
|
|
18
18
|
npx drawcall design -p r6z2n9k4x8m1qc frame list
|
|
19
19
|
npx drawcall design -p r6z2n9k4x8m1qc frame create Racecar --type glts --size 1280x800 --import ./parts/wheel.glts=-0.5,0,-0.5:0.5,1,0.5 --text - <<'GLTS'
|
|
20
|
-
import
|
|
21
|
-
import Wheel from "./parts/wheel.glts";
|
|
20
|
+
import { gltsLoader, scene } from "@drawcall/glts";
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
}
|
|
22
|
+
const wheel = await gltsLoader.loadAsync(
|
|
23
|
+
new URL("./parts/wheel.glts", import.meta.url),
|
|
24
|
+
);
|
|
25
|
+
scene.add(wheel);
|
|
29
26
|
GLTS
|
|
30
27
|
npx drawcall design -p r6z2n9k4x8m1qc write /a4z8m2q7v9kcde/parts/wheel.glts - <<'GLTS'
|
|
31
28
|
import * as THREE from "three";
|
|
29
|
+
import { onDispose, scene } from "@drawcall/glts";
|
|
32
30
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
const geometry = new THREE.TorusGeometry(0.4, 0.12, 16, 48);
|
|
32
|
+
const material = new THREE.MeshStandardMaterial({ color: 0x222222 });
|
|
33
|
+
scene.add(new THREE.Mesh(geometry, material));
|
|
34
|
+
|
|
35
|
+
onDispose(() => {
|
|
36
|
+
geometry.dispose();
|
|
37
|
+
material.dispose();
|
|
38
|
+
});
|
|
38
39
|
GLTS
|
|
39
40
|
npx drawcall design -p r6z2n9k4x8m1qc frame preview a4z8m2q7v9kcde
|
|
40
41
|
npx drawcall design -p r6z2n9k4x8m1qc frame screenshot a4z8m2q7v9kcde
|
|
@@ -51,7 +52,7 @@ npx drawcall design -p r6z2n9k4x8m1qc frame generate-image 'Product photograph'
|
|
|
51
52
|
npx drawcall design -p r6z2n9k4x8m1qc frame edit-image b4z8m2q7v9kcdf --prompt 'Use warmer light' --name 'Warm product photograph' --reference ./lighting.webp
|
|
52
53
|
```
|
|
53
54
|
|
|
54
|
-
`frame create --text`, `write`, comment create, and reply text accept `-` to read the text from stdin; a quoted heredoc keeps multi-line source intact. `--import <specifier>=<min>:<max>` declares the bounding box of
|
|
55
|
+
`frame create --text`, `write`, comment create, and reply text accept `-` to read the text from stdin; a quoted heredoc keeps multi-line source intact. `--import <specifier>=<min>:<max>` declares the bounding box of a contextually loaded `.glts` file that does not exist yet, as `x,y,z:x,y,z`, and may repeat. Run one file write per command invocation, never several in one shell command. Use `--position-2d x,y` only for normalized image coordinates and `--position-3d x,y,z` only for authoritative GLTS world coordinates.
|
|
55
56
|
|
|
56
57
|
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 mutable labels. In user-facing replies, refer to projects, frames, and other named resources by their current names. Do not expose their IDs unless the user explicitly asks for them; IDs may remain embedded in URLs that link to those resources.
|
|
57
58
|
|
|
@@ -95,82 +96,127 @@ An error means the requested operation did not happen. Follow its next action wi
|
|
|
95
96
|
|
|
96
97
|
## GLTS assets
|
|
97
98
|
|
|
98
|
-
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
|
|
99
|
+
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, exportless TypeScript ESM script that builds a native `THREE.Scene` through contextual values from `@drawcall/glts`:
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
import * as THREE from "three";
|
|
103
|
+
import { onDispose, scene } from "@drawcall/glts";
|
|
104
|
+
|
|
105
|
+
const geometry = new THREE.BoxGeometry();
|
|
106
|
+
const material = new THREE.MeshStandardMaterial({ color: "orange" });
|
|
107
|
+
scene.add(new THREE.Mesh(geometry, material));
|
|
108
|
+
|
|
109
|
+
onDispose(() => {
|
|
110
|
+
geometry.dispose();
|
|
111
|
+
material.dispose();
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Use named contextual imports: `gltsLoader`, `instanceCount`, `isPreview`, `loadingManager`, `onDispose`, `onFrame`, `onMatrixUpdateAt`, and `scene`. Do not export anything or import `GLTSLoader` or `GLTSRenderer`; the host owns loading and rendering. The script may import `three`, Three addons, and browser-compatible npm packages, but not static `.glts` imports, dynamic imports, import attributes, or sibling `.ts` helpers.
|
|
116
|
+
|
|
117
|
+
The host owns the root `scene` transform. Put authored placement and animation under child objects instead of changing the root scene's transform.
|
|
118
|
+
|
|
119
|
+
### Composition and placeholders
|
|
99
120
|
|
|
100
|
-
|
|
121
|
+
Compose another `.glts` file with the contextual loader and an explicit URL. Every loaded child must be added beneath `scene` before the script finishes:
|
|
101
122
|
|
|
102
123
|
```ts
|
|
103
124
|
import * as THREE from "three";
|
|
104
|
-
import
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
for (const [x, z] of [
|
|
112
|
-
[-0.8, 1.3],
|
|
113
|
-
[0.8, 1.3],
|
|
114
|
-
[-0.8, -1.3],
|
|
115
|
-
[0.8, -1.3],
|
|
116
|
-
]) {
|
|
117
|
-
const wheel = new Wheel();
|
|
118
|
-
wheel.position.set(x, 0.4, z);
|
|
119
|
-
this.add(wheel);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
125
|
+
import { gltsLoader, scene } from "@drawcall/glts";
|
|
126
|
+
|
|
127
|
+
const wheel = await gltsLoader.loadAsync(
|
|
128
|
+
new URL("./parts/wheel.glts", import.meta.url),
|
|
129
|
+
);
|
|
130
|
+
wheel.position.set(0.8, 0.4, 1.3);
|
|
131
|
+
scene.add(wheel);
|
|
123
132
|
```
|
|
124
133
|
|
|
125
|
-
|
|
134
|
+
For a 3D object, create the frame with its complete `index.glts` first. When a referenced `.glts` file does not exist yet, give its URL specifier a rough bounding box in `imports`; Design creates a visible placeholder at that path. Then write each placeholder file one call at a time, the most visible first, and take a screenshot once none remain. A nested file that loads another missing file declares that file's box on its own write.
|
|
135
|
+
|
|
136
|
+
Use relative URLs within a frame. A reusable 3D asset belongs in another frame; load its root by project-absolute URL instead of copying its source:
|
|
126
137
|
|
|
127
138
|
```ts
|
|
128
|
-
|
|
139
|
+
const chassis = await gltsLoader.loadAsync(
|
|
140
|
+
new URL("/other-frame-id/index.glts", import.meta.url),
|
|
141
|
+
);
|
|
142
|
+
scene.add(chassis);
|
|
129
143
|
```
|
|
130
144
|
|
|
131
|
-
|
|
145
|
+
Do not register `child.dispose()` with `onDispose`; attached GLTS children are owned and disposed recursively. Avoid cyclic loads. Use `loadInstancesAsync(url, count)` for a static mesh hierarchy when repeated copies matter; animated, nested, skinned, or already-instanced content needs native instancing with `instanceCount` and `onMatrixUpdateAt`.
|
|
146
|
+
|
|
147
|
+
### Resources, updates, and cleanup
|
|
148
|
+
|
|
149
|
+
For a non-GLTS file from an image or Market frame, resolve its project filesystem URL through `import.meta.url`:
|
|
132
150
|
|
|
133
151
|
```ts
|
|
134
152
|
const modelUrl = new URL("/market-frame-id/models/car.glb", import.meta.url);
|
|
135
153
|
```
|
|
136
154
|
|
|
137
|
-
|
|
155
|
+
Pass the contextual `loadingManager` to Three.js loaders during script evaluation so the frame waits for their requests and surfaces failures. Three.js loaders take URL strings; GLTS loader methods accept the `URL` itself. Top-level `await` is supported. Do not start loads from frame, matrix, timer, event, or effect callbacks because the loading scope has closed.
|
|
138
156
|
|
|
139
157
|
```ts
|
|
140
158
|
import * as THREE from "three";
|
|
141
|
-
import { loadingManager } from "@drawcall/glts";
|
|
159
|
+
import { loadingManager, scene } from "@drawcall/glts";
|
|
142
160
|
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
|
|
143
161
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
new URL("./car.glb", import.meta.url).href,
|
|
149
|
-
({ scene }) => this.add(scene),
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
162
|
+
const model = await new GLTFLoader(loadingManager).loadAsync(
|
|
163
|
+
new URL("./car.glb", import.meta.url).href,
|
|
164
|
+
);
|
|
165
|
+
scene.add(model.scene);
|
|
153
166
|
```
|
|
154
167
|
|
|
155
|
-
|
|
168
|
+
Release only resources the script creates. GLTS recursively disposes managed child scenes but does not infer geometry, material, texture, or listener ownership. Close disposal callbacks over the owned values rather than traversing the imported `scene`, whose live binding follows the new revision during reload.
|
|
156
169
|
|
|
157
|
-
|
|
170
|
+
Use `onFrame((delta) => ...)` for animation. Design advances the loaded root every frame, including managed descendants. A failed reload leaves the previous scene mounted.
|
|
158
171
|
|
|
159
|
-
|
|
160
|
-
import * as THREE from "three";
|
|
172
|
+
### Root presentation
|
|
161
173
|
|
|
162
|
-
|
|
163
|
-
previewCamera.position.set(4, 3, 6);
|
|
164
|
-
previewCamera.lookAt(0, 0, 0);
|
|
174
|
+
Native scene properties such as `scene.background`, `scene.environment`, `scene.fog`, and `scene.overrideMaterial` describe the asset when it is the render root. Assign `scene.defaultCamera` to recommend an authored view; a saved Design frame camera still overrides it. Design autofits the scene when neither exists.
|
|
165
175
|
|
|
166
|
-
|
|
167
|
-
previewLighting.add(new THREE.HemisphereLight(0xffffff, 0x223344, 2));
|
|
176
|
+
Use `isPreview` for staging that belongs only in the standalone Design frame, such as a floor, light rig, background, fog, or presentation effects. Design loads each displayed root in preview mode; nested GLTS scenes always receive `isPreview === false`, so their presentation does not leak into composition. Keep intrinsic content and each mesh's `castShadow` setting outside this block.
|
|
168
177
|
|
|
169
|
-
|
|
170
|
-
|
|
178
|
+
```ts
|
|
179
|
+
import * as THREE from "three";
|
|
180
|
+
import { isPreview, onDispose, scene } from "@drawcall/glts";
|
|
181
|
+
import { UnrealBloomPass } from "three/addons/postprocessing/UnrealBloomPass.js";
|
|
182
|
+
|
|
183
|
+
scene.defaultCamera = new THREE.PerspectiveCamera(35, 1, 0.1, 100);
|
|
184
|
+
scene.defaultCamera.position.set(4, 3, 6);
|
|
185
|
+
scene.defaultCamera.lookAt(0, 1, 0);
|
|
186
|
+
|
|
187
|
+
if (isPreview) {
|
|
188
|
+
const floor = new THREE.Mesh(
|
|
189
|
+
new THREE.CircleGeometry(20),
|
|
190
|
+
new THREE.MeshStandardMaterial({ color: "#333333" }),
|
|
191
|
+
);
|
|
192
|
+
floor.rotation.x = -Math.PI / 2;
|
|
193
|
+
floor.receiveShadow = true;
|
|
194
|
+
const light = new THREE.DirectionalLight("white", 3);
|
|
195
|
+
light.position.set(4, 6, 3);
|
|
196
|
+
light.castShadow = true;
|
|
197
|
+
|
|
198
|
+
scene.background = new THREE.Color("#171b2b");
|
|
199
|
+
scene.add(light, light.target, floor);
|
|
200
|
+
scene.rendering.shadows = true;
|
|
201
|
+
scene.rendering.toneMapping = THREE.ACESFilmicToneMapping;
|
|
202
|
+
scene.rendering.toneMappingExposure = 1.1;
|
|
203
|
+
scene.rendering.effects.push(
|
|
204
|
+
({ height, width }) =>
|
|
205
|
+
new UnrealBloomPass(new THREE.Vector2(width, height), 0.3, 0.4, 0.85),
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
onDispose(() => {
|
|
209
|
+
light.dispose();
|
|
210
|
+
floor.geometry.dispose();
|
|
211
|
+
floor.material.dispose();
|
|
212
|
+
});
|
|
171
213
|
}
|
|
172
214
|
```
|
|
173
215
|
|
|
174
|
-
|
|
216
|
+
`scene.rendering` supports shadows, clipping planes, tone mapping, exposure, and post-processing effect factories. A factory returns a fresh Three.js `Pass`; do not add `RenderPass` or `OutputPass`, load resources there, or dispose the returned pass yourself. The host renderer owns those passes. Visible shadows require renderer shadows plus a shadow-casting light, casting meshes, and receiving surfaces.
|
|
217
|
+
|
|
218
|
+
Presentation belongs only to the root. A nested scene's background, environment, fog, default camera, and rendering profile do not override its parent.
|
|
219
|
+
|
|
220
|
+
### Verification
|
|
175
221
|
|
|
176
222
|
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.
|