rtistree 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/CONTRIBUTING.md +47 -0
- package/README.md +38 -22
- package/SECURITY.md +20 -0
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/dist/art-direction.js +1 -1
- package/dist/cli.js +55 -32
- package/dist/cli.js.map +1 -1
- package/dist/commands.d.ts +12 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +18 -2
- package/dist/mcp.js.map +1 -1
- package/dist/print-scene.d.ts +6 -0
- package/dist/program.js +3 -1
- package/dist/program.js.map +1 -1
- package/dist/project-config.js +2 -1
- package/dist/project-config.js.map +1 -1
- package/dist/render.js +21 -1
- package/dist/render.js.map +1 -1
- package/dist/schema.d.ts +46 -0
- package/dist/schema.js +107 -0
- package/dist/schema.js.map +1 -1
- package/dist/sprites.d.ts +31 -0
- package/dist/sprites.js +142 -0
- package/dist/sprites.js.map +1 -0
- package/dist/starter.d.ts +7 -0
- package/dist/starter.js +38 -0
- package/dist/starter.js.map +1 -0
- package/dist/studio-reference.js +1 -1
- package/dist/studio-reference.js.map +1 -1
- package/docs/agent-art-workflow.md +12 -2
- package/docs/agent-setup.md +12 -7
- package/docs/atelier.md +15 -4
- package/docs/cli-reference.md +89 -26
- package/docs/core-concepts.md +95 -0
- package/docs/decisions/004-print-production-and-projects.md +1 -1
- package/docs/decisions/005-programmable-digital-art.md +1 -1
- package/docs/engine-overview.md +121 -165
- package/docs/evolution.md +12 -9
- package/docs/getting-started.md +84 -53
- package/docs/next-milestone.md +9 -9
- package/docs/production.md +22 -16
- package/docs/releasing.md +99 -43
- package/docs/scene-format.md +45 -8
- package/docs/sprites.md +166 -0
- package/docs/studio.md +27 -12
- package/examples/hello/README.md +24 -8
- package/examples/hello/render.mjs +2 -1
- package/package.json +10 -5
- package/schemas/authoring.schema.json +359 -229
- package/schemas/command.schema.json +462 -332
- package/schemas/patch.schema.json +462 -332
- package/schemas/scene.schema.json +347 -217
- package/schemas/sprites.schema.json +41 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { Project } from './project.js';
|
|
3
|
+
/** Controls the two portable artifacts written by exportSpriteSheet. */
|
|
4
|
+
export declare const spriteSheetOptionsSchema: z.ZodObject<{
|
|
5
|
+
manifest: z.ZodOptional<z.ZodString>;
|
|
6
|
+
atlas: z.ZodOptional<z.ZodObject<{
|
|
7
|
+
padding: z.ZodDefault<z.ZodNumber>;
|
|
8
|
+
extrusion: z.ZodDefault<z.ZodNumber>;
|
|
9
|
+
power_of_two: z.ZodDefault<z.ZodBoolean>;
|
|
10
|
+
max_width: z.ZodDefault<z.ZodNumber>;
|
|
11
|
+
}, z.core.$strict>>;
|
|
12
|
+
}, z.core.$strict>;
|
|
13
|
+
export type SpriteSheetOptions = z.infer<typeof spriteSheetOptionsSchema>;
|
|
14
|
+
/**
|
|
15
|
+
* Render declared canvas-frame sprites once and pack their exact RGBA pixels
|
|
16
|
+
* into a deterministic, engine-neutral PNG atlas and JSON manifest. Frames are
|
|
17
|
+
* intentionally not trimmed: their declared bounds and pivots remain stable.
|
|
18
|
+
*/
|
|
19
|
+
export declare function exportSpriteSheet(project: Project, output: string, raw?: unknown): Promise<{
|
|
20
|
+
image: string;
|
|
21
|
+
manifest: string;
|
|
22
|
+
width: number;
|
|
23
|
+
height: number;
|
|
24
|
+
frames: number;
|
|
25
|
+
animations: number;
|
|
26
|
+
evidence: {
|
|
27
|
+
scene_hash: string;
|
|
28
|
+
source_png_hash: string;
|
|
29
|
+
atlas_png_hash: string;
|
|
30
|
+
};
|
|
31
|
+
}>;
|
package/dist/sprites.js
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { extname, basename, resolve } from 'node:path';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { createCanvas } from './native.js';
|
|
4
|
+
import { writeArtifact } from './artifacts.js';
|
|
5
|
+
import { sceneHash, sha256 } from './assets.js';
|
|
6
|
+
import { spriteAtlasSchema } from './schema.js';
|
|
7
|
+
/** Controls the two portable artifacts written by exportSpriteSheet. */
|
|
8
|
+
export const spriteSheetOptionsSchema = z.strictObject({
|
|
9
|
+
manifest: z.string().min(1).max(2048).optional(),
|
|
10
|
+
atlas: spriteAtlasSchema.optional(),
|
|
11
|
+
});
|
|
12
|
+
function nextPowerOfTwo(value) {
|
|
13
|
+
let result = 1;
|
|
14
|
+
while (result < value)
|
|
15
|
+
result *= 2;
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
function packFrames(sprites, atlas) {
|
|
19
|
+
const margin = atlas.padding + atlas.extrusion;
|
|
20
|
+
const frames = Object.entries(sprites.frames)
|
|
21
|
+
.map(([id, frame]) => ({
|
|
22
|
+
id,
|
|
23
|
+
width: frame.bounds[2] + margin * 2,
|
|
24
|
+
height: frame.bounds[3] + margin * 2,
|
|
25
|
+
}))
|
|
26
|
+
// The explicit sort means authored object ordering cannot change the atlas.
|
|
27
|
+
.sort((a, b) => b.height - a.height || b.width - a.width || a.id.localeCompare(b.id));
|
|
28
|
+
const widest = Math.max(...frames.map((frame) => frame.width));
|
|
29
|
+
// POT sheets start at the narrowest possible valid power of two. This can
|
|
30
|
+
// fit tall sparse sets that a square-root estimate would wrongly reject.
|
|
31
|
+
const minimum = atlas.power_of_two
|
|
32
|
+
? widest
|
|
33
|
+
: Math.max(widest, Math.ceil(Math.sqrt(frames.reduce((sum, frame) => sum + frame.width * frame.height, 0))));
|
|
34
|
+
if (minimum > atlas.max_width)
|
|
35
|
+
throw new Error('Sprite atlas frames exceed max_width');
|
|
36
|
+
let width = atlas.power_of_two ? nextPowerOfTwo(minimum) : minimum;
|
|
37
|
+
if (width > atlas.max_width)
|
|
38
|
+
throw new Error('Sprite atlas power-of-two width exceeds max_width');
|
|
39
|
+
while (true) {
|
|
40
|
+
let x = 0, y = 0, rowHeight = 0, usedWidth = 0;
|
|
41
|
+
const placements = [];
|
|
42
|
+
for (const frame of frames) {
|
|
43
|
+
if (x && x + frame.width > width) {
|
|
44
|
+
y += rowHeight;
|
|
45
|
+
x = 0;
|
|
46
|
+
rowHeight = 0;
|
|
47
|
+
}
|
|
48
|
+
if (y + frame.height > 8192)
|
|
49
|
+
break;
|
|
50
|
+
placements.push({ ...frame, x, y });
|
|
51
|
+
x += frame.width;
|
|
52
|
+
rowHeight = Math.max(rowHeight, frame.height);
|
|
53
|
+
usedWidth = Math.max(usedWidth, x);
|
|
54
|
+
}
|
|
55
|
+
if (placements.length === frames.length) {
|
|
56
|
+
const usedHeight = y + rowHeight;
|
|
57
|
+
const outputWidth = atlas.power_of_two ? width : usedWidth;
|
|
58
|
+
const outputHeight = atlas.power_of_two ? nextPowerOfTwo(usedHeight) : usedHeight;
|
|
59
|
+
if (outputWidth > 8192 || outputHeight > 8192)
|
|
60
|
+
throw new Error('Sprite atlas exceeds 8192 pixels');
|
|
61
|
+
return { placements, width: outputWidth, height: outputHeight };
|
|
62
|
+
}
|
|
63
|
+
const next = atlas.power_of_two
|
|
64
|
+
? width * 2
|
|
65
|
+
: Math.min(atlas.max_width, Math.max(width + 1, Math.ceil(width * 1.5)));
|
|
66
|
+
if (next > atlas.max_width || next === width)
|
|
67
|
+
throw new Error('Sprite atlas cannot fit within max_width and 8192-pixel height');
|
|
68
|
+
width = next;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function copyPixel(target, targetWidth, targetX, targetY, source, sourceWidth, sourceX, sourceY) {
|
|
72
|
+
const to = (targetY * targetWidth + targetX) * 4, from = (sourceY * sourceWidth + sourceX) * 4;
|
|
73
|
+
target.set(source.subarray(from, from + 4), to);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Render declared canvas-frame sprites once and pack their exact RGBA pixels
|
|
77
|
+
* into a deterministic, engine-neutral PNG atlas and JSON manifest. Frames are
|
|
78
|
+
* intentionally not trimmed: their declared bounds and pivots remain stable.
|
|
79
|
+
*/
|
|
80
|
+
export async function exportSpriteSheet(project, output, raw = {}) {
|
|
81
|
+
const options = spriteSheetOptionsSchema.parse(raw);
|
|
82
|
+
if (extname(output).toLowerCase() !== '.png')
|
|
83
|
+
throw new Error('Sprite atlas output must end in .png');
|
|
84
|
+
const image = resolve(output), manifest = resolve(options.manifest ?? output.replace(/\.png$/i, '.json'));
|
|
85
|
+
if (image === manifest)
|
|
86
|
+
throw new Error('Sprite atlas image and manifest must have different paths');
|
|
87
|
+
if (extname(manifest).toLowerCase() !== '.json')
|
|
88
|
+
throw new Error('Sprite atlas manifest must end in .json');
|
|
89
|
+
const scene = await project.scene(), sprites = scene.sprites;
|
|
90
|
+
if (!sprites)
|
|
91
|
+
throw new Error('Scene has no sprites manifest');
|
|
92
|
+
const atlas = spriteAtlasSchema.parse({ ...sprites.atlas, ...options.atlas }), packing = packFrames(sprites, atlas), render = await project.render({ quality: 'final', cache: false }), canvas = createCanvas(packing.width, packing.height), context = canvas.getContext('2d'), pixels = context.createImageData(packing.width, packing.height), records = {};
|
|
93
|
+
const placements = new Map(packing.placements.map((placement) => [placement.id, placement]));
|
|
94
|
+
for (const [id, frame] of Object.entries(sprites.frames)) {
|
|
95
|
+
const placement = placements.get(id);
|
|
96
|
+
const [sourceX, sourceY, width, height] = frame.bounds;
|
|
97
|
+
const x = placement.x + atlas.padding + atlas.extrusion, y = placement.y + atlas.padding + atlas.extrusion;
|
|
98
|
+
for (let py = 0; py < height; py++)
|
|
99
|
+
for (let px = 0; px < width; px++)
|
|
100
|
+
copyPixel(pixels.data, packing.width, x + px, y + py, render.pixels, render.width, sourceX + px, sourceY + py);
|
|
101
|
+
// Copy edge pixels into the extrusion ring. Padding outside this ring stays transparent.
|
|
102
|
+
for (let py = -atlas.extrusion; py < height + atlas.extrusion; py++)
|
|
103
|
+
for (let px = -atlas.extrusion; px < width + atlas.extrusion; px++) {
|
|
104
|
+
if (px >= 0 && py >= 0 && px < width && py < height)
|
|
105
|
+
continue;
|
|
106
|
+
copyPixel(pixels.data, packing.width, x + px, y + py, render.pixels, render.width, sourceX + Math.max(0, Math.min(width - 1, px)), sourceY + Math.max(0, Math.min(height - 1, py)));
|
|
107
|
+
}
|
|
108
|
+
records[id] = {
|
|
109
|
+
frame: [x, y, width, height],
|
|
110
|
+
source: frame.bounds,
|
|
111
|
+
pivot: frame.pivot,
|
|
112
|
+
duration: frame.duration,
|
|
113
|
+
tags: frame.tags,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
context.putImageData(pixels, 0, 0);
|
|
117
|
+
const png = await canvas.encode('png'), pngHash = sha256(png), document = {
|
|
118
|
+
format: 'rtistree-sprites@1',
|
|
119
|
+
image: basename(image),
|
|
120
|
+
size: [packing.width, packing.height],
|
|
121
|
+
frames: records,
|
|
122
|
+
animations: sprites.animations,
|
|
123
|
+
atlas: { ...atlas, packing: 'shelf-v1', trimmed: false, sampling: 'nearest' },
|
|
124
|
+
evidence: {
|
|
125
|
+
scene_hash: sceneHash(scene),
|
|
126
|
+
source_png_hash: render.evidence.render.png_hash,
|
|
127
|
+
atlas_png_hash: pngHash,
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
await writeArtifact(image, png);
|
|
131
|
+
await writeArtifact(manifest, JSON.stringify(document, null, 2) + '\n');
|
|
132
|
+
return {
|
|
133
|
+
image,
|
|
134
|
+
manifest,
|
|
135
|
+
width: packing.width,
|
|
136
|
+
height: packing.height,
|
|
137
|
+
frames: Object.keys(records).length,
|
|
138
|
+
animations: Object.keys(sprites.animations).length,
|
|
139
|
+
evidence: document.evidence,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=sprites.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sprites.js","sourceRoot":"","sources":["../src/sprites.ts"],"names":[],"mappings":"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"}
|
package/dist/starter.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { resolve, join } from 'node:path';
|
|
3
|
+
/** Create a starter in a new directory. Existing paths are never overwritten. */
|
|
4
|
+
export async function createStarter(directory) {
|
|
5
|
+
const destination = resolve(directory);
|
|
6
|
+
const names = ['scene.json', 'refine.json', 'render.mjs', 'README.md'];
|
|
7
|
+
const templates = await Promise.all(names.map(async (name) => [name, await readFile(new URL(`../examples/hello/${name}`, import.meta.url))]));
|
|
8
|
+
const { version } = JSON.parse(await readFile(new URL('../package.json', import.meta.url), 'utf8'));
|
|
9
|
+
const manifest = {
|
|
10
|
+
name: 'rtistree-artwork',
|
|
11
|
+
private: true,
|
|
12
|
+
type: 'module',
|
|
13
|
+
scripts: { render: 'rtistree render scene.json -o hello.png', 'render:sdk': 'node render.mjs' },
|
|
14
|
+
dependencies: { rtistree: version },
|
|
15
|
+
};
|
|
16
|
+
// mkdir is exclusive: reject files, directories and symlinks, even empty directories.
|
|
17
|
+
try {
|
|
18
|
+
await mkdir(destination);
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
if (error.code === 'EEXIST')
|
|
22
|
+
throw new Error(`Destination already exists: ${destination}. Choose a new directory.`);
|
|
23
|
+
throw error;
|
|
24
|
+
}
|
|
25
|
+
for (const [name, contents] of templates)
|
|
26
|
+
await writeFile(join(destination, name), contents, { flag: 'wx' });
|
|
27
|
+
await writeFile(join(destination, 'package.json'), JSON.stringify(manifest, null, 2) + '\n', {
|
|
28
|
+
flag: 'wx',
|
|
29
|
+
});
|
|
30
|
+
await writeFile(join(destination, '.gitignore'), 'node_modules/\nhistory/\n*.png\n*.evidence.json\n', { flag: 'wx' });
|
|
31
|
+
return {
|
|
32
|
+
directory: destination,
|
|
33
|
+
files: [...names, 'package.json', '.gitignore'],
|
|
34
|
+
next: ['Change into the created directory', 'npm install', 'npm run render'],
|
|
35
|
+
output: 'hello.png',
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=starter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"starter.js","sourceRoot":"","sources":["../src/starter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C,iFAAiF;AACjF,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,SAAiB;IACnD,MAAM,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,CAAC,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC;IACvE,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,GAAG,CACjC,KAAK,CAAC,GAAG,CACP,KAAK,EAAE,IAAI,EAAE,EAAE,CACb,CAAC,IAAI,EAAE,MAAM,QAAQ,CAAC,IAAI,GAAG,CAAC,qBAAqB,IAAI,EAAE,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAU,CACzF,CACF,CAAC;IACF,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,CAC5B,MAAM,QAAQ,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAC7C,CAAC;IACzB,MAAM,QAAQ,GAAG;QACf,IAAI,EAAE,kBAAkB;QACxB,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,EAAE,MAAM,EAAE,yCAAyC,EAAE,YAAY,EAAE,iBAAiB,EAAE;QAC/F,YAAY,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE;KACpC,CAAC;IACF,sFAAsF;IACtF,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,WAAW,CAAC,CAAC;IAC3B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YACpD,MAAM,IAAI,KAAK,CAAC,+BAA+B,WAAW,2BAA2B,CAAC,CAAC;QACzF,MAAM,KAAK,CAAC;IACd,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,SAAS;QACtC,MAAM,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACrE,MAAM,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE;QAC3F,IAAI,EAAE,IAAI;KACX,CAAC,CAAC;IACH,MAAM,SAAS,CACb,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,EAC/B,mDAAmD,EACnD,EAAE,IAAI,EAAE,IAAI,EAAE,CACf,CAAC;IACF,OAAO;QACL,SAAS,EAAE,WAAW;QACtB,KAAK,EAAE,CAAC,GAAG,KAAK,EAAE,cAAc,EAAE,YAAY,CAAC;QAC/C,IAAI,EAAE,CAAC,mCAAmC,EAAE,aAAa,EAAE,gBAAgB,CAAC;QAC5E,MAAM,EAAE,WAAW;KACpB,CAAC;AACJ,CAAC"}
|
package/dist/studio-reference.js
CHANGED
|
@@ -34,6 +34,6 @@ export const studioReference = {
|
|
|
34
34
|
lighting: 'art.normal(heightFn,x,y,strength=1,step=1) → surface normal from central differences. art.light(normal,[r,g,b,a],{light:[x,y,z]?,ambient?,diffuse?,specular?,shininess?}) → RGBA using Lambert diffuse and Blinn–Phong specular, viewer along +Z. Artistic 2.5D shading, not ray tracing.',
|
|
35
35
|
},
|
|
36
36
|
example: 'return art.raster((x,y) => { const n=art.fbm(x/35,y/35); return [35+n*40,40+n*35,45+n*30,255]; });',
|
|
37
|
-
edits: 'readRasterRegion reads exact canvas-space PNG pixels and a scene hash. writeRasterRegion consumes an exact-size project-local PNG and that expected_hash, with replace/over semantics and canvas/layer coordinates. Layer-space patches capture reference dimensions and follow transforms.
|
|
37
|
+
edits: 'readRasterRegion reads exact canvas-space PNG pixels and a scene hash. writeRasterRegion consumes an exact-size project-local PNG and that expected_hash, with replace/over semantics and canvas/layer coordinates. Layer-space patches capture reference dimensions and follow transforms. Patches follow target effects/operations and precede its mask/opacity; ancestor effects can change appearance; locality guards reject outward leakage.',
|
|
38
38
|
};
|
|
39
39
|
//# sourceMappingURL=studio-reference.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"studio-reference.js","sourceRoot":"","sources":["../src/studio-reference.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,mFAAmF;AACnF,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,OAAO,EAAE,mBAAmB;IAC5B,UAAU,EAAE,gBAAgB;IAC5B,aAAa,EAAE,iBAAiB;IAChC,UAAU,EACR,8YAA8Y;IAChZ,QAAQ,EACN,sWAAsW;IACxW,SAAS,EACP,wPAAwP;IAC1P,MAAM,EAAE;QACN,iBAAiB,EAAE,EAAE;QACrB,MAAM,EAAE,EAAE;QACV,4BAA4B,EAAE,EAAE;QAChC,IAAI,EAAE,IAAI;QACV,UAAU,EAAE,GAAG;QACf,cAAc,EAAE,EAAE;QAClB,UAAU,EAAE,CAAC,EAAE,EAAE,KAAK,CAAC;QACvB,WAAW,EAAE,GAAG;KACjB;IACD,GAAG,EAAE;QACH,MAAM,EACJ,gbAAgb;QAClb,MAAM,EACJ,uRAAuR;QACzR,MAAM,EACJ,iJAAiJ;QACnJ,MAAM,EACJ,sLAAsL;QACxL,KAAK,EACH,oGAAoG;QACtG,KAAK,EACH,0OAA0O;QAC5O,KAAK,EACH,qKAAqK;QACvK,WAAW,EACT,+IAA+I;QACjJ,MAAM,EACJ,qIAAqI;QACvI,IAAI,EAAE,kKAAkK;QACxK,QAAQ,EACN,0HAA0H;QAC5H,IAAI,EAAE,2EAA2E;QACjF,QAAQ,EACN,2RAA2R;KAC9R;IACD,OAAO,EACL,oGAAoG;IACtG,KAAK,EACH,
|
|
1
|
+
{"version":3,"file":"studio-reference.js","sourceRoot":"","sources":["../src/studio-reference.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,mFAAmF;AACnF,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,OAAO,EAAE,mBAAmB;IAC5B,UAAU,EAAE,gBAAgB;IAC5B,aAAa,EAAE,iBAAiB;IAChC,UAAU,EACR,8YAA8Y;IAChZ,QAAQ,EACN,sWAAsW;IACxW,SAAS,EACP,wPAAwP;IAC1P,MAAM,EAAE;QACN,iBAAiB,EAAE,EAAE;QACrB,MAAM,EAAE,EAAE;QACV,4BAA4B,EAAE,EAAE;QAChC,IAAI,EAAE,IAAI;QACV,UAAU,EAAE,GAAG;QACf,cAAc,EAAE,EAAE;QAClB,UAAU,EAAE,CAAC,EAAE,EAAE,KAAK,CAAC;QACvB,WAAW,EAAE,GAAG;KACjB;IACD,GAAG,EAAE;QACH,MAAM,EACJ,gbAAgb;QAClb,MAAM,EACJ,uRAAuR;QACzR,MAAM,EACJ,iJAAiJ;QACnJ,MAAM,EACJ,sLAAsL;QACxL,KAAK,EACH,oGAAoG;QACtG,KAAK,EACH,0OAA0O;QAC5O,KAAK,EACH,qKAAqK;QACvK,WAAW,EACT,+IAA+I;QACjJ,MAAM,EACJ,qIAAqI;QACvI,IAAI,EAAE,kKAAkK;QACxK,QAAQ,EACN,0HAA0H;QAC5H,IAAI,EAAE,2EAA2E;QACjF,QAAQ,EACN,2RAA2R;KAC9R;IACD,OAAO,EACL,oGAAoG;IACtG,KAAK,EACH,obAAob;CACvb,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Art direction for agents
|
|
2
2
|
|
|
3
3
|
Read this before creating illustration, painting or procedural assets. The versioned
|
|
4
|
-
protocol is returned by `
|
|
4
|
+
protocol is returned by `rtistree art-guide`, included in `rtistree studio-help`
|
|
5
5
|
and MCP `studioHelp`, and exported as `artDirectionGuide` by the SDK.
|
|
6
6
|
|
|
7
7
|
MCP connections receive the core rules in the server's initialization
|
|
@@ -10,7 +10,7 @@ MCP connections receive the core rules in the server's initialization
|
|
|
10
10
|
All of these surfaces share `src/art-direction.ts`; consumers do not need access
|
|
11
11
|
to this repository or its example files. SDK hosts should put the exported
|
|
12
12
|
`rtistreeAgentInstructions` in their agent context and expose the full guide.
|
|
13
|
-
CLI hosts should read `
|
|
13
|
+
CLI hosts should read `rtistree art-guide` before authoring. A client decides how
|
|
14
14
|
to present instructions to its model; shipping guidance cannot force every client
|
|
15
15
|
or agent to read it, follow it, or exercise good visual judgment.
|
|
16
16
|
|
|
@@ -59,6 +59,16 @@ hidden backs of its hoops over the near lid, where they looked like handles.
|
|
|
59
59
|
Both shared geometry and correct occlusion matter. Distinct shaded faces and a
|
|
60
60
|
common palette are insufficient evidence of sound construction.
|
|
61
61
|
|
|
62
|
+
**Pixel art:** declare the intended display size, palette and transparency policy.
|
|
63
|
+
Keep coordinates, frame dimensions and pivots on integer pixels, use
|
|
64
|
+
nearest-neighbour scaling, and inspect at the actual game size. A declared
|
|
65
|
+
pixel-art contract can catch palette overruns, invalid tile geometry and
|
|
66
|
+
disallowed transforms or blur; the sprite exporter preserves exact RGBA frame
|
|
67
|
+
pixels. It cannot decide whether a one-pixel choice is artistically good.
|
|
68
|
+
Use palette tiles for compact indexed marks and seeded studio programs for dense
|
|
69
|
+
or generated frames. Pack a set only after the individual frames and their
|
|
70
|
+
contact sheet have been inspected.
|
|
71
|
+
|
|
62
72
|
**Animation:** declare facing, travel direction, ground plane, stride distance,
|
|
63
73
|
cycle duration and contact/recovery phases. Play a full loop against ground
|
|
64
74
|
markers and inspect contact, passing and recovery frames at the intended size.
|
package/docs/agent-setup.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# Connect an agent
|
|
2
2
|
|
|
3
|
+
New to Rtistree? Read [Core concepts: an agent is the interface](core-concepts.md)
|
|
4
|
+
for how you, your agent and the engine work together.
|
|
5
|
+
|
|
3
6
|
Rtistree provides a CLI, an MCP server and a TypeScript SDK. The engine renders locally;
|
|
4
7
|
your host supplies the model and any vision capability.
|
|
5
8
|
|
|
@@ -41,17 +44,19 @@ Example task:
|
|
|
41
44
|
> visual findings separately. Revise failed criteria before exporting.
|
|
42
45
|
|
|
43
46
|
The server exposes inspection, rendering, crop inspection, typed edits, undo/redo, verification,
|
|
44
|
-
critiques, program execution, pipelines and staged production.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
+
critiques, program execution, pipelines, sprite-atlas export and staged production. The
|
|
48
|
+
`exportSprites` tool writes an engine-neutral PNG atlas plus JSON frame/animation metadata for
|
|
49
|
+
a scene with a `sprites` manifest. Rendering tools return PNG image content; use a
|
|
50
|
+
vision-capable agent to judge appearance. Structured inspection alone cannot establish that an
|
|
51
|
+
image looks good.
|
|
47
52
|
|
|
48
53
|
## CLI agents
|
|
49
54
|
|
|
50
55
|
```sh
|
|
51
|
-
npx
|
|
52
|
-
npx
|
|
53
|
-
npx
|
|
54
|
-
npx
|
|
56
|
+
npx rtistree art-guide
|
|
57
|
+
npx rtistree inspect scene.json
|
|
58
|
+
npx rtistree render scene.json -o review.png
|
|
59
|
+
npx rtistree studio-help
|
|
55
60
|
```
|
|
56
61
|
|
|
57
62
|
Read the JSON guide, open the rendered image, then choose a focused edit. Do not substitute a
|
package/docs/atelier.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Start with [Art direction for agents](agent-art-workflow.md): reference study, distinct silhouettes, construction, grayscale values and targeted revision. Its protocol is included in CLI/MCP `studioHelp`.
|
|
4
4
|
|
|
5
|
-
Rtistree provides the tools and records; a human or agent still makes visual decisions. No image-generation service or 3D renderer is required. Start with `
|
|
5
|
+
Rtistree provides the tools and records; a human or agent still makes visual decisions. No image-generation service or 3D renderer is required. Start with `rtistree studio-help` for the synchronous painting API and technique catalogue.
|
|
6
6
|
|
|
7
7
|
## Working sequence
|
|
8
8
|
|
|
@@ -17,6 +17,13 @@ CLI actions also have SDK equivalents (`buildPipeline`, `production`) and MCP to
|
|
|
17
17
|
|
|
18
18
|
## Editable dependency graph
|
|
19
19
|
|
|
20
|
+
These examples assume an installed package and an existing scene project; see
|
|
21
|
+
[the first painting](studio.md#first-painting). Save the graph as `pipeline.json`,
|
|
22
|
+
create `programs/ground.js` inside the artwork project, and make that program return
|
|
23
|
+
a Canvas of the requested dimensions. For a minimal ground program, use
|
|
24
|
+
`return art.raster(() => [38, 62, 69, 255]);`. Source paths inside the graph resolve
|
|
25
|
+
from the artwork project root; the CLI request filename resolves from your shell directory.
|
|
26
|
+
|
|
20
27
|
```json
|
|
21
28
|
{
|
|
22
29
|
"version": 1,
|
|
@@ -44,15 +51,19 @@ CLI actions also have SDK equivalents (`buildPipeline`, `production`) and MCP to
|
|
|
44
51
|
}
|
|
45
52
|
```
|
|
46
53
|
|
|
47
|
-
`
|
|
54
|
+
`rtistree pipeline my-project pipeline.json` reports `built` or `cached` for each node. An input can instead use `{ "asset": "registered-asset-id" }`. Source and inline code are mutually exclusive. Only subscribed shared parameters enter a node's key. Per-node parameters override nothing implicitly: an explicit binding takes precedence over a parameter of the same name. A changed node whose PNG is identical need not rebuild its dependants. Node array order defines auto-created layer order; dependency order defines execution order. Existing layer geometry is preserved. Changing output resolution changes cache keys. Removing a node does not remove previously authored layers or assets; use normal scene commands for removal.
|
|
48
55
|
|
|
49
|
-
All node artifacts are baked before one scene transaction.
|
|
56
|
+
All node artifacts are baked before one scene transaction. The CLI takes the graph
|
|
57
|
+
as the request file directly. To pass a previously inspected `expected_hash`, use
|
|
58
|
+
the SDK third argument or MCP’s separate `expected_hash` field. A failed build can leave unused immutable files in the cache, but never a partially updated scene. Identical builds add no history. Use `expected_hash` with the SDK/MCP to reject a scene changed since inspection.
|
|
50
59
|
|
|
51
60
|
The exact executed graph, including inline source, is stored under `scene.metadata.pipeline_<id>`. After restoring a candidate, use that graph to resume its settings; a working `pipeline.json` file is deliberately not overwritten by selection. Portable export includes the selected graph and registered input assets, so it can rebuild without the original source files.
|
|
61
|
+
It does not copy production sessions, rejected candidates, reviews or edit history; retain
|
|
62
|
+
the original project if you need those records.
|
|
52
63
|
|
|
53
64
|
## Production requests
|
|
54
65
|
|
|
55
|
-
Create a plan with `
|
|
66
|
+
Create a plan with `rtistree production my-project plan.json`:
|
|
56
67
|
|
|
57
68
|
```json
|
|
58
69
|
{
|
package/docs/cli-reference.md
CHANGED
|
@@ -1,34 +1,54 @@
|
|
|
1
1
|
# CLI reference
|
|
2
2
|
|
|
3
|
-
Installing Rtistree exposes `graphics`. In a local npm project, use `npx
|
|
4
|
-
Run `
|
|
5
|
-
stdout as JSON; errors go to stderr.
|
|
3
|
+
Installing Rtistree exposes `rtistree` and the compatibility alias `graphics`. In a local npm project, use `npx rtistree`.
|
|
4
|
+
Run `rtistree --help` for the complete installed-version reference. Structured results go to
|
|
5
|
+
stdout as JSON; errors go to stderr. Failed verification/preflight and non-identical recipe replay exit 2; input/runtime errors exit 1.
|
|
6
|
+
|
|
7
|
+
## Create a starter
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npx rtistree@latest init my-art
|
|
11
|
+
cd my-art
|
|
12
|
+
npm install
|
|
13
|
+
npm run render
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The destination must be a new directory. The starter includes a scene, sample patch, SDK example
|
|
17
|
+
and npm render scripts. `init` writes starter files without installing dependencies or executing painting programs.
|
|
6
18
|
|
|
7
19
|
## Inspect and edit
|
|
8
20
|
|
|
9
21
|
```sh
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
22
|
+
npx rtistree inspect scene.json
|
|
23
|
+
npx rtistree inspect scene.json --layer title
|
|
24
|
+
npx rtistree inspect-region scene.json 0 0 100 100
|
|
25
|
+
npx rtistree render scene.json -o image.png
|
|
26
|
+
npx rtistree render-region scene.json 0 0 100 100 -o crop.png
|
|
27
|
+
npx rtistree sprites scene.json -o output/sprites.png --manifest output/sprites.json
|
|
28
|
+
npx rtistree apply scene.json patch.json
|
|
29
|
+
npx rtistree undo scene.json
|
|
30
|
+
npx rtistree redo scene.json
|
|
31
|
+
npx rtistree history scene.json
|
|
19
32
|
```
|
|
20
33
|
|
|
21
34
|
Coordinates are `x y width height` in canvas pixels. A patch contains a reason and a typed
|
|
22
35
|
commands array. Supply the current `expected_hash` when coordinating concurrent edits.
|
|
23
36
|
See [scene format](scene-format.md) for command shapes and coordinate rules.
|
|
24
37
|
|
|
38
|
+
`sprites` reads a scene or configured project with a sprite manifest and writes a
|
|
39
|
+
deterministically packed atlas plus frame/animation metadata. The atlas output
|
|
40
|
+
must end in `.png`; the optional `--manifest` path must end in `.json`. Pixel-art
|
|
41
|
+
projects can opt into integer, palette and nearest-neighbour guardrails. Use
|
|
42
|
+
`npx rtistree sprites --help` for the exact options supported by the installed
|
|
43
|
+
version.
|
|
44
|
+
|
|
25
45
|
## Verify, review and export
|
|
26
46
|
|
|
27
47
|
```sh
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
48
|
+
npx rtistree verify scene.json -o report.json --heatmap heatmap.png
|
|
49
|
+
npx rtistree critique scene.json critique.json
|
|
50
|
+
npx rtistree export scene.json -o portable/scene.json
|
|
51
|
+
npx rtistree export scene.json --format png -o image.png
|
|
32
52
|
```
|
|
33
53
|
|
|
34
54
|
Verification measures configured technical constraints. Critiques are authored after inspecting
|
|
@@ -38,12 +58,12 @@ described in [print production](production.md).
|
|
|
38
58
|
## Studio and production
|
|
39
59
|
|
|
40
60
|
```sh
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
61
|
+
npx rtistree art-guide
|
|
62
|
+
npx rtistree studio-help
|
|
63
|
+
npx rtistree program scene.json program.json
|
|
64
|
+
npx rtistree program-replay scene.json asset-id
|
|
65
|
+
npx rtistree pipeline scene.json pipeline.json
|
|
66
|
+
npx rtistree production scene.json request.json
|
|
47
67
|
```
|
|
48
68
|
|
|
49
69
|
Read [studio](studio.md) for program requests and [staged production](atelier.md) for plans,
|
|
@@ -52,10 +72,53 @@ candidate captures, reviews and selection. Program execution is for trusted code
|
|
|
52
72
|
## Project creation and integration
|
|
53
73
|
|
|
54
74
|
```sh
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
75
|
+
npx rtistree project new artwork --size A3 --orientation landscape --ppi 300 --bleed 3mm
|
|
76
|
+
npx rtistree schema --kind scene
|
|
77
|
+
npx rtistree schema --kind command
|
|
78
|
+
npx rtistree serve /absolute/path/to/scene.json
|
|
59
79
|
```
|
|
60
80
|
|
|
61
81
|
The MCP server uses stdio. See [agent setup](agent-setup.md).
|
|
82
|
+
|
|
83
|
+
## Additional commands
|
|
84
|
+
|
|
85
|
+
| Command | Purpose |
|
|
86
|
+
| ----------------------------------------------------------- | ----------------------------------------------------------------------------------- |
|
|
87
|
+
| `npx rtistree rebase scene.json` | Merge manual source changes into journaled state; conflicts fail without committing |
|
|
88
|
+
| `npx rtistree compact scene.json` | Compress history while retaining undo and redo |
|
|
89
|
+
| `npx rtistree raster-read scene.json read.json` | Write an exact crop plus evidence and return an asset descriptor |
|
|
90
|
+
| `npx rtistree raster-write scene.json write.json` | Commit an exact-size PNG patch with a required current hash |
|
|
91
|
+
| `npx rtistree sprites scene.json -o output/sprites.png` | Pack declared sprite frames into an atlas and write animation metadata |
|
|
92
|
+
| `npx rtistree import-svg drawing.svg -o drawing.scene.json` | Import the supported static SVG subset |
|
|
93
|
+
| `npx rtistree preflight artwork --preset screen` | Check physical document/export settings and save a report |
|
|
94
|
+
| `npx rtistree proof artwork --preset print -o proof.png` | Make a CMYK round-trip proof; requires a configured ICC profile |
|
|
95
|
+
| `npx rtistree benchmark scene.json brief.json before` | Capture a benchmark checkpoint after recording a current critique |
|
|
96
|
+
| `npx rtistree benchmark scene.json brief.json finish` | Finish after at least two inspected checkpoints |
|
|
97
|
+
|
|
98
|
+
Dense request shapes are in [studio](studio.md). Source rebasing, critiques and benchmark
|
|
99
|
+
requirements are in [editing workflows](evolution.md). Names such as `patch.json`, `read.json`
|
|
100
|
+
and `critique.json` are request files you author, not files created by `init`.
|
|
101
|
+
|
|
102
|
+
## Options, paths and output
|
|
103
|
+
|
|
104
|
+
- `--output` / `-o` chooses an artifact path. Explicit paths and request filenames resolve
|
|
105
|
+
from the shell's working directory. Asset/program paths inside requests resolve from the
|
|
106
|
+
artwork project root. Without `-o`, configured projects use `output_dir`; bare scene files
|
|
107
|
+
use a `renders/` directory alongside the scene.
|
|
108
|
+
- `render --quality draft|preview|final` controls PNG rendering. Draft halves dimensions
|
|
109
|
+
after rendering; preview and final share the full-quality path. `--layer ID` renders an
|
|
110
|
+
isolated layer on a full-size transparent canvas. `render-region` requires an integer crop
|
|
111
|
+
entirely inside the canvas; default/final quality is an exact full-render crop.
|
|
112
|
+
- `inspect-region` also writes `inspection.png` and its evidence unless you supply `-o`.
|
|
113
|
+
- Artwork `export` and full `render` accept `--format`, `--preset` and `--ppi`. Known output
|
|
114
|
+
extensions are inferred. Print exports additionally accept `--profile` (project-relative
|
|
115
|
+
ICC file; implies CMYK), `--colour-space srgb|cmyk` and `--crop-marks`. Use `export` for
|
|
116
|
+
print options; a plain PNG `render` with only `--profile` does not select the export path.
|
|
117
|
+
- `schema --kind scene` describes a resolved scene. Source scenes with includes/components
|
|
118
|
+
use the packaged `authoring.schema.json`; a patch uses `patch.schema.json`.
|
|
119
|
+
|
|
120
|
+
JSON is the structured result format; help is plain text and `serve` writes MCP protocol
|
|
121
|
+
messages. The npm/npx launcher can print its own installation notices. `verify` and
|
|
122
|
+
`preflight` failures, and non-identical `program-replay` results, exit 2. Input/runtime/export
|
|
123
|
+
errors exit 1. Warnings alone do not make preflight fail. Program or pipeline build success
|
|
124
|
+
only means execution succeeded; it does not establish visual quality.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Core concepts: an agent is the interface
|
|
2
|
+
|
|
3
|
+
Rtistree is designed to be operated through an agent. You describe what you want,
|
|
4
|
+
set constraints and give feedback. The agent uses Rtistree to construct artwork,
|
|
5
|
+
inspect renders and make focused revisions.
|
|
6
|
+
|
|
7
|
+
The CLI, MCP server and TypeScript SDK are the agent's controls. They are also
|
|
8
|
+
available for direct human use, but learning every command is not the intended
|
|
9
|
+
starting point for someone who wants to make art.
|
|
10
|
+
|
|
11
|
+
## Three roles
|
|
12
|
+
|
|
13
|
+
| Role | Responsibility |
|
|
14
|
+
| --------- | -------------------------------------------------------------------------------------------------- |
|
|
15
|
+
| You | Set the brief, references, constraints and intended use; judge whether the result meets your needs |
|
|
16
|
+
| The agent | Plan the work, call tools, inspect images, identify defects and revise the artwork |
|
|
17
|
+
| Rtistree | Store the editable scene, render it, apply typed edits, track history and export files |
|
|
18
|
+
|
|
19
|
+
Rtistree does not contain a model. Your agent host supplies the model, its context,
|
|
20
|
+
image-viewing capability and tool access. An agent that cannot inspect images can
|
|
21
|
+
still operate the tools, but cannot credibly judge their visual quality.
|
|
22
|
+
|
|
23
|
+
You can connect an MCP-capable host, give an agent access to the CLI, or integrate
|
|
24
|
+
the SDK into your own application. [Agent setup](agent-setup.md) explains each path.
|
|
25
|
+
The host decides which tools require confirmation and what files the agent can access.
|
|
26
|
+
|
|
27
|
+
## A conversation becomes an editable scene
|
|
28
|
+
|
|
29
|
+
A useful starting brief might be:
|
|
30
|
+
|
|
31
|
+
> Create a square event poster with a bold title, a quiet landscape and room for
|
|
32
|
+
> a date. Keep the title and illustration independently editable. Show me a
|
|
33
|
+
> composition before adding detail.
|
|
34
|
+
|
|
35
|
+
The agent creates a scene with named layers rather than treating the final PNG as
|
|
36
|
+
its only state. Text, geometry, image assets, masks and adjustments can retain
|
|
37
|
+
separate identities. For painted detail, trusted JavaScript programs can produce
|
|
38
|
+
baked raster assets with saved source, parameters and seeds.
|
|
39
|
+
|
|
40
|
+
After inspecting the render, you might say:
|
|
41
|
+
|
|
42
|
+
> The title works. Reduce the contrast behind it and move the sun farther right.
|
|
43
|
+
|
|
44
|
+
The agent can inspect the relevant layers, change those parts and render again.
|
|
45
|
+
It should preserve the parts you approved and check that the requested revision
|
|
46
|
+
actually helps. Scoped raster edits have an enforced pixel-locality check;
|
|
47
|
+
arbitrary structural edits do not automatically promise that every other pixel
|
|
48
|
+
will remain unchanged.
|
|
49
|
+
|
|
50
|
+
A painted image is only as editable as its construction. If an agent bakes every
|
|
51
|
+
part into one asset, Rtistree cannot recover meaningful objects from those pixels.
|
|
52
|
+
Ask for independent layers or program parameters for the parts you expect to revise.
|
|
53
|
+
|
|
54
|
+
## The working loop
|
|
55
|
+
|
|
56
|
+
1. **Direct:** establish the brief, references, intended size and acceptance criteria.
|
|
57
|
+
2. **Construct:** make a representative composition or asset with useful editable structure.
|
|
58
|
+
3. **Inspect:** open the actual render, including silhouettes, crops or animation frames as relevant.
|
|
59
|
+
4. **Refine:** identify a specific defect, make a focused change and compare the result.
|
|
60
|
+
5. **Deliver:** export the accepted state and keep the source needed for future edits.
|
|
61
|
+
|
|
62
|
+
This loop is deliberate. A successful command, valid file or reproducible image
|
|
63
|
+
is not proof that the artwork is good. The agent brings drawing and observation
|
|
64
|
+
skills; Rtistree provides tools and records. A stronger agent may use the same
|
|
65
|
+
toolkit better, but the toolkit does not guarantee artistic success.
|
|
66
|
+
|
|
67
|
+
## Guidance travels with the tool
|
|
68
|
+
|
|
69
|
+
The package includes art-direction guidance based on recorded trials: connected
|
|
70
|
+
construction, coherent prop perspective, ground contact, representative samples,
|
|
71
|
+
and separate technical, functional and visual assessment.
|
|
72
|
+
|
|
73
|
+
- MCP supplies compact instructions during connection and exposes the full guide
|
|
74
|
+
through `studioHelp` and the `rtistree://guides/art-direction` resource.
|
|
75
|
+
- CLI agents can read it with `rtistree art-guide`.
|
|
76
|
+
- SDK hosts can provide `rtistreeAgentInstructions` and `artDirectionGuide` to their agent.
|
|
77
|
+
|
|
78
|
+
Availability is not automatic compliance: some hosts do not pass server instructions
|
|
79
|
+
to their model. Ask the agent to read the guide before authoring. The
|
|
80
|
+
[art-direction workflow](agent-art-workflow.md) explains the process and optional
|
|
81
|
+
production gates in detail.
|
|
82
|
+
|
|
83
|
+
## Local work and explicit execution
|
|
84
|
+
|
|
85
|
+
Ordinary scene loading and rendering use local assets and do not execute painting
|
|
86
|
+
recipes. Program execution, pipeline builds and recipe replay are explicit actions
|
|
87
|
+
for trusted code; the JavaScript VM is not a security sandbox. The agent host's
|
|
88
|
+
model calls may use a remote service even though Rtistree renders locally.
|
|
89
|
+
|
|
90
|
+
Edits are journaled and can be undone. Portable export saves the current artwork,
|
|
91
|
+
assets and recipes as a new baseline; it does not copy the complete edit history
|
|
92
|
+
or production reviews. Keep the original project when those records matter.
|
|
93
|
+
|
|
94
|
+
Start by [connecting your agent](agent-setup.md). To understand the mechanics
|
|
95
|
+
first, [make your first image](getting-started.md) with the small CLI walkthrough.
|
|
@@ -16,4 +16,4 @@ Hybrid PDF preserves supported text, vectors, gradients and isolation-free group
|
|
|
16
16
|
|
|
17
17
|
The print trial revealed two defects that were fixed during implementation: metadata configuration could overwrite the requested CMYK conversion, and mask inversion after erosion expanded the selected foreground instead of shrinking it. Actual-file tests and visual proof inspection cover these cases. The original engine regression suite remains in place, alongside production and editing tests.
|
|
18
18
|
|
|
19
|
-
See [the production guide](../production.md) for capabilities and operational limits, [the A3 evidence](../previews/a3-production.json), and [the generated-asset print trial](
|
|
19
|
+
See [the production guide](../production.md) for capabilities and operational limits, [the A3 evidence](../previews/a3-production.json), and [the generated-asset print trial](https://github.com/Coly010/rtistree/blob/main/examples/print-trial/README.md).
|