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.
Files changed (56) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/CONTRIBUTING.md +47 -0
  3. package/README.md +38 -22
  4. package/SECURITY.md +20 -0
  5. package/THIRD_PARTY_NOTICES.md +1 -1
  6. package/dist/art-direction.js +1 -1
  7. package/dist/cli.js +55 -32
  8. package/dist/cli.js.map +1 -1
  9. package/dist/commands.d.ts +12 -0
  10. package/dist/index.d.ts +1 -0
  11. package/dist/index.js +1 -0
  12. package/dist/index.js.map +1 -1
  13. package/dist/mcp.js +18 -2
  14. package/dist/mcp.js.map +1 -1
  15. package/dist/print-scene.d.ts +6 -0
  16. package/dist/program.js +3 -1
  17. package/dist/program.js.map +1 -1
  18. package/dist/project-config.js +2 -1
  19. package/dist/project-config.js.map +1 -1
  20. package/dist/render.js +21 -1
  21. package/dist/render.js.map +1 -1
  22. package/dist/schema.d.ts +46 -0
  23. package/dist/schema.js +107 -0
  24. package/dist/schema.js.map +1 -1
  25. package/dist/sprites.d.ts +31 -0
  26. package/dist/sprites.js +142 -0
  27. package/dist/sprites.js.map +1 -0
  28. package/dist/starter.d.ts +7 -0
  29. package/dist/starter.js +38 -0
  30. package/dist/starter.js.map +1 -0
  31. package/dist/studio-reference.js +1 -1
  32. package/dist/studio-reference.js.map +1 -1
  33. package/docs/agent-art-workflow.md +12 -2
  34. package/docs/agent-setup.md +12 -7
  35. package/docs/atelier.md +15 -4
  36. package/docs/cli-reference.md +89 -26
  37. package/docs/core-concepts.md +95 -0
  38. package/docs/decisions/004-print-production-and-projects.md +1 -1
  39. package/docs/decisions/005-programmable-digital-art.md +1 -1
  40. package/docs/engine-overview.md +121 -165
  41. package/docs/evolution.md +12 -9
  42. package/docs/getting-started.md +84 -53
  43. package/docs/next-milestone.md +9 -9
  44. package/docs/production.md +22 -16
  45. package/docs/releasing.md +99 -43
  46. package/docs/scene-format.md +45 -8
  47. package/docs/sprites.md +166 -0
  48. package/docs/studio.md +27 -12
  49. package/examples/hello/README.md +24 -8
  50. package/examples/hello/render.mjs +2 -1
  51. package/package.json +10 -5
  52. package/schemas/authoring.schema.json +359 -229
  53. package/schemas/command.schema.json +462 -332
  54. package/schemas/patch.schema.json +462 -332
  55. package/schemas/scene.schema.json +347 -217
  56. package/schemas/sprites.schema.json +41 -0
@@ -1,16 +1,22 @@
1
- # Projects, print production and editing in v0.3
1
+ # Projects, print production and editing
2
2
 
3
3
  ## Start a project
4
4
 
5
+ Run these commands from a directory where `npm install rtistree` has completed.
6
+ `project new` creates the artwork files and presets, not a Node package or dependency installation.
7
+
5
8
  ```sh
6
- graphics project new alpine --size A3 --orientation landscape --ppi 300 --bleed 3mm --output-dir output
7
- graphics render alpine --preset screen
8
- graphics preflight alpine --preset print
9
+ npx rtistree project new alpine --size A3 --orientation landscape --ppi 300 --bleed 3mm --output-dir output
10
+ npx rtistree render alpine --preset screen
11
+ npx rtistree preflight alpine --preset screen
9
12
  ```
10
13
 
11
14
  `project new` accepts A3, A4, A5, Letter, or a custom pair such as `160x100` (mm) or `8.5inx11in`. It creates `rtistree.yaml`, a scene with layer fragments, assets/fonts/profiles/history directories, local JSON Schemas, a README and a designated output directory. The destination must be new. Existing scene-file commands remain available; opening a configured entry-point scene also discovers its project settings.
12
15
 
13
- Generated projects start with an sRGB screen preset and a CMYK print preset. Before using the print preset, copy your printer/paper ICC file into `profiles/` and set `presets.print.profile`. Set `profile_hash` to its SHA-256 digest to pin it. CMYK export rejects missing, invalid, changed or non-CMYK profiles. The demo profile is for exercising the pipeline, not a recommendation for a printing process.
16
+ Generated projects start with an sRGB screen preset and a CMYK print preset. Before using the print preset, copy your printer/paper ICC file into `profiles/` and set `presets.print.profile`. Set `profile_hash` to `sha256:` followed by its 64-character hexadecimal digest to pin it. CMYK export rejects missing, invalid, changed or non-CMYK profiles. The demo profile is for exercising the pipeline, not a recommendation for a printing process.
17
+ An unconfigured print preset fails preflight with exit code 2; the first example deliberately
18
+ uses the screen preset. After configuring a real profile, run `npx rtistree preflight alpine --preset print`
19
+ before the CMYK export and proof commands below.
14
20
 
15
21
  Project paths are local to the project root. CLI/MCP renders and artwork exports use `output_dir`; CLI verification and preflight reports use it too. History and critique records remain persistent project state. Explicit CLI `--output` paths override artifact destinations.
16
22
 
@@ -37,12 +43,12 @@ The renderer accepts edges up to 8,192 pixels. Print preflight also enforces a 3
37
43
  ## Formats and colour
38
44
 
39
45
  ```sh
40
- graphics export alpine --preset print --format pdf
41
- graphics export alpine --preset print --format tiff
42
- graphics export alpine --preset screen --format jpeg
43
- graphics export alpine --format svg -o alpine/output/artwork.svg
44
- graphics proof alpine --preset print
45
- graphics export alpine --format project -o /tmp/alpine-copy/scene.json
46
+ npx rtistree export alpine --preset print --format pdf
47
+ npx rtistree export alpine --preset print --format tiff
48
+ npx rtistree export alpine --preset screen --format jpeg
49
+ npx rtistree export alpine --format svg -o alpine/output/artwork.svg
50
+ npx rtistree proof alpine --preset print
51
+ npx rtistree export alpine --format project -o /tmp/alpine-copy/scene.json
46
52
  ```
47
53
 
48
54
  Known artwork extensions are inferred for `export` and full `render`. Region renders remain PNG. A filename extension must agree with the actual format. Portable scene export keeps its original meaning with `--format project` or a JSON/YAML destination, and copies configured print profiles/presets when exporting a project.
@@ -71,7 +77,7 @@ Preflight checks physical geometry, render capacity, output profiles, font glyph
71
77
 
72
78
  Each artwork export has a `.evidence.json` containing the scene hash, output hash, resolved settings, ICC hash, backend versions and inspection of the actual encoded bytes. Raster inspection reads format, dimensions, channels, profile and density. PDF inspection reads page boxes, image colour-space declarations, embedded font descriptors and profile streams. This complements visual proof inspection; it does not replace press validation.
73
79
 
74
- ## New editing operations
80
+ ## Editing operations
75
81
 
76
82
  Commands are available through `apply` in the CLI, SDK and MCP. See generated command/patch schemas for complete inputs.
77
83
 
@@ -93,15 +99,15 @@ Shapes support stroke caps, joins, dash arrays and dash offsets. Text styles sup
93
99
 
94
100
  Masks now support editable SVG-style paths, image alpha/luminance/colour-range selections, and union/intersection/subtraction/XOR. Combined masks use one coordinate space; children inherit the outer space and reference size. The processing order is selection/algebra, inversion, grow/shrink, then feathering. Image masks reference an asset directly, making external segmentation masks usable without a visible mask layer.
95
101
 
96
- New scoped operations are levels, piecewise-linear RGB/channel curves, white balance, clone and heal. Cloning samples a frozen copy of the target using `source_offset`. Healing adds a local mean-colour correction to that cloned texture; this is a deterministic colour-matched clone, not a Poisson or learned healing algorithm. All operate non-destructively through the existing history and scoped-pixel checks.
102
+ Additional scoped operations are levels, piecewise-linear RGB/channel curves, white balance, clone and heal. Cloning samples a frozen copy of the target using `source_offset`. Healing adds a local mean-colour correction to that cloned texture; this is a deterministic colour-matched clone, not a Poisson or learned healing algorithm. All operate non-destructively through the existing history and scoped-pixel checks.
97
103
 
98
104
  ## SVG interchange and trial
99
105
 
100
106
  ```sh
101
- graphics import-svg drawing.svg -o drawing.scene.json
102
- graphics export drawing.scene.json --format svg -o drawing.svg
107
+ npx rtistree import-svg drawing.svg -o drawing.scene.json
108
+ npx rtistree export drawing.scene.json --format svg -o drawing.svg
103
109
  ```
104
110
 
105
111
  The importer supports static paths, rectangles, circles, ellipses, lines, polygons, polylines, groups, transforms and basic stroke/fill styling. Unsupported elements/attributes, remote resources, scripts and entities are rejected rather than silently dropped. Text, filters and arbitrary CSS are not imported. Exported text is outlined; complex export fallbacks are embedded images. Full round-trip equivalence for arbitrary SVG is not promised.
106
112
 
107
- The [print trial](../examples/print-trial/README.md) generates a ceramic vase/leaf photograph, extracts its silhouette using the new masks, adds a contact shadow and colour adjustment, adapts it to two aspect ratios, and exports CMYK PDF/TIFF/JPEG. The source, exact prompt, edits, critiques, final scenes and output evidence are retained.
113
+ The [print trial](https://github.com/Coly010/rtistree/blob/main/examples/print-trial/README.md) used an external image-generation tool to create a ceramic vase/leaf photograph. Rtistree then extracted its silhouette with masks, added a contact shadow and colour adjustment, adapted it to two aspect ratios, and exported CMYK PDF/TIFF/JPEG. The source, exact prompt, edits, critiques, final scenes and output evidence are retained.
package/docs/releasing.md CHANGED
@@ -1,60 +1,116 @@
1
1
  # Release process
2
2
 
3
- The repository is `Coly010/rtistree`, the npm package is `rtistree`, and the website's
4
- canonical origin is `https://rtistree.dev`. The package is MIT licensed to Colum Ferry.
5
-
6
- ## Validate a release
7
-
8
- 1. Update `package.json`, its lockfile and `CHANGELOG.md` together. Keep the website version
9
- label and package instructions aligned with the release.
10
- 2. Run `npm ci`, `npm run check`, `npm run format:check` and `npm run package:check`.
11
- 3. Run `npm ci --prefix website` and `npm run build --prefix website`.
12
- 4. Review the tarball inventory, documentation commands and example sources. The package
13
- intentionally includes only the small hello example; larger trials are repository assets.
14
- 5. Commit the validated source and tag the matching version, for example `v0.5.0`.
15
-
16
- ## First npm publication
3
+ Rtistree uses Release Please to prepare version and changelog updates, and npm trusted
4
+ publishing to publish from GitHub Actions. The repository is `Coly010/rtistree`, the npm
5
+ package is `rtistree`, and the website is `https://rtistree.dev`.
6
+
7
+ ## Everyday releases
8
+
9
+ 1. Merge changes into `main` using Conventional Commit messages. For squash merges, use
10
+ a conventional PR title; that title becomes the commit message.
11
+ 2. The **Release** workflow opens or updates a release PR with the next version,
12
+ `CHANGELOG.md`, both package lockfiles, and the README and website version labels.
13
+ 3. Review the generated notes and the **Graphics engine** and **Documentation website**
14
+ checks on that PR. Release PRs stay open until a maintainer decides to ship.
15
+ 4. Merge the release PR. The same workflow creates the `vX.Y.Z` tag and GitHub release,
16
+ validates the tagged source and packaged installation, then publishes the tested
17
+ tarball to npm with provenance. It also attaches that tarball to the GitHub release.
18
+
19
+ There is no npm token or personal access token in this flow. GitHub supplies a short-lived
20
+ OIDC identity that npm checks against the configured repository and workflow.
21
+
22
+ ### Commit messages and versions
23
+
24
+ | Commit | Example | Version change |
25
+ | --------------------------------- | -------------------------------------------------- | --------------------------------------- |
26
+ | `fix:` | `fix: preserve layer opacity when undoing an edit` | Patch: 0.5.1 → 0.5.2 |
27
+ | `feat:` | `feat: add palette extraction` | Minor: 0.5.1 → 0.6.0 |
28
+ | Breaking change (`!`) | `feat!: replace the scene coordinate format` | Minor before 1.0; major from 1.0 onward |
29
+ | `docs:`, `ci:`, `chore:`, `test:` | `docs: explain sprite export` | No release on their own |
30
+
31
+ Use a `BREAKING CHANGE:` footer to explain migration steps for breaking changes.
32
+ The largest applicable change determines the release version. Do not edit versions by hand
33
+ for a routine release. Releases continue to use normal `0.x.y` versions on npm's `latest`
34
+ tag while the project is a public alpha; this does not claim a stable 1.0 API.
35
+
36
+ The manifest starts at the already-published 0.5.1. `bootstrap-sha` bounds the initial
37
+ history scan at that tag. Older non-conventional commit messages are not automatically
38
+ converted into changelog entries. Once the first automated release is merged, normal
39
+ release history takes over.
40
+
41
+ ## Trusted publisher setup
42
+
43
+ The npm package owner configures this once in the package's settings:
44
+
45
+ - Provider: GitHub Actions
46
+ - Repository owner: `Coly010`
47
+ - Repository: `rtistree`
48
+ - Workflow filename: `release.yml`
49
+ - Environment: leave blank (the workflow does not use a GitHub environment)
50
+ - Permission: publish
17
51
 
18
- The owner must authenticate with `npm login` and complete any npm 2FA challenge.
19
- Confirm `npm whoami` is the intended owner. Build and inspect the package before publishing:
52
+ Alternatively, with an authenticated npm owner account and 2FA:
20
53
 
21
54
  ```sh
22
- npm pack
23
- npm publish rtistree-0.5.0.tgz --access public
55
+ npx --yes npm@11.19.1 trust list rtistree
56
+ npx --yes npm@11.19.1 trust github rtistree --repository Coly010/rtistree --file release.yml --allow-publish --yes
24
57
  ```
25
58
 
26
- Do not republish a version number. If a command's outcome is uncertain, check the npm
27
- registry before retrying. Never commit npm tokens or configure long-lived tokens in workflows.
59
+ The workflow uses Node.js 24, npm 11.19.1, a GitHub-hosted runner and `id-token: write`.
60
+ No `NPM_TOKEN`, `NODE_AUTH_TOKEN`, or enablement variable is required. A trust mismatch
61
+ fails publication visibly rather than silently skipping it.
28
62
 
29
- ## Subsequent releases with trusted publishing
63
+ In GitHub **Settings Actions → General → Workflow permissions**, enable **Allow GitHub
64
+ Actions to create and approve pull requests**. GitHub bundles creation and approval in
65
+ one setting; this workflow creates release PRs but does not approve or merge them.
66
+ The repository's default workflow permission can remain read-only.
30
67
 
31
- In the npm package settings, configure a GitHub Actions trusted publisher:
68
+ Bot-created PRs and releases do not trigger ordinary workflows when using `GITHUB_TOKEN`.
69
+ The Release workflow explicitly dispatches both validation workflows on the release PR
70
+ branch and publishes in a dependent job when a release is created. This avoids needing a
71
+ long-lived GitHub token just to trigger CI.
32
72
 
33
- - Owner: `Coly010`
34
- - Repository: `rtistree`
35
- - Workflow filename: `release.yml`
73
+ See the [npm trusted publishing documentation](https://docs.npmjs.com/trusted-publishers/)
74
+ and [Release Please documentation](https://github.com/googleapis/release-please-action).
36
75
 
37
- After configuring the npm trusted publisher, set the GitHub repository Actions variable
38
- `NPM_TRUSTED_PUBLISHING_ENABLED` to `true`. Without it, release validation runs but npm
39
- publication is skipped. This permits the initial GitHub tarball release before npm sign-in.
76
+ ## Recovering a failed release
40
77
 
41
- The release workflow checks the tag against the package version, validates the engine,
42
- website and packaged installation, then publishes the same checked tarball with provenance.
43
- It runs on publication of a GitHub release. Configure trust before publishing the next release.
44
- For the bootstrap release, publish npm first and let the workflow skip an already-published version.
78
+ A GitHub release can exist while npm publication is still running or has failed. Check the
79
+ **Release** workflow before announcing availability. Correct the account/trust problem, then
80
+ use **Actions Release Run workflow**, select `main`, and enter the existing tag in the
81
+ `tag` input. Leave the tag blank to refresh the release PR instead.
45
82
 
46
- See https://docs.npmjs.com/trusted-publishers/ for current npm account requirements.
83
+ The retry checks that the tag matches the package, has a published GitHub release and belongs
84
+ to `main`. It rebuilds and tests the tarball. If npm already has that version, the workflow
85
+ only skips publication when its integrity matches the checked tarball; a mismatch or registry
86
+ error fails. Never delete/reuse a published version to fix package contents: ship a new version.
87
+ A failed publish can also be retried by rerunning failed jobs from its original workflow run.
47
88
 
48
- ## Website
89
+ ## Local validation
49
90
 
50
- The website is an Astro/Starlight static build in `website/`. `docs/` is the source of truth;
51
- the content sync script generates Starlight pages, remaps repository links and copies curated
52
- assets. Generated files are ignored by Git but included when preparing a standalone Sites source snapshot.
91
+ ```sh
92
+ npm ci
93
+ npm run check
94
+ npm run format:check
95
+ npm run docs:check
96
+ npm run package:check
97
+ npm ci --prefix website
98
+ npm run build --prefix website
99
+ ```
100
+
101
+ The package check installs the actual tarball in a temporary project and exercises the CLI,
102
+ starter, rendering, SDK and MCP guide. It retains the checked archive for the publish job.
103
+ Large trial assets stay in the repository; only the small hello example ships in the package.
53
104
 
54
- `npm run build --prefix website` produces `website/dist`. This is portable static output.
55
- The Sites project ID is in `website/.openai/hosting.json`; never replace it on redeployment.
56
- Use the Sites publishing flow to save and deploy the validated source and static archive.
57
- The `website.yml` workflow validates and uploads a deployable static artifact for each change.
105
+ ## Website deployment
58
106
 
59
- Custom-domain DNS must use the exact records returned by the hosting provider. Do not infer
60
- an apex A record from a preview hostname. Confirm domain and TLS status after the DNS change.
107
+ The website is an Astro/Starlight static build in `website/`. `docs/` is the source of truth;
108
+ the content sync script publishes an explicit list of current user guides plus the changelog,
109
+ remaps repository links and copies curated assets. Maintainer procedures and historical proposals/
110
+ decisions remain in the repository. Removed generated routes and raw source copies are deleted
111
+ during synchronization. Generated files are ignored by Git but included in a standalone Sites source snapshot.
112
+
113
+ `npm run build --prefix website` produces `website/dist`. The `website.yml` workflow validates
114
+ and uploads that static artifact. **npm releases do not deploy the live website.** Publish the
115
+ validated website through the Sites flow when documentation or the displayed version changes.
116
+ Keep the existing project ID in `website/.openai/hosting.json` when redeploying.
@@ -1,21 +1,26 @@
1
1
  # Scene format v1
2
2
 
3
- The examples in this document are the implemented format. The original proposal is exploratory; unsupported fields are rejected, not silently interpreted. Generate machine-readable schemas with `npm run schema` or `graphics schema`.
3
+ The examples in this document are the implemented format. The original proposal is exploratory; unsupported fields are rejected, not silently interpreted. The package ships schemas in `node_modules/rtistree/schemas/`. Use `authoring.schema.json`
4
+ for source scenes with includes/components and `fragment.schema.json` for included files.
5
+ `npx rtistree schema --kind scene` prints the resolved scene schema; `--kind command` prints
6
+ a single-command schema. A transaction uses `patch.schema.json`. Repository contributors
7
+ can regenerate all schemas with `npm run schema`.
4
8
 
5
- The [production guide](production.md) describes v0.3 physical documents, exports, affine and perspective transforms, extended masks, adjustments, path commands and typography.
9
+ The [production guide](production.md) describes physical documents, exports, affine and perspective transforms, extended masks, adjustments, path commands and typography.
6
10
 
7
- The [studio guide](studio.md) describes v0.4 programmable assets and dense editing. Assets may carry a `recipe: {source, hash}` reference to a frozen program manifest. Promoted regions accept `composite: replace|over` (default replacement). Programs are executed explicitly and baked; scenes never execute referenced recipes while rendering.
11
+ The [studio guide](studio.md) describes programmable assets and dense editing. Assets may carry a `recipe: {source, hash}` reference to a frozen program manifest. Promoted regions accept `composite: replace|over` (default replacement). Programs are executed explicitly and baked; scenes never execute referenced recipes while rendering.
8
12
 
9
13
  ## Files and assets
10
14
 
11
- Root documents contain `version: 1`, `canvas`, `layers` and/or `include`, optional `assets`, `metadata`, and `verification: {rules: [...]}`. Fragments contain `include`, `assets`, `fonts`, `components` and `layers`. JSON and YAML can be mixed. There can be at most 128 included documents and 256 total layers.
15
+ Root documents contain `version: 1`, `canvas`, optional `layers` and/or `include`, optional `assets`, `metadata`, and `verification: {rules: [...]}`. Fragments contain `include`, `assets`, `fonts`, `components` and `layers`. JSON and YAML can be mixed. Root scenes can also declare `fonts`, `components`, `document` and `paragraph_styles`.
16
+ The loader permits at most 128 document reads including the root, and 256 total layers after expansion.
12
17
 
13
18
  ```yaml
14
19
  assets:
15
20
  portrait:
16
21
  type: image # or generated-image; provenance category only
17
22
  source: ./assets/portrait.png
18
- hash: sha256:... # optional on input; checked when supplied
23
+ # hash is optional; when supplied, use sha256: followed by the file’s 64 hex digest characters
19
24
  ```
20
25
 
21
26
  PNG, JPEG, WebP and TIFF assets are supported. ICC-tagged input is normalised to sRGB. The separate `import-svg` command converts a closed static geometry subset into scene layers. No URL loading or external resource resolution is permitted. Asset paths must resolve inside the root scene directory, including after symlink resolution. File size is limited to 64 MiB and decoded dimensions to 32 megapixels. Large rasters belong in binary image files, not YAML arrays.
@@ -66,7 +71,7 @@ Shapes are `rectangle` (optional radius), `ellipse`, or `path` with SVG path dat
66
71
 
67
72
  Text is retained as semantic content. It wraps at whitespace and respects explicit newlines. `style` supports `font: inter|display`, `size`, `weight: regular|bold`, `colour`, `line_height` as a multiplier, and `align: left|center|right`. `display` uses DM Serif Display regular; its bold variant is not supplied. Text is clipped to its box, and the verifier reports overflow. Bundled Latin fonts provide reproducible typography; a custom font can be registered in the scene fonts map and selected by its ID.
68
73
 
69
- Generators: `solid` (`colour`); `gradient` (`from`, `to`, `angle`, with 0° horizontal and 90° vertical); `noise` (`seed`, `amount`, optional base `colour`). Every random generator requires an integer seed. Noise is sampled in a stable row-major order.
74
+ Generators: `solid` (`colour`); `gradient` (`from`, `to`, `angle`, with 0° horizontal and 90° vertical); `noise` (`seed`, `amount`, optional base `colour`). Every noise generator requires an explicit integer seed. Noise is sampled in a stable row-major order.
70
75
 
71
76
  Blend modes: normal, multiply, screen, overlay, darken, lighten, difference, soft-light, hard-light. Compositing and colour adjustments use Skia's sRGB path; this is not a linear-light color grading engine.
72
77
 
@@ -115,12 +120,44 @@ Tiles have canvas bounds, a single-character palette, and rows of keys. Rows mus
115
120
 
116
121
  `replaceTile` replaces a tile with exactly matching bounds or appends a new one. Transparent tile pixels composite over underlying layer content. Palette tiles remain compact grids. Separately, `promoteRegion`, `updateRegion` and `demoteRegion` manage patches with 1–4× resolution and optional external raster sources; see [evolution](evolution.md).
117
122
 
123
+ For a complete pixel-art and sprite workflow, see [Pixel art, sprites and
124
+ spritesheets](sprites.md). An optional pixel-art scene contract makes integer
125
+ coordinates, palette use and nearest-neighbour delivery explicit:
126
+
127
+ ```yaml
128
+ pixel_art:
129
+ scale: 1 # authored tile pixel → scene-pixel multiplier
130
+ palette: ['#00000000', '#f2be81', '#b75c40']
131
+ strict: true # reject transforms/blur and invalid tile geometry
132
+ ```
133
+
134
+ The optional `sprites` manifest selects integer canvas rectangles and records
135
+ their game-facing pivot, duration and tags. Animations list frame IDs and a
136
+ loop flag. Atlas settings support padding, edge extrusion, power-of-two output
137
+ and a maximum width:
138
+
139
+ ```yaml
140
+ sprites:
141
+ frames:
142
+ walk_0: { bounds: [0, 0, 16, 16], pivot: [8, 14], duration: 120, tags: [walk, right] }
143
+ animations:
144
+ walk_right: { frames: [walk_0], loop: true }
145
+ atlas: { padding: 1, extrusion: 1, power_of_two: true, max_width: 2048 }
146
+ ```
147
+
148
+ `rtistree sprites scene.json -o atlas.png --manifest atlas.json` renders the
149
+ declared frame rectangles and writes an engine-neutral, deterministic atlas
150
+ manifest. Frames are not trimmed; exported records retain both atlas and source
151
+ rectangles. Use `rtistree schema --kind scene` for the complete scene contract
152
+ and `rtistree schema --kind sprites` for export options in the installed version.
153
+
118
154
  ## Commands and verification
119
155
 
120
- `apply` accepts `{reason, expected_hash?, commands: [...]}`. Commands include add/remove/move/resize layer, set opacity/blend/text/style, group siblings, align/distribute siblings, apply effect, apply raster operation, and replace tile. See `graphics schema --kind command` for exact fields. Removing referenced mask or verification targets is rejected unless the resulting scene is valid. Grouping can change compositing with interleaved siblings; it is an explicit structural edit without a locality promise.
156
+ `apply` accepts `{reason, expected_hash?, commands: [...]}`. Commands include add/remove/move/resize layer, set opacity/blend/text/style, group siblings, align/distribute siblings, apply effect, apply raster operation, and replace tile. See `rtistree schema --kind command` for exact fields. Removing referenced mask or verification targets is rejected unless the resulting scene is valid. Grouping can change compositing with interleaved siblings; it is an explicit structural edit without a locality promise.
121
157
 
122
158
  Verification always checks rendered text overflow. Optional rules cover safe-area, text-overflow, text-equals, required-role, contrast, no-overlap and region-luma. Luma is a mean weighted sRGB channel value in [0,1], not perceptual luminance. `contrast` uses declared foreground and explicit background colours. `pixel-contrast` and `visible-area` use counterfactual rendered samples through `verifyRendered` / `Project.verify`. Geometry checks use transformed bounding boxes, not exact silhouettes. A heatmap marks issue bounds. All reports state these limitations.
123
159
 
124
- `render-region` requires an integer rectangle fully inside the canvas and equals an exact crop of the full render. `draft` halves both output dimensions after rendering; preview and final currently use the same full-quality pipeline. PNG output includes renderer evidence in a sidecar. Canonical scene hashes omit timestamps; history includes timestamps for audit purposes without influencing pixel output.
160
+ `render-region` requires an integer rectangle fully inside the canvas and equals an exact crop of the full render. `draft` halves both output dimensions after rendering; preview and final currently use the same full-quality pipeline. PNG output includes renderer evidence in a sidecar. Scene hashes cover the resolved scene, including authored metadata. Journal timestamps are outside
161
+ that scene hash and do not influence pixel output; a timestamp you put in scene metadata does change the hash.
125
162
 
126
163
  The [evolution guide](evolution.md) documents the expanded command surface, coordinates, components, fonts, adaptive regions, critiques, rebase, compaction, and agent trials.
@@ -0,0 +1,166 @@
1
+ # Pixel art, sprites and spritesheets
2
+
3
+ Rtistree can author small raster assets and package them as a sprite set. The
4
+ sprite workflow is deliberately split into two jobs:
5
+
6
+ 1. draw and inspect each frame as an ordinary Rtistree scene or studio asset;
7
+ 2. describe the frames, pivots and animation timing in a `sprites` manifest and
8
+ export a deterministic atlas for the game or other runtime to consume.
9
+
10
+ This keeps the artwork editable and reviewable while making the delivery format
11
+ boring and portable. Rtistree is an asset authoring and verification tool here;
12
+ it is not a game engine, a runtime animation system or an automatic animation
13
+ critic.
14
+
15
+ ## Choose the pixel-art contract
16
+
17
+ Use the optional `pixel_art` scene contract when the image is meant to be read
18
+ as pixels rather than as a smoothly sampled illustration. A pixel-art scene
19
+ should declare its palette policy and grid scale, then keep the following
20
+ invariants visible to the agent and reviewer:
21
+
22
+ - coordinates and frame dimensions are integer pixels;
23
+ - colour choices come from the declared palette, including transparency;
24
+ - `scale` is an integer multiplier from a tile's authored grid to its
25
+ scene-pixel bounds;
26
+ - atlas sampling uses nearest-neighbour filtering;
27
+ - frame canvases and pivots are stable across an animation;
28
+ - strict mode rejects transforms, rotation and blur on the scene's pixel-art
29
+ layers and checks tile geometry and declared palette membership.
30
+
31
+ The contract does not make a weak drawing good. It makes common production
32
+ mistakes detectable and makes an intentional one-pixel edit auditable. Keep
33
+ the intended game display size in the brief and inspect the result at that size
34
+ as well as zoomed in.
35
+
36
+ For small, deliberately indexed marks, palette tiles are the compact scene
37
+ primitive:
38
+
39
+ ```yaml
40
+ - id: lantern
41
+ type: raster
42
+ tiles:
43
+ - bounds: [8, 8, 10, 6]
44
+ palette:
45
+ .: '#00000000'
46
+ a: '#f2be81'
47
+ b: '#b75c40'
48
+ pixels:
49
+ - '....aa....'
50
+ - '...abba...'
51
+ - '..abbbba..'
52
+ - '..abbbba..'
53
+ - '...abba...'
54
+ - '....aa....'
55
+ ```
56
+
57
+ Rows must be equal in width and every key must exist in the palette. Palette
58
+ tiles are limited to 256 × 256 and are scaled with nearest-neighbour sampling.
59
+ Use `replaceTile` for an auditable tile-sized revision. For dense or generated
60
+ frames, use the studio's `art.raster`, `art.pixels` and `art.put` APIs instead;
61
+ those bake ordinary PNG assets with a replayable recipe.
62
+
63
+ The complete scene and command shapes are in [scene format](scene-format.md).
64
+ Run `rtistree schema --kind scene` or `rtistree schema --kind command` against
65
+ the installed version rather than copying a stale schema from a blog post.
66
+
67
+ ## Build a sprite set
68
+
69
+ Start with one representative character frame and one representative prop.
70
+ Record the intended facing, ground line, display scale, palette, silhouette and
71
+ pivot before multiplying the set. A useful frame brief says what must remain
72
+ stable (for example, the foot contact point) and what changes (for example,
73
+ the lifted leg).
74
+
75
+ The scene's `sprites` manifest is the delivery description for a set. Each
76
+ `frames[id].bounds` is a canvas rectangle selecting source pixels. The exporter
77
+ writes a JSON manifest in which each output `frames[id]` records:
78
+
79
+ - the frame rectangle in the atlas;
80
+ - the original canvas `source` rectangle;
81
+ - the pixel pivot or origin used by the game;
82
+ - optional duration and tags such as `idle`, `contact` or `recovery`;
83
+ - animation order and loop behaviour; use tags to carry labels such as facing.
84
+
85
+ Atlas placement is deterministic. The same frame inputs and atlas settings
86
+ produce the same packed image and metadata on the same pinned runtime. Keep
87
+ the atlas image and its metadata together; the metadata is part of the asset,
88
+ not an optional comment for the viewer.
89
+
90
+ Export the set with the installed command:
91
+
92
+ ```sh
93
+ npx rtistree sprites scene.json -o output/sprites.png --manifest output/sprites.json
94
+ ```
95
+
96
+ The command accepts a scene or configured project containing the sprite
97
+ manifest. Use `npx rtistree sprites --help` and the installed schema/help
98
+ output for the exact options in the release you are using. The PNG path must
99
+ end in `.png` and the manifest path in `.json`. The export produces an atlas
100
+ image plus machine-readable frame and animation metadata. Frames are not
101
+ trimmed or rotated. `padding`, `extrusion`, `power_of_two` and `max_width`
102
+ control packing; edge extrusion copies the frame's edge pixels and the
103
+ remaining padding stays transparent.
104
+
105
+ The same export is available through the SDK as `exportSpriteSheet(project,
106
+ output, options)` and through the MCP `exportSprites` tool. SDK callers should
107
+ retain the returned atlas and metadata as release artifacts; MCP callers should
108
+ expose the result to the agent so it can inspect the actual image and not only
109
+ the JSON. The MCP tool writes `<name>.png` and `<name>.json` into the configured
110
+ project output directory.
111
+
112
+ ## Review an animation before shipping it
113
+
114
+ Technical validity and animation quality are separate gates. For each set,
115
+ check the following in order:
116
+
117
+ 1. Render every frame and inspect a contact sheet at the intended display size.
118
+ 2. Confirm frame dimensions, alpha margins, palette use, atlas rectangles and
119
+ pivots against the manifest.
120
+ 3. Play a complete loop against a ground marker. Inspect contact, passing and
121
+ recovery frames, then inspect the loop boundary.
122
+ 4. Check that the subject's silhouette, weight, facing and prop ownership read
123
+ consistently. For walking, planted feet should remain coherent against the
124
+ ground while lifted feet recover in the travel direction.
125
+ 5. Record technical, functional and visual results separately. A set can have
126
+ reproducible PNGs and valid metadata while still being rejected for weak
127
+ posing, muddy silhouettes or a broken loop.
128
+
129
+ `rtistree verify` can check declared technical constraints and scoped changes;
130
+ it cannot watch a loop, judge a silhouette or prove that a reviewer looked at
131
+ the image. Keep the rendered frames, contact sheet, atlas, manifest and any
132
+ rejected revision together so a later agent can compare against the actual
133
+ parent rather than trusting a summary.
134
+
135
+ ## Existing example
136
+
137
+ The [Verdigris Watch asset trial](https://github.com/Coly010/rtistree/tree/main/examples/warden-asset-trial)
138
+ is the reference end-to-end example. It draws 17 transparent sprites, bakes an
139
+ eight-frame walk cycle, records fixed pivots and 8 fps playback metadata, packs
140
+ an atlas, and provides a small viewer for stepping through the loop. Its
141
+ `render.mjs` and `verify.mjs` intentionally keep atlas assembly and motion
142
+ checks visible, so the example also documents what the first-class export is
143
+ meant to make less bespoke.
144
+
145
+ The trial is evidence of a reproducible workflow, not a claim that every image
146
+ is production-quality. Read its review and inspect the actual frames before
147
+ using it as a visual reference.
148
+
149
+ For the smallest strict-pixel example, see
150
+ [`examples/pixel-sprite-lab`](https://github.com/Coly010/rtistree/tree/main/examples/pixel-sprite-lab).
151
+ It uses four 16 × 16 palette-tile frames, a fixed `[8, 14]` pivot, 120 ms
152
+ durations, a `walk_right` animation, one-pixel padding and one-pixel edge
153
+ extrusion. Its verifier checks source-to-atlas pixels, palette use, fixed
154
+ pivots and deterministic cold export.
155
+
156
+ ## Scope and limits
157
+
158
+ The sprite workflow is a neutral asset format. It does not add a dependency on
159
+ Godot, Unity, Phaser or another game engine, and it does not promise a native
160
+ timeline, inverse kinematics, automatic retargeting, palette optimisation or
161
+ automatic visual approval. A renderer or game project can consume the atlas and
162
+ metadata through its own adapter.
163
+
164
+ For a broader view of the agent protocol, read [art direction for agents](agent-art-workflow.md),
165
+ then [programmable digital art](studio.md) for seeded frame generation and
166
+ [production](production.md) for general image export.
package/docs/studio.md CHANGED
@@ -1,14 +1,26 @@
1
- # Programmable digital art in v0.4
1
+ # Programmable digital art
2
2
 
3
3
  The studio is the escape hatch below scene abstractions. An agent can build an image using paths and gradients, paint pressure-sensitive strokes, calculate pixel colours, sample textures, or write a custom image-processing algorithm. No image-generation model is used by these tools.
4
4
 
5
5
  Scene layers still describe composition. Programs produce ordinary pinned PNG assets and can replace the source of a raster/image layer. Their exact source, seed, parameters, input snapshots and output hash are saved as a recipe. Rendering, inspecting and opening a scene never runs a program. Re-execution is explicit, and existing edits remain undoable.
6
6
 
7
+ This is also the frame-generation path for sprites: keep the frame construction
8
+ function pure and parameterise its pose or animation phase, then bake one asset
9
+ per frame. A `sprites` manifest can reference those frames and the sprite
10
+ exporter can pack them into an atlas with pivots, durations and animation tags.
11
+ See [pixel art, sprites and spritesheets](sprites.md) for the review and delivery
12
+ workflow.
13
+
7
14
  ## First painting
8
15
 
16
+ Run these commands from a directory where `npm install rtistree` has already completed.
17
+ `project new` creates a scene project; unlike `init`, it does not create a package.json
18
+ or install Rtistree. The custom size `100x100` is in millimetres and gives this example
19
+ a 400 × 400 design canvas.
20
+
9
21
  ```sh
10
- graphics project new study --size 100x100
11
- graphics studio-help
22
+ npx rtistree project new study --size 100x100
23
+ npx rtistree studio-help
12
24
  ```
13
25
 
14
26
  Save this as `study/programs/rubber.js`:
@@ -41,16 +53,16 @@ Save a request as `study/paint.json`:
41
53
  ```
42
54
 
43
55
  ```sh
44
- graphics program study study/paint.json
45
- graphics render study -o study/output/rubber.png
46
- graphics program-replay study rubberPaint
56
+ npx rtistree program study study/paint.json
57
+ npx rtistree render study -o study/output/rubber.png
58
+ npx rtistree program-replay study rubberPaint
47
59
  ```
48
60
 
49
61
  Supply exactly one of `source` (a project-local JavaScript file) or `code` (an inline function body). A program receives `art` and `parameters`, runs synchronously and returns one Canvas with the declared dimensions. It cannot import modules through the public API. A new `target` creates a raster layer; an existing target must accept an image source. Omit `target` to register an asset for subsequent mask, region or layer operations. The runner captures the starting scene hash and rejects a concurrent edit before committing.
50
62
 
51
63
  ## Authoring vocabulary
52
64
 
53
- `graphics studio-help` and the MCP `studioHelp` tool expose the complete signatures and a runnable example. TypeScript consumers can use `RasterStudio` from the SDK.
65
+ `rtistree studio-help` and the MCP `studioHelp` tool expose the complete signatures and a runnable example. TypeScript consumers can use `RasterStudio` from the SDK.
54
66
 
55
67
  | API | Purpose |
56
68
  | ----------------------------------------------- | ------------------------------------------------------------------------------- |
@@ -72,9 +84,10 @@ Height-field lighting is an artistic 2.5D calculation, with the viewer along pos
72
84
 
73
85
  ## Dense regional edits
74
86
 
75
- `readRasterRegion` / `graphics raster-read PROJECT request.json` read a PNG crop of the composite or an isolated layer. The request contains integer canvas-space `bounds` and an optional `target`. The result includes the scene hash and an asset descriptor ready for `registerAsset`.
87
+ `readRasterRegion` / `rtistree raster-read PROJECT request.json` read a PNG crop of the composite or an isolated layer. The request contains integer canvas-space `bounds` and an optional `target`. The result includes the scene hash and an asset descriptor (`source` and `hash`). Wrap
88
+ that descriptor in a `registerAsset` command with an `id` before using it as a program input.
76
89
 
77
- `writeRasterRegion` / `graphics raster-write PROJECT request.json` consumes:
90
+ `writeRasterRegion` / `rtistree raster-write PROJECT request.json` consumes:
78
91
 
79
92
  ```json
80
93
  {
@@ -89,7 +102,8 @@ Height-field lighting is an artistic 2.5D calculation, with the viewer along pos
89
102
  }
90
103
  ```
91
104
 
92
- The source must be a project-local PNG matching the region's exact dimensions. `replace` clears/replaces the region, including alpha; `over` composites it onto the previous pixels. The command creates or updates a named promoted region at scale 1 and stores an immutable copy of the PNG. `space: layer` captures reference dimensions, so the patch follows later transforms and resizing. `space: canvas` stays at canvas coordinates. Existing layer masks/effects still apply; locality validation rejects changes leaking outside the declared region. Undo/redo restores the prior image.
105
+ The source must be a project-local PNG matching the region's exact dimensions. `replace` clears/replaces the region, including alpha; `over` composites it onto the previous pixels. The command creates or updates a named promoted region at scale 1 and stores an immutable copy of the PNG. `space: layer` captures reference dimensions, so the patch follows later transforms and resizing. `space: canvas` stays at canvas coordinates. The patch is composited after the target layer’s effects and ordinary operations, but
106
+ before its mask and opacity. Ancestor effects can still change its appearance; locality validation rejects changes leaking outside the declared region. Undo/redo restores the prior image.
93
107
 
94
108
  For a custom filter, register the descriptor returned by the read, pass that asset to `runProgram.inputs`, calculate the new pixels, and write the returned PNG into a region. Use the latest scene hash returned by each mutation. Canvas-space reads cannot automatically become local-space reads of a rotated object; use canvas-space patch coordinates for a direct read/edit/write round trip.
95
109
 
@@ -101,8 +115,9 @@ Programs execute only when explicitly requested and must be trusted code. A work
101
115
 
102
116
  The runner checks a 16-megapixel output limit, 16 input images, an 8,192-pixel edge, 256 KiB source, 64 KiB parameters, and up to 30 seconds of execution. The parent watchdog allows two additional seconds for worker setup. Studio helper allocations are capped at 32 cumulative megapixels including inputs; V8's heap limit is 256 MiB. Native Canvas buffers and arbitrary allocations made through exposed native objects are outside the V8 accounting, so these limits are not an OS memory quota. Scene rendering retains its separate surface budget.
103
117
 
104
- The studio has no live dependency graph. Changing program code, parameters or an input does not automatically rebake dependent assets. Explicit execution replaces a target source through the existing transaction/history mechanism. If execution or commit fails, the scene is unchanged; a late failed commit can leave unreferenced content-addressed artifacts.
118
+ Programs do not rebake automatically. The [pipeline API](atelier.md) provides an explicit
119
+ dependency graph with caching; run it when you want to rebuild changed nodes. Changing program code, parameters or an input does not automatically rebake dependent assets. Explicit execution replaces a target source through the existing transaction/history mechanism. If execution or commit fails, the scene is unchanged; a late failed commit can leave unreferenced content-addressed artifacts.
105
120
 
106
121
  ## Trial
107
122
 
108
- The [manual wheel trial](../examples/manual-wheel-trial/README.md) used no model-generated or downloaded imagery. Its eight layers were painted with code, geometry, material fields, text and brushes. Source, recipes, initial/refined images, critiques and replay checks are retained. The result demonstrates a reproducible digital illustration; its visual evaluation explicitly leaves photographic realism unachieved.
123
+ The [manual wheel trial](https://github.com/Coly010/rtistree/blob/main/examples/manual-wheel-trial/README.md) used no model-generated or downloaded imagery. Its eight layers were painted with code, geometry, material fields, text and brushes. Source, recipes, initial/refined images, critiques and replay checks are retained. The result demonstrates a reproducible digital illustration; its visual evaluation explicitly leaves photographic realism unachieved.