rtistree 0.5.1 → 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 (51) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/CONTRIBUTING.md +47 -0
  3. package/README.md +14 -5
  4. package/SECURITY.md +20 -0
  5. package/THIRD_PARTY_NOTICES.md +1 -1
  6. package/dist/cli.js +17 -3
  7. package/dist/cli.js.map +1 -1
  8. package/dist/commands.d.ts +12 -0
  9. package/dist/index.d.ts +1 -0
  10. package/dist/index.js +1 -0
  11. package/dist/index.js.map +1 -1
  12. package/dist/mcp.js +18 -2
  13. package/dist/mcp.js.map +1 -1
  14. package/dist/print-scene.d.ts +6 -0
  15. package/dist/program.js +3 -1
  16. package/dist/program.js.map +1 -1
  17. package/dist/project-config.js +2 -1
  18. package/dist/project-config.js.map +1 -1
  19. package/dist/render.js +21 -1
  20. package/dist/render.js.map +1 -1
  21. package/dist/schema.d.ts +46 -0
  22. package/dist/schema.js +107 -0
  23. package/dist/schema.js.map +1 -1
  24. package/dist/sprites.d.ts +31 -0
  25. package/dist/sprites.js +142 -0
  26. package/dist/sprites.js.map +1 -0
  27. package/dist/studio-reference.js +1 -1
  28. package/dist/studio-reference.js.map +1 -1
  29. package/docs/agent-art-workflow.md +10 -0
  30. package/docs/agent-setup.md +8 -3
  31. package/docs/atelier.md +12 -1
  32. package/docs/cli-reference.md +76 -25
  33. package/docs/core-concepts.md +95 -0
  34. package/docs/decisions/004-print-production-and-projects.md +1 -1
  35. package/docs/decisions/005-programmable-digital-art.md +1 -1
  36. package/docs/engine-overview.md +121 -165
  37. package/docs/evolution.md +12 -9
  38. package/docs/getting-started.md +15 -8
  39. package/docs/next-milestone.md +4 -4
  40. package/docs/production.md +22 -16
  41. package/docs/releasing.md +99 -43
  42. package/docs/scene-format.md +44 -7
  43. package/docs/sprites.md +166 -0
  44. package/docs/studio.md +25 -10
  45. package/examples/hello/README.md +4 -0
  46. package/package.json +8 -5
  47. package/schemas/authoring.schema.json +359 -229
  48. package/schemas/command.schema.json +462 -332
  49. package/schemas/patch.schema.json +462 -332
  50. package/schemas/scene.schema.json +347 -217
  51. package/schemas/sprites.schema.json +41 -0
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 `rtistree 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
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
- rtistree project new study --size 100x100
11
- rtistree 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,9 +53,9 @@ Save a request as `study/paint.json`:
41
53
  ```
42
54
 
43
55
  ```sh
44
- rtistree program study study/paint.json
45
- rtistree render study -o study/output/rubber.png
46
- rtistree 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.
@@ -72,7 +84,8 @@ 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` / `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 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
90
  `writeRasterRegion` / `rtistree raster-write PROJECT request.json` consumes:
78
91
 
@@ -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.
@@ -1,5 +1,9 @@
1
1
  # Your first Rtistree project
2
2
 
3
+ Run these commands inside a project created by `npx rtistree@latest init my-art`.
4
+ If you are reading this in the repository’s `examples/hello` directory, create a project
5
+ first: these are template files, and `init` supplies the package.json and npm scripts.
6
+
3
7
  ```sh
4
8
  npm install
5
9
  npm run render
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rtistree",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "description": "Deterministic, agent-operable raster graphics engine",
5
5
  "main": "./dist/index.js",
6
6
  "scripts": {
@@ -11,12 +11,13 @@
11
11
  "graphics": "node --import tsx src/cli.ts",
12
12
  "demo": "node --import tsx scripts/demo.ts",
13
13
  "schema": "node --import tsx scripts/schema.ts",
14
- "format": "prettier --write src tests scripts docs examples schemas README.md package.json tsconfig.json .github .prettierrc.json",
15
- "format:check": "prettier --check src tests scripts docs examples schemas README.md package.json tsconfig.json .github .prettierrc.json",
14
+ "format": "prettier --write src tests scripts docs examples schemas README.md package.json tsconfig.json .github .prettierrc.json release-please-config.json .release-please-manifest.json CONTRIBUTING.md",
15
+ "format:check": "prettier --check src tests scripts docs examples schemas README.md package.json tsconfig.json .github .prettierrc.json release-please-config.json .release-please-manifest.json CONTRIBUTING.md",
16
16
  "performance": "node --import tsx scripts/performance.ts",
17
17
  "prepack": "npm run build",
18
18
  "package:check": "node scripts/package-smoke.mjs",
19
- "rtistree": "node --import tsx src/cli.ts"
19
+ "rtistree": "node --import tsx src/cli.ts",
20
+ "docs:check": "npm run build && node scripts/docs-smoke.mjs"
20
21
  },
21
22
  "keywords": [
22
23
  "graphics",
@@ -68,7 +69,9 @@
68
69
  "CHANGELOG.md",
69
70
  "THIRD_PARTY_NOTICES.md",
70
71
  "licenses",
71
- "examples/hello"
72
+ "examples/hello",
73
+ "SECURITY.md",
74
+ "CONTRIBUTING.md"
72
75
  ],
73
76
  "license": "MIT",
74
77
  "author": "Colum Ferry",