asciify-engine 4.8.0 → 4.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,15 @@
1
+ import { STUDIO_ANIMATION_PRESETS } from 'asciify-engine/studio';
2
+ import { createComposition } from './studio-composition.js';
3
+
4
+ /** A live still-image composition, with settings persistence and independent export. */
5
+ export async function createLivingImage(canvas: HTMLCanvasElement, source: File | string, signal?: AbortSignal) {
6
+ const composition=await createComposition(canvas,source,signal);
7
+ function applyAnimation(id: string) {
8
+ const preset=STUDIO_ANIMATION_PRESETS.find(item=>item.id===id);
9
+ if(!preset)throw new Error(`Unknown animation preset: ${id}`);
10
+ // Partial group updates preserve edgeSafe, the art style, source and finish.
11
+ composition.update({motion:preset.motion,hover:preset.hover});
12
+ }
13
+ applyAnimation('quiet-light');
14
+ return {...composition,applyAnimation};
15
+ }
@@ -0,0 +1,15 @@
1
+ import { createComposition } from './studio-composition.js';
2
+
3
+ /** Live image, saved controls, and independent PNG/MP4 export in one reusable component. */
4
+ export async function createLivingPrint(canvas: HTMLCanvasElement, source: File | string, signal?: AbortSignal) {
5
+ const composition = await createComposition(canvas, source, signal);
6
+ composition.update({
7
+ style: 'engraving', cellSize: 7, colorMode: 'accent', ink: '#becbbe',
8
+ print: { angle: -35, weight: 1.1, roughness: .3 },
9
+ backdrop: { color: '#101810' },
10
+ motion: { type: 'sheen', speed: .5, amount: .4 },
11
+ hover: { effect: 'water', radius: .4, strength: .5 },
12
+ });
13
+ // On unmount, call the returned destroy(). Export owns independent media.
14
+ return composition;
15
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "asciify-engine",
3
- "version": "4.8.0",
3
+ "version": "4.10.0",
4
4
  "description": "Framework-agnostic ASCII art engine. Convert images, videos, and GIFs into ASCII art rendered on canvas.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -57,8 +57,10 @@
57
57
  "examples/media-background.ts",
58
58
  "examples/studio-composition.ts",
59
59
  "examples/layered-composition.ts",
60
+ "examples/print-composition.ts",
60
61
  "THIRD_PARTY.md",
61
- "licenses"
62
+ "licenses",
63
+ "examples/living-image.ts"
62
64
  ],
63
65
  "scripts": {
64
66
  "build": "tsup",
@@ -2,13 +2,13 @@
2
2
  name: asciify-engine
3
3
  description: Build and tune browser ASCII images, video, GIFs, text, and interactive heroes with asciify-engine. Use for media conversion, character and color choices, hover integration, layered HTML typography, scroll-synced video, and rendering performance in apps using this package.
4
4
  metadata:
5
- tested-engine: "4.8.0"
5
+ tested-engine: "4.10.0"
6
6
  updated: "2026-10-07"
7
7
  ---
8
8
 
9
9
  # Asciify Engine
10
10
 
11
- Use the published `asciify-engine` npm package for browser canvas rendering. Tested against **4.8.0**. Check the application's installed version and its public types before using newer options; a local checkout can contain unpublished changes.
11
+ Use the published `asciify-engine` npm package for browser canvas rendering. Tested against **4.10.0**. Check the application's installed version and its public types before using newer options; a local checkout can contain unpublished changes.
12
12
 
13
13
  - Agent entry: https://asciify.org/skill (redirects to this Markdown document).
14
14
  - Playground: https://asciify.org/editor
@@ -92,7 +92,7 @@ Preview it: letter glyph densities differ, so arbitrary words are not automatica
92
92
 
93
93
  The public npm `HoverEffect` IDs in 1.2.0 are `spotlight`, `magnify`, `repel`, `glow`, `colorShift`, `attract`, `shatter`, `trail`, and `glitchText`. Those remain valid APIs, but they are **not identical to the current website's enhanced interactions**.
94
94
 
95
- The website offers **Trail, Water, Contour, Dissolve, Silk, Vortex, Magnetic Pull, Scatter, Emboss, Elastic, Rake, and Off** through an optional studio surface module. Its ten still-image motions—Caustics, Slow Current, Reveal & Reform, Sheen, Tidal Rings, Living Grain, Parallax, Woven Flow, Print Shift, Contour Light—and fine-dither treatments ship in the same `asciify-engine/hover` module. Use its typed options rather than converting display names into engine `hoverEffect` or `animationStyle` values.
95
+ The website offers **Trail, Water, Contour, Dissolve, Silk, Vortex, Magnetic Pull, Scatter, Emboss, Elastic, Rake, Lens wake, Smudge, Ripple rings, and Off** through an optional studio surface module. Its fourteen still-image motions—Caustics, Slow Current, Reveal & Reform, Sheen, Tidal Rings, Living Grain, Parallax, Woven Flow, Print Shift, Contour Light, Relight, Shimmer, Breeze, Unfold—and fine-dither treatments ship in the same `asciify-engine/hover` module. Use its typed options rather than converting display names into engine `hoverEffect` or `animationStyle` values.
96
96
 
97
97
  To reproduce those interactions, read [references/studio-effects.md](references/studio-effects.md). Import `mountHover` from `asciify-engine/hover` (1.2.0+); no separate download is needed. Keep engine `hoverStrength: 0` and `animationStyle: 'none'` when using it, to avoid applying two effects. Trail is the site's default. Prefer a stationary-grid effect such as Trail or Dissolve when the user wants a wake without spatial displacement.
98
98
 
@@ -143,7 +143,7 @@ For optional wallpaper/backdrops, alternate renderers, palettes, masks, saved lo
143
143
 
144
144
  For multiple media/text layers in one live component, use 4.8+ `mountStudioProject` and read [layered-projects.md](references/layered-projects.md). It shares one playback loop and rendering budgets across up to eight independently styled layers. Persist source keys separately from media, and use `exportStudioProject` for independent exports. Do not create one mounted Studio instance per layer or rasterize accessible interface text.
145
145
 
146
- Legacy `CHARSETS`, `ART_STYLE_PRESETS`, `CHARSET_SEQUENCES`, `LIVING_STYLE_PRESETS` and their key types are removed. Do not import them or generate old names such as Katakana, Binary, Waves or Smoke. Use the 18 `STUDIO_STYLES` for render-style selectors and `/studio` rendering. For ASCII-only character ramps use `CHARACTER_SETS` from `/core` or `STUDIO_CHARACTER_SETS` from `/studio`; custom Unicode and user-provided frame arrays remain supported. Core `artStyle` only accepts `classic`; use explicit options instead of preset shortcuts. Despite the requested 4.1.0 version number, migrating these removed APIs is a breaking change.
146
+ Legacy `CHARSETS`, `ART_STYLE_PRESETS`, `CHARSET_SEQUENCES`, `LIVING_STYLE_PRESETS` and their key types are removed. Do not import them or generate old names such as Katakana, Binary, Waves or Smoke. Use the 24 `STUDIO_STYLES` for render-style selectors and `/studio` rendering. For ASCII-only character ramps use `CHARACTER_SETS` from `/core` or `STUDIO_CHARACTER_SETS` from `/studio`; custom Unicode and user-provided frame arrays remain supported. Core `artStyle` only accepts `classic`; use explicit options instead of preset shortcuts. Despite the requested 4.1.0 version number, migrating these removed APIs is a breaking change.
147
147
 
148
148
 
149
149
  ## Fine dither and creative controls (4.2)
@@ -155,3 +155,9 @@ From 4.5, `dither.algorithm: 'blue-noise'` uses a precomputed dispersed threshol
155
155
  From 4.6, Studio adds `color.curves` (RGB, red, green, blue) and optional edge-preserving `color.denoise`. `player.settings` returns a detached snapshot for saving or exporting after updates. Read [channel curves and source noise](references/studio-workspace.md#channel-curves-and-source-noise-46) for point limits, update semantics and the processing budget. Do not turn noise reduction on by default or apply it again to the already-rendered characters.
156
156
 
157
157
  From 4.7, Studio supports up to eight ordered source warps: Twirl, Pinch, Spherize, Ripple, Zigzag, Shear, Smudge, Polar and Fragment. Build controls from `STUDIO_WARPS`, retain array order, and read [source shaping](references/source-shaping.md) for bounds, alpha/edge policy and cached-map performance. These shape the source; use `motion.type` to bring a still image to life and `hover.effect` for pointer interaction. Keep them independent, with an empty warp stack by default.
158
+
159
+ From 4.9, optional Studio adds Stipple, Engraving, Crosshatch, Woodblock, Risograph and Pointillism with a shared `print` settings group. Read [print and illustration](references/print-styles.md) for exact controls, light-ink versus dark-ink polarity, still-motion integration and dense-render limits. These are genuine additional render paths; do not substitute dither presets for their IDs.
160
+
161
+ ## Lively images and interaction starting points (4.10)
162
+
163
+ `STUDIO_ANIMATION_PRESETS` provides six editable motion/hover pairings through `/studio` and `/hover`. Apply `motion` and `hover` to an existing Studio player to keep the source and art style; do not treat the pairings as additional art styles. Read [studio-effects.md](references/studio-effects.md#lively-images-410) for exact new IDs, loop limits and the live component example.
@@ -0,0 +1,63 @@
1
+ # Print and illustration (4.9)
2
+
3
+ Six local Canvas renderers live in the optional `asciify-engine/studio` entry. They do not change the default ASCII style or add a server/provider. They share source grading, curves, warps, masks, hover, still-image motion, finishing, saved settings, single-image export and layered projects.
4
+
5
+ | Style ID | Mechanism | Useful controls |
6
+ | --- | --- | --- |
7
+ | `stipple` | Four spatially jittered dots per sample; tone changes their area | Coverage, weight, texture, seed |
8
+ | `engraving` | Parallel world-anchored cuts with tone-dependent width | Coverage, weight, angle, texture |
9
+ | `crosshatch` | Up to three crossing screens appear across the tonal range | Coverage, weight, angle, texture |
10
+ | `woodblock` | Five tone steps in broad carved bands with correlated irregular edges | Coverage, weight, angle, texture |
11
+ | `risograph` | Two overlapping ink-dot screens; source warmth separates coverage in source-color mode | Second ink, registration offset/direction, texture |
12
+ | `pointillism` | Four small elliptical pigment strokes per sample | Source color, weight, texture, seed |
13
+
14
+ `STUDIO_PRINT_STYLES` supplies `value`, `label`, and `description` for selectors. `isStudioPrintStyle(style)` identifies this family. The full `STUDIO_STYLES` catalog has 24 styles. Existing `riso` and `print` look IDs remain dither presets; choose `style: 'risograph'` to use the new two-screen renderer. These are print-inspired raster treatments, not physical ink simulation, CMYK separations or vector paths.
15
+
16
+ ## Live still image
17
+
18
+ ```ts
19
+ import { mountStudio } from 'asciify-engine/studio';
20
+
21
+ const player = await mountStudio(canvas, '/your-image.jpg', {
22
+ settings: {
23
+ style: 'engraving', cellSize: 7, colorMode: 'accent', ink: '#becbbe',
24
+ print: { angle: -35, weight: 1.1, roughness: .3 },
25
+ backdrop: { color: '#101810' },
26
+ motion: { type: 'sheen', speed: .5, amount: .4 },
27
+ hover: { effect: 'water', radius: .4, strength: .5 },
28
+ },
29
+ maxDimension: 960, maxCells: 12000,
30
+ onError: console.error,
31
+ });
32
+ player.update({ print: { angle: 20 } }); // retains the other print settings
33
+ const settings = player.settings; // detached snapshot for saving/export
34
+ // On unmount:
35
+ player.destroy();
36
+ ```
37
+
38
+ For dark ink on paper, use `print.invert: true`, a dark `ink`, and a light `backdrop.color`. Inversion chooses which source tones receive ink; it does not change the ink or backdrop automatically. Dissolve reduces ink in either polarity. Trail still inverts the local tonal response. The motion engine retains its own `12 / speed` cycle; the print texture has no independent time source.
39
+
40
+ ## Exact settings
41
+
42
+ `print` is an optional nested group in `StudioInput` and saved version-1 `StudioSettings`. Old files receive compatible defaults. Partial updates merge this group. `normalizeStudioPrint`, `DEFAULT_STUDIO_PRINT`, and `StudioPrintSettings` are exported from `/studio`.
43
+
44
+ | Field | Range / default | Meaning |
45
+ | --- | --- | --- |
46
+ | `density` | 0–2 / 1 | Tonal coverage; zero draws no print marks |
47
+ | `weight` | .25–2 / 1 | Dot/stroke size; size is bounded within the screen |
48
+ | `angle` | −180–180° / −35 | Line angle for engraving/crosshatch/woodblock; registration direction for risograph |
49
+ | `roughness` | 0–1 / .35 | Spatial texture variation; not random animation |
50
+ | `invert` | boolean / false | False draws highlights; true draws shadows |
51
+ | `secondaryInk` | six-digit hex / `#ec6752` | Second risograph ink only |
52
+ | `registration` | 0–1 / .2 | Risograph offset, up to .38 of one cell |
53
+ | `seed` | integer 0–65535 / 7 | Repeatable spatial texture |
54
+
55
+ All print styles use square sampling cells. `cellSize` accepts 1–60 in the reference frame; `studioGrid` still reports any effective budget limit. It is independent of `dither.scale`. Source color and gray modes remain available. Only Pointillism's source-color mode separates pigment hues; accent mode retains the chosen ink. Risograph mixes its two screens on transparent artwork with multiply, then composes that artwork over the chosen backdrop.
56
+
57
+ ## Work and quality limits
58
+
59
+ Compiled screen directions and texture buffers are reused. No per-cell canvas, save/rotate/clip, or new simulation loop is created. A stable still caches the complete composition. Spatial texture uses a deterministic seed and bounded lookup; source tone changes can still change coverage. Woodblock intentionally has stepped tones. Do not label it smooth continuous shading.
60
+
61
+ Dense live print rendering costs more than the sample count alone: Pointillism draws four strokes per cell, Crosshatch up to three screens, and Woodblock emits carved polygons. Start with 12,000 cells, retain adaptive quality for motion, and measure the real device. High-resolution still exports can use a larger explicit budget. Keep the same reference pixel ratio/grid for preview and export.
62
+
63
+ The regression suite checks geometry, normalization, scaling, deterministic texture, composition caching and every hover/motion path. CPU geometry timings exclude actual Canvas drawing, decoding, GPU work and browser frame pacing. Visual output, browser export and mobile frame-rate acceptance are still unverified; do not claim competitor parity or guaranteed FPS from these tests.
@@ -43,6 +43,9 @@ The positioned host must fit the displayed source canvas. The surface appends a
43
43
  | `etch` | Signed light-and-shadow impression; the glyph grid stays fixed. |
44
44
  | `elastic` | Directional momentum, damped recoil and a return to rest. |
45
45
  | `rake` | Alternating strips shear with the pointer, then align again. |
46
+ | `lens` | Smooth local magnification, relaxing when the pointer stops. |
47
+ | `smudge` | Directional source drag with a non-oscillating release. |
48
+ | `ripple` | Expanding signed tonal wave packets; speed-sensitive and fixed-grid. |
46
49
  | `none` | No hover effect. |
47
50
 
48
51
  These are `/hover` module `effect` IDs, not the root engine’s legacy `HoverEffect` values. For example, passing `hoverEffect: 'water'` to the published engine is invalid.
@@ -75,3 +78,29 @@ For a fixed grid, try Contour Light with Emboss. For continuous spatial movement
75
78
  All ambient modes repeat after `12 / speed` seconds. Looping the motion does not guarantee that a source video, film grain, dust, glitch or animated dither has the same boundary. Exported PNG/JPEG captures one frame; MP4/WebM/GIF carries autonomous motion, not live pointer movement. For complete composition export, use `/studio` rather than capturing the hover overlay.
76
79
 
77
80
  The pointer simulations have bounded storage. Elastic allocates its two velocity buffers only when first selected; idle effects stop. This is not a device-independent FPS promise. Test dense grids, fast reversal and the actual finish stack on the target device.
81
+
82
+ ## Lively images (4.10)
83
+
84
+ The catalogs contain fourteen active hover effects and fourteen active ambient motions, plus Off for each. New motion IDs are `relight`, `shimmer`, `breeze`, and `unfold`. Relight models midtones with a rotating light field; Shimmer slowly animates source highlights. Both keep geometry stationary. Breeze bends the image with a traveling sway. Unfold closes and opens staggered panels, then holds the complete image. All use deterministic 12-second base cycles; `motion.speed` changes cycle duration, `motion.amount` changes strength. These are local image treatments, not AI-generated scene or subject motion.
85
+
86
+ `STUDIO_ANIMATION_PRESETS` is exported by `/studio` and `/hover`. Its six entries have `id`, `label`, `description`, `motion: {type,speed,amount}`, and `hover: {effect,radius,strength}`. These are editable combinations, not additional renderer styles. Do not overwrite the rest of a user's settings to apply one:
87
+
88
+ ```ts
89
+ import { mountStudio, STUDIO_ANIMATION_PRESETS } from 'asciify-engine/studio';
90
+ const preset = STUDIO_ANIMATION_PRESETS.find(item => item.id === 'quiet-light')!;
91
+ const player = await mountStudio(canvas, '/photo.webp', {
92
+ settings: { style: 'ascii', cellSize: 6, motion: preset.motion, hover: preset.hover },
93
+ maxDimension: 960,
94
+ });
95
+ player.update({ motion: { amount: .6 }, hover: { radius: .55 } });
96
+ // Stop on unmount. Do not mount a second /hover instance on this canvas.
97
+ player.destroy();
98
+ ```
99
+
100
+ For a complete integration with independent PNG/MP4 export, copy the repository's `examples/living-image.ts` and `examples/studio-composition.ts`. Keep their relative import together; these helpers are example application code, not npm exports. Saved Studio state stores the resolved settings, so later catalog edits do not change a saved look.
101
+
102
+ For `/hover`, the same catalog needs an explicit shape conversion: `surface.update({ motion: preset.motion.type, motionSpeed: preset.motion.speed, effect: preset.hover.effect, radius: preset.hover.radius, strength: preset.hover.strength })`. `/hover` has no `motion.amount` option; use Studio for independently adjustable motion strength. Do not spread the nested Studio groups directly into surface options.
103
+
104
+ Ripple rings uses at most eight wave packets and a fixed-resolution field. It does not allocate particles per character. Lens and Smudge reuse the existing field; their release integrates elapsed time, not a fixed frame count. Zero strength suppresses hover input; completed wakes sleep. These bounds and tests are not a guaranteed frame rate on every device.
105
+
106
+ To export a loop of a photo, use duration `12 / speed`. Restrict the speed/duration to your encoder's limits and use a frame count that fits whole cycles. Film grain, dust, glitch, pattern animation and input videos may not loop at that boundary. Pointer paths are not included in offline export. Respect reduced motion and provide pause; do not advertise artificial depth as true scene reconstruction.
@@ -25,7 +25,7 @@ await studio.seek(1.5);
25
25
  studio.destroy();
26
26
  ```
27
27
 
28
- Keep complete settings in application state. Apply edits with `updateStudioSettings(settings, patch)` and pass that state to `studio.update`; the mounted instance does not expose a settings getter. Serialize your application state when saving a look.
28
+ Keep complete settings in application state. Apply edits with `updateStudioSettings(settings, patch)` and pass that state to `studio.update`; from 4.6 the mounted instance also exposes a detached `settings` snapshot. Serialize that snapshot or your application state when saving a look.
29
29
 
30
30
  In React, create the AbortController inside the effect. On cleanup, abort and destroy the returned instance; if setup resolves after disposal, immediately destroy that instance. Do not remount for slider changes: call `update`. The mount owns its loaded media. `mountStudioMedia` takes ownership of an already loaded `StudioMedia`. Use an independent media instance for export.
31
31
 
@@ -182,7 +182,7 @@ Stationary artwork, masks, lights, backdrops and character bloom are cached whil
182
182
 
183
183
  ## Expanded motion library (4.4)
184
184
 
185
- Use `STUDIO_HOVERS` and `STUDIO_MOTIONS` to show all eleven hovers and ten still-image motions, plus Off, grouped by behavior. New hover IDs are `etch`, `elastic`, `rake`; new motion IDs are `parallax`, `weave`, `print`, `trace`. `hover.radius` and `hover.strength` are independent of `motion.speed` and `motion.amount`. All remain serialized in look links and saved projects. A static photo needs no video input or AI service to animate.
185
+ Use `STUDIO_HOVERS` and `STUDIO_MOTIONS` to show all available hovers and still-image motions, plus Off, grouped by behavior. New hover IDs are `etch`, `elastic`, `rake`; new motion IDs are `parallax`, `weave`, `print`, `trace`. `hover.radius` and `hover.strength` are independent of `motion.speed` and `motion.amount`. All remain serialized in look links and saved projects. A static photo needs no video input or AI service to animate.
186
186
 
187
187
  Example: `player.update({ motion: { type: 'trace', speed: 1, amount: .7 }, hover: { effect: 'etch', radius: .45, strength: .65 } })`. Tone and character choices remain yours. See [effect behaviors and combinations](studio-effects.md#catalogs-and-useful-combinations-44). Do not run several looping thumbnail canvases just to display this catalog; apply the selected treatment to one shared preview.
188
188
 
@@ -190,7 +190,7 @@ Example: `player.update({ motion: { type: 'trace', speed: 1, amount: .7 }, hover
190
190
 
191
191
  Use `color.gamma` to lift midtones (above 1) or deepen them (below 1), from 0.25 to 4. `color.shadows` and `color.highlights` range from −1 to 1; positive lifts that region, negative darkens it. They form a monotone curve with fixed black, middle and white anchors. This is a bounded tonal curve, not a freely editable per-channel curve graph. It cannot recover clipped source detail.
192
192
 
193
- `color.blackPoint` (0–0.99, default 0) and `color.whitePoint` (default 1) map the input range before gamma. White is normalized to at least 1/255 above black. These controls apply equally to all 18 renderers before dither/character conversion, preserve source alpha, and round-trip in settings. Neutral settings skip the transform. The 256-entry lookup is rebuilt on configuration changes and reused for source frames. Reset with `{ blackPoint: 0, whitePoint: 1, gamma: 1, shadows: 0, highlights: 0 }`.
193
+ `color.blackPoint` (0–0.99, default 0) and `color.whitePoint` (default 1) map the input range before gamma. White is normalized to at least 1/255 above black. These controls apply equally to all Studio renderers before dither/character conversion, preserve source alpha, and round-trip in settings. Neutral settings skip the transform. The 256-entry lookup is rebuilt on configuration changes and reused for source frames. Reset with `{ blackPoint: 0, whitePoint: 1, gamma: 1, shadows: 0, highlights: 0 }`.
194
194
 
195
195
  `blue-noise` uses a deterministic 64×64 toroidal rank tile generated offline with void-and-cluster relaxation. It suppresses low-frequency clumping; it is not white noise with a different label. A palette-pair projection controls coverage, preserving flat grayscale means for a black/white palette at full strength. Arbitrary color palettes still approximate the source. The original palette uses web-safe channel quantization. The rank tile is 8 KiB in memory, loads only with `/studio`, and has no network request or runtime generator.
196
196
 
@@ -243,3 +243,11 @@ const saved = serializeStudioSettings(player.settings);
243
243
  ## Ordered source shaping (4.7)
244
244
 
245
245
  `warps` stores up to eight optional transforms applied in array order before all styles. `warpEdge` selects extended or transparent edges. Read [source shaping](source-shaping.md) for the nine mechanisms, controls, normalization, editor construction and dense-video cost. This is separate from art-style selection, pointer response and autonomous motion. The default stack is empty.
246
+
247
+ ## Print and illustration (4.9)
248
+
249
+ The catalog adds six print treatments with fine square cells and an optional `print` settings group. See [print-styles.md](print-styles.md) for the mechanisms, controls, polarity, bounded rendering and living-image example. They use the same Studio pipeline, saved settings and exports.
250
+
251
+ ## Animation starting points (4.10)
252
+
253
+ Fourteen hover responses and fourteen local still-image motions are available through the public catalogs. The editor's Effects panel and layered editor's Motion panel share all choices, independent size/strength/speed controls and six editable starting combinations from `STUDIO_ANIMATION_PRESETS`. See [lively images](studio-effects.md#lively-images-410). Existing defaults stay unchanged; animate a photograph deliberately rather than enabling motion for every upload.
@@ -77,3 +77,11 @@ Adds optional Studio `warps` and `warpEdge` with an empty default stack. Nine tr
77
77
  ### 4.8 layered projects
78
78
 
79
79
  Adds `mountStudioProject`, `mountStudioProjectMedia`, `createStudioProjectRenderer`, `exportStudioProject` and the typed project model in optional `/studio`. Up to eight independently styled media/text layers share a playback loop and cell/raster budgets. Existing single-source APIs/defaults remain. Layered project JSON uses a distinct `kind` and source keys; it is not interchangeable with single-source settings JSON and does not contain media. See [layered-projects.md](layered-projects.md) for ownership, pointer routing, export consistency and migration choices. Refresh this skill separately from npm; do not migrate simple heroes unnecessarily.
80
+
81
+ ## 4.9 print rendering
82
+
83
+ Six additional `STUDIO_STYLES` use optional `print` settings. Existing v1 settings remain valid and ASCII defaults stay unchanged. The print group merges on partial updates. Import the shared catalog and read [print-styles.md](print-styles.md); offer print-specific controls only for those styles. Existing `print` and `riso` look IDs retain their dither behavior. Refresh the npm dependency and installed skill separately.
84
+
85
+ ## 4.10 interaction expansion
86
+
87
+ Adds `lens`, `smudge`, `ripple` hover and `relight`, `shimmer`, `breeze`, `unfold` ambient motion. No IDs are removed and existing defaults remain. `STUDIO_ANIMATION_PRESETS` is exported by Studio and hover; its nested settings are shaped for `player.update`. Core accepts the new ambient IDs through `animationStyle`, with its existing simpler opacity treatment. Do not pass the new surface hover IDs to core `hoverEffect`. Update the npm dependency and refresh the agent skill separately; older packages do not implement these IDs.