asciify-engine 4.24.0 → 4.25.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 (102) hide show
  1. package/CHANGELOG.md +315 -0
  2. package/README.md +71 -718
  3. package/dist/core.cjs +1 -1
  4. package/dist/core.js +1 -1
  5. package/dist/field.cjs +1 -1
  6. package/dist/field.d.cts +4 -1
  7. package/dist/field.d.ts +4 -1
  8. package/dist/field.js +1 -1
  9. package/dist/hover.cjs +1 -1
  10. package/dist/hover.js +1 -1
  11. package/dist/index.cjs +1 -1
  12. package/dist/index.js +1 -1
  13. package/dist/kit/{chunk-3473NPIN.js → chunk-2D2SG6FW.js} +1 -1
  14. package/dist/kit/chunk-2JQ4MRIP.js +1 -0
  15. package/dist/kit/{chunk-RFLIFKZ4.js → chunk-2KFBIOVS.js} +1 -1
  16. package/dist/kit/{chunk-FR3ZJNOY.js → chunk-2TQW2PIG.js} +1 -1
  17. package/dist/kit/{chunk-C4KZYCPF.js → chunk-3F6FTBMN.js} +1 -1
  18. package/dist/kit/chunk-4SHQA3CO.js +1 -0
  19. package/dist/kit/chunk-4XT5IKM3.js +1 -0
  20. package/dist/kit/{chunk-YBRP6BFW.js → chunk-6L2GAV5C.js} +1 -1
  21. package/dist/kit/{chunk-3A5LID2G.js → chunk-6XNIZ52V.js} +1 -1
  22. package/dist/kit/{chunk-I4QVLLRQ.js → chunk-6YVZZ3DO.js} +1 -1
  23. package/dist/kit/{chunk-FUI5AVIF.js → chunk-A6EDU3UT.js} +1 -1
  24. package/dist/kit/{chunk-J2YZBT3N.js → chunk-A73S2BCE.js} +1 -1
  25. package/dist/kit/{chunk-ENTDGT2V.js → chunk-ANLBW5RI.js} +1 -1
  26. package/dist/kit/{chunk-K563CCOL.js → chunk-B6GZ645M.js} +1 -1
  27. package/dist/kit/{chunk-ZRJVOUWH.js → chunk-BBOSHBZK.js} +1 -1
  28. package/dist/kit/{chunk-5Z2EJAUV.js → chunk-BJRPY7UB.js} +1 -1
  29. package/dist/kit/{chunk-QALCXKU6.js → chunk-CA5J25SV.js} +1 -1
  30. package/dist/kit/{chunk-XANKANGR.js → chunk-CR7QS3B3.js} +1 -1
  31. package/dist/kit/{chunk-ROR6MG3K.js → chunk-D4KCZSIP.js} +1 -1
  32. package/dist/kit/{chunk-YCWMOTYH.js → chunk-EHXSXMBE.js} +1 -1
  33. package/dist/kit/{chunk-TTGMK4EA.js → chunk-EHYFSX5K.js} +1 -1
  34. package/dist/kit/{chunk-PCIAA2LL.js → chunk-EJ3W4FN6.js} +1 -1
  35. package/dist/kit/{chunk-BN7HL52Z.js → chunk-EK4GIXIO.js} +1 -1
  36. package/dist/kit/{chunk-VVW7LZT2.js → chunk-EPVZIGEZ.js} +1 -1
  37. package/dist/kit/chunk-EWPT56TR.js +1 -0
  38. package/dist/kit/{chunk-QRCXXS5Z.js → chunk-FIWIUXNV.js} +1 -1
  39. package/dist/kit/{chunk-5I4IZTL5.js → chunk-G4BQYQJ6.js} +1 -1
  40. package/dist/kit/chunk-GCIZKMJL.js +1 -0
  41. package/dist/kit/{chunk-PFKYKAIP.js → chunk-H4DBJULW.js} +1 -1
  42. package/dist/kit/{chunk-MGVPLQ3Z.js → chunk-HMW5NRUV.js} +1 -1
  43. package/dist/kit/{chunk-IPVN22ZM.js → chunk-IUX46UDR.js} +1 -1
  44. package/dist/kit/{chunk-MQJQIDO5.js → chunk-JAM46FF6.js} +1 -1
  45. package/dist/kit/{chunk-PIU2BMFU.js → chunk-JRSCTMFM.js} +1 -1
  46. package/dist/kit/{chunk-T3GWGPST.js → chunk-KBXVIAWS.js} +1 -1
  47. package/dist/kit/{chunk-7ABNWOW4.js → chunk-KJJJORN6.js} +1 -1
  48. package/dist/kit/chunk-KS3TL3S2.js +1 -0
  49. package/dist/kit/{chunk-BR6ZNJZW.js → chunk-KTYCGGRO.js} +1 -1
  50. package/dist/kit/{chunk-H2UZBVKE.js → chunk-L3P7ZDSK.js} +1 -1
  51. package/dist/kit/{chunk-VC2ZQG63.js → chunk-LUOIH2EM.js} +1 -1
  52. package/dist/kit/{chunk-WJLZM3DR.js → chunk-MIA6TUQC.js} +1 -1
  53. package/dist/kit/{chunk-SARCZMLN.js → chunk-MRDEO5HZ.js} +1 -1
  54. package/dist/kit/{chunk-BQZCLGCY.js → chunk-NPJ77LDC.js} +1 -1
  55. package/dist/kit/{chunk-5QE6UMXN.js → chunk-ODMQERGZ.js} +1 -1
  56. package/dist/kit/{chunk-E3TUOX2A.js → chunk-ONVONNUH.js} +1 -1
  57. package/dist/kit/{chunk-C3C7AYKL.js → chunk-OVCIHOOS.js} +1 -1
  58. package/dist/kit/{chunk-G57QACJG.js → chunk-P6S6HSN3.js} +1 -1
  59. package/dist/kit/{chunk-4OT66HSZ.js → chunk-PCGRRX5P.js} +1 -1
  60. package/dist/kit/{chunk-4ZQFDFEH.js → chunk-PDNKLLBI.js} +1 -1
  61. package/dist/kit/{chunk-IUKSHYED.js → chunk-PFNFW4ZI.js} +1 -1
  62. package/dist/kit/chunk-PFQBEWCF.js +1 -0
  63. package/dist/kit/{chunk-2CF4PX6U.js → chunk-PND73YEV.js} +1 -1
  64. package/dist/kit/{chunk-AIM3J2US.js → chunk-PZAQLUAS.js} +1 -1
  65. package/dist/kit/{chunk-IQTGJRDX.js → chunk-QKZYCROD.js} +1 -1
  66. package/dist/kit/{chunk-W2STAN6V.js → chunk-QTVMD62E.js} +1 -1
  67. package/dist/kit/{chunk-S62H7ZIU.js → chunk-QZHZWO7N.js} +1 -1
  68. package/dist/kit/{chunk-XDKKCIIL.js → chunk-SAQJAH2I.js} +1 -1
  69. package/dist/kit/{chunk-HTUGMGVA.js → chunk-SE6MQQLB.js} +1 -1
  70. package/dist/kit/{chunk-NURPDP3Y.js → chunk-SQGJ263V.js} +1 -1
  71. package/dist/kit/{chunk-XB4DKPGL.js → chunk-SVXRMHUJ.js} +1 -1
  72. package/dist/kit/chunk-UO4U32P7.js +1 -0
  73. package/dist/kit/{chunk-BNVRKD3V.js → chunk-V6GEQ5Y5.js} +1 -1
  74. package/dist/kit/{chunk-KWTF6Q5W.js → chunk-VFV7HZ3G.js} +1 -1
  75. package/dist/kit/{chunk-DZ5XGHTJ.js → chunk-WT3XOWAI.js} +1 -1
  76. package/dist/kit/{chunk-2NVKPXPL.js → chunk-XDNCXCR7.js} +1 -1
  77. package/dist/kit/chunk-XVB3B3FV.js +1 -0
  78. package/dist/kit/{chunk-O7SGY4YJ.js → chunk-XXPDXJMQ.js} +1 -1
  79. package/dist/kit/{chunk-5BEBNKYM.js → chunk-XYLLL2PQ.js} +1 -1
  80. package/dist/kit/{chunk-MIZ2DUHU.js → chunk-YBBYCUFP.js} +1 -1
  81. package/dist/kit/{chunk-DFOWXOZR.js → chunk-YDP6566E.js} +1 -1
  82. package/dist/kit/chunk-YL2AXWRA.js +1 -0
  83. package/dist/kit/{chunk-4QHFEMFS.js → chunk-ZYYLWSPY.js} +1 -1
  84. package/dist/kit.cjs +1 -1
  85. package/dist/kit.d.cts +3 -1
  86. package/dist/kit.d.ts +3 -1
  87. package/dist/kit.js +1 -1
  88. package/package.json +2 -1
  89. package/skills/asciify-engine/SKILL.md +2 -2
  90. package/skills/asciify-engine/references/applying-asciify.md +1 -1
  91. package/skills/asciify-engine/references/kit.md +2 -2
  92. package/skills/asciify-engine/references/performance.md +5 -2
  93. package/dist/kit/chunk-3PCKMO6I.js +0 -1
  94. package/dist/kit/chunk-4HWMQCAM.js +0 -1
  95. package/dist/kit/chunk-73M2OESE.js +0 -1
  96. package/dist/kit/chunk-BTD6EFAW.js +0 -1
  97. package/dist/kit/chunk-OWEZV7TQ.js +0 -1
  98. package/dist/kit/chunk-S7RZP2MT.js +0 -1
  99. package/dist/kit/chunk-SNCXU7KF.js +0 -1
  100. package/dist/kit/chunk-UML6XQAR.js +0 -1
  101. package/dist/kit/chunk-UO7RB7RC.js +0 -1
  102. package/dist/kit/chunk-XM56OTYT.js +0 -1
package/CHANGELOG.md ADDED
@@ -0,0 +1,315 @@
1
+ # Changelog
2
+
3
+ Notable changes to `asciify-engine`, newest first. Releases are published to [npm](https://www.npmjs.com/package/asciify-engine) from version tags.
4
+
5
+ ## 4.25: one shared context, bounded memory
6
+
7
+ - Every glyph field and kit surface on a page now draws through one shared WebGL2 context and one frame loop. Programs compile once, atlases are shared per glyphs/font/size, and one set of page listeners and observers serves every field. Output is pixel-identical.
8
+ - Static fields draw once. Ambient motion slows when frames are expensive, and render scale steps down (1 → 0.5) before frame rate drops. Mounts wait while the page scrolls.
9
+ - GPU memory is budgeted at 256 MB per page: off-screen kit fields fall back to posters, farthest first, and unused atlases are evicted. The shared context is released 3 s after the last field.
10
+ - Fixed: more than 12 `lazy: false` fields fought over the context budget forever, growing memory without bound. Fixed: `destroy()` left a context on user canvases. The Studio surface shader no longer blocks the page (241 ms → 5 ms), and GIF frame extraction yields between frames.
11
+
12
+ ## 4.24: Lighter on the host page
13
+
14
+ - The kit is split per component: a host importing one component ships about 33 KB gzip instead of 99 KB. Existing imports are unchanged.
15
+ - Animating components draw once per frame (they drew twice), ambient motion is capped at 60 fps (30 on low-end devices or Save-Data) while interactions keep the full rate, and at most one field mounts per frame, so mounts never stack into a long task.
16
+ - Studio hover redraws at most 60 times a second and never takes more than half the main thread. Off-screen core video loops stop, zero-size fields stop, the backing store is capped at one 4K screen, and `destroy()` removes every listener.
17
+ - See `references/performance.md` in the skill for what the engine promises host apps.
18
+
19
+ ## 4.23: Dialogs always render, sharper motion cues, cleaner hovers
20
+
21
+ - Kit fields inside an open modal dialog always get a WebGL context: fields covered by the dialog give theirs up and come back when it closes. A released field hands its canvas back at once (Safari counts dead contexts toward its limit), and a field whose context is lost recovers onto a fresh canvas.
22
+ - Depth is fused from focus, haze, a horizon prior, texture and saliency with an edge-aware filter; Drift finds water (including non-blue seas by reflection), sky, cloud and falling water, and holds everything else still. The classic core renderer shares the same motion code. Analysis follows grid changes and reads the ungraded photo.
23
+ - Water settles cleanly; Ripple and Emboss draw their own rings on dark or transparent ground; glyph fields take `scope`; video subjects update as the video plays; the hover catalog (`HOVER_CONTROLS`, `DEFAULT_HOVER`, `resolveHover`) is exported once. On the GPU path, Trail keeps the artwork's ground and Water moves whole cells.
24
+
25
+ ## 4.22: Photo-aware motion and finish
26
+
27
+ - A new set of still-image motions read the photo's own light, form, highlights, detail and estimated depth: `relight`, `sheen` (specular sweep), `glow` (highlight bloom), `shimmer` (glints), `parallax`, `push`, `focus`, `mist`, `current` (drift) and `develop`.
28
+ - Retired motions keep working through `DEPRECATED_STUDIO_MOTIONS`: caustics → sheen, grain → shimmer, trace → relight, tidal/weave/breeze → current, reform/print/unfold → develop.
29
+ - Optical finish: bloom is a wide soft glow around highlights, and grain is fine film grain weighted to the midtones.
30
+ - Animation presets are re-paired with the new motions, plus a new Depth study.
31
+
32
+ ## 4.21: Hovers that know the subject
33
+
34
+ - Six new hovers: `loupe`, `reveal`, `repel`, `tilt`, `haze` and `bleed`; `scatter`, `elastic` and `ripple` are refined, and `rake` is deprecated (it plays `silk`).
35
+ - Every hover takes `decay` (how long it lingers) and `scope: 'all' | 'subject' | 'outside'`: the subject comes from transparency, a drawn mask or an even plain ground, with a feathered edge; a busy full-bleed photo acts as `all`.
36
+ - Hovers ease in, settle when the pointer stops, follow touch drags and stay off under reduced motion.
37
+ - `mountHover` now runs on the GPU in Chrome (a reserved word in its shader forced the 2D fallback).
38
+
39
+ ## 4.20: Sharper presets, 61 looks, twelve backgrounds
40
+
41
+ - Studio presets `ascii` (Signature ASCII) and `night` (Night signal) are retuned: finer 4px cells, brighter inks, lifted midtones and a faint glow.
42
+ - The woodblock print style no longer leaves pale seams between cells.
43
+ - `aurora` joins the deprecated backgrounds (closest current preset: `mesh`), leaving twelve curated presets; `halo` fits tall stages, `caustics` is calmer in small cards and `wordField` reads on small dark stages.
44
+ - The skill's `looks.md` covers 61 looks, adding Projects looks for album covers, editorial portraits, product heroes, posters, postcards, botanical plates, lookbooks, game box art, stickers and phone wallpapers, each with its export size and frame.
45
+
46
+ ## 4.19: A curated set of backgrounds
47
+
48
+ - New presets `halo`, `ripple`, `mesh`, `interference`, `constellation` and `cascade`; `caustics`, `contour` and `aurora` are rebuilt on the GPU. All follow `setGlobalLook`, keep a quiet zone behind content and hold a still frame under reduced motion.
49
+ - `cursor: false` turns pointer interaction off for every preset. `mark: 'glyph' | 'dot'` draws any preset in characters or dots; `swell` keeps dots by default.
50
+ - Dated presets (`dna`, `circuit`, `fire`, `grid`, `morph`, `noise`, `pulse`, `rain`, `silk`, `stars`, `terrain`, `veil`, `void`, `wave`, `weave`, `dune`, `etch`, `facet`, `moire`, `halftone`) stay exported but are deprecated; the kit reference names the closest current preset for each.
51
+ - Switching presets no longer leaves the previous preset's poster covering the new one.
52
+ - `pageDissolve` draws its settled blocks in one masked pass and snapshots at 1x on touch devices, so the wave stays light on phones.
53
+ - The skill's `looks.md` now covers 47 artwork looks, every render style, plus composed (blur, transparent, gradient) and finished (vignette, grain, bloom, scanlines) looks.
54
+
55
+ ## 4.18: 24 render styles in every live field, artwork looks, smoother components
56
+
57
+ - Glyph fields draw the Studio's tile and print styles: `mark` accepts `pixel`, `mosaic`, `lego`, `voxel`, `disco`, `dither`, `hex`, `led`, `cmyk`, `stipple`, `engraving`, `crosshatch`, `woodblock`, `risograph` and `pointillism` (see `FIELD_MARKS`), one shader branch each.
58
+ - `setGlobalLook({ style })` re-skins every opted-in kit field in any of the 24 Studio styles (`KIT_STYLES`); `charset` still works alongside.
59
+ - New background preset `swell`: a halftone dot field in slow crossing waves, quiet behind the content, swelling under the pointer.
60
+ - Reworked kit components: `blockChart` (crisp glyph columns, scrubbing, morphing ranges), `commandPalette` (gliding selection, resolving rows, AI shimmer), `toastStack` (no outlines, layered stack, swipe to dismiss), `pill` and `tabs` (glyph status dots, gliding indicator, rolling figures), `pageDissolve` (one continuous wave), `imageGenerate` (one develop curve), `accordion` (one spring per panel, hover intent), `pullRefresh` (an iOS-sized ring), `dropzone` (a quiet ring that comes alive on drag-over).
61
+ - The skill gains `references/looks.md`: 22 artwork looks with prompts and settings for wallpapers, posters and hero art.
62
+ - Studio defaults are paper and graphite instead of yellow; the default characters are Classic ASCII.
63
+
64
+ ## 4.17: A thinking label that rolls
65
+
66
+ - `thinking` drops the dot bands and the dotted rule. A wave runs through the status label instead, each letter rolling up through glyphs and back in the label's own font; when the answer starts, the label rolls into `Thought for 2s`. New options `roll`, `wave` and `glyphs`; `lines` and `rule` are ignored.
67
+
68
+ ## 4.16: Smooth shading in every charset, rolling streamed text
69
+
70
+ - Glyph fields gain `blend` (default `'auto'`): with nine or fewer characters, a photo or video mixes neighbouring characters in a fixed 4x4 pattern for the shades between them, so binary, dots and block sets shade like a full ramp. Drawn interface shapes stay crisp. It costs one comparison per cell and never shimmers.
71
+ - `streamText(el, { transition: 'roll' })` rolls each character up through glyphs into the crisp letter, like the odometer, with the caret on the front of the roll.
72
+
73
+ ## 4.15: Every charset at the same weight, inks from your tokens
74
+
75
+ - `setGlobalLook({ charset })` measures the set's ink against classic ASCII and balances it: block and solid sets draw smaller glyphs and keep their detail, sets without light glyphs ease off, and faint sets draw larger, bolder glyphs. Tones are untouched.
76
+ - Kit inks default to `--ascii-ink-strong`, and with that unset, to the element's own text colour, so components follow the page's tokens instead of a fixed grey.
77
+ - `skeleton` reads its blocks' shapes from CSS (an image's radius; one bar per line of text, as wide as the words) and its shimmer is a continuous wave until `resolve()`.
78
+ - A hidden (`display: none`) field gives its WebGL context to fields on screen.
79
+
80
+ ## 4.14: Backgrounds in the kit, site-quality components
81
+
82
+ - **`background(el, { preset })`** brings all 26 asciify.org backgrounds into the kit: drift, halftone, wordField and fluid on the GPU field, and 22 canvas presets (caustics, contour, facet, etch, moire, weave, veil, dune, wave, aurora, noise, silk, rain, stars, pulse, grid, voidWell, morph, fire, dna, terrain, circuit). Presets are separate imports, so a page pays only for the ones it uses, and each matches the /backgrounds page's rendering.
83
+ - **The site now runs on the kit.** Every component demo on asciify.org is the kit itself, so what you see is what you install. Where the kit was weaker than the hand-built demos, the kit was raised to match.
84
+ - **Performance and integration:** fields mount lazily near the viewport and release far from it, a page-wide budget keeps at most 12 WebGL contexts live, `poster` shows a still for first paint and as the no-GPU fallback, `setGlobalLook({ charset })` re-skins every glyph field at once with a short sweep, and `update({ ink, look })` merges per instance.
85
+ - **New guide:** [applying-asciify.md](skills/asciify-engine/references/applying-asciify.md) teaches agents the house design: which component or background to use, text over fields, ink, radius, motion, performance and a finishing checklist.
86
+
87
+ ## 4.13: The kit, interface components in one call
88
+
89
+ `asciify-engine/kit` turns Asciify's interface components into short, customisable calls on the GPU field. Each one follows its element's size and border radius, takes ink from your CSS variables in light and dark, honours reduced motion, pauses off screen, leaves your HTML working without WebGL2, and cleans up with `destroy()`.
90
+
91
+ ```ts
92
+ import { beam, buttonLoading, statusOrb } from 'asciify-engine/kit';
93
+
94
+ const b = beam(card, { palette: 'colorful', mode: 'progress' });
95
+ b.progress(0.6); b.success();
96
+
97
+ const save = buttonLoading(saveButton, { text: 'Save' });
98
+ save.start('Saving'); await request; save.succeed('Saved');
99
+ ```
100
+
101
+ Thirty components ship in the kit: beam, decode, odometer, buttonLoading, statusOrb, skeleton, pill, tabs, imageGenerate, voiceOrb, commandPalette, slideToConfirm, likeBurst, blockChart, pageDissolve, swipeDeck, codeInput, toastStack, thinking, streamText, compare, accordion, dropzone, disintegrate, pullRefresh, fieldBackground, wordmark, asciiVideo, artPanel and pricingGlow. Unused components tree-shake away; each adds about 2–4 kB gzipped on top of a 3.5 kB shared core and the `/field` entry. See [kit.md](skills/asciify-engine/references/kit.md), and [components.md](skills/asciify-engine/references/components.md) for the prompt and snippet of every component.
102
+
103
+ ## 4.12: Halftone fields for interfaces
104
+
105
+ `mark: 'dot'` turns the GPU field into a halftone: one circle per cell, its area following the tone, crisp at any pixel ratio. The new `drift` scene draws a few broad, slow lobes; `clear` keeps the field quiet around an element so copy stays readable; `pulse()` sends a ring through the dots when your interface wants to answer an event.
106
+
107
+ ```ts
108
+ const field = mountGlyphField(canvas, {
109
+ mark: 'dot', scene: 'drift', cellSize: 14, dotScale: 0.64,
110
+ ink: '#9a988f', background: 'transparent',
111
+ clear: { element: document.querySelector('#hero .copy') },
112
+ });
113
+ saveButton.addEventListener('click', () => field.pulse({ element: saveButton }));
114
+ ```
115
+
116
+ Also in 4.12:
117
+
118
+ - **Even quality across styles.** Character styles stretch each image's tones to its own range and pick glyphs by measured ink, so dark or flat images keep their subject in every character set and look. Set `color.levels: 'none'` for the previous linear mapping. Adaptive resolution only steps down while frames are genuinely over budget, and returns to full detail when motion settles.
119
+ - **Faster fields.** Image sources decode off the main thread and are scaled to what the cells can show; scene maths runs once per cell; shaders compile without blocking. `ready` resolves for fields mounted off screen, and a shader link failure is reported through `onError`.
120
+ - **4.12.1:** fields size themselves from layout, so a parent's transform (a dialog scaling open) no longer stretches them.
121
+ - **31 ready-made components in the agent skill** ([components.md](skills/asciify-engine/references/components.md)): controls, feedback, AI states, transitions, data, media, text and pages, each with the prompt and the reference code. See them running at [asciify.org/components](https://asciify.org/components).
122
+
123
+ ## 4.11: GPU glyph fields
124
+
125
+ `asciify-engine/field` renders an image, a video or generated motion as characters entirely on the GPU, with three cursor responses: `trail` (the Asciify Trail, the same ink field as the studio's, now on the GPU), `fluid` (an incompressible ink-in-water wake that curls into eddies) and `lantern` (a soft light with no distortion). Use it for full-bleed heroes and brand fields that must stay smooth while people move over them. Characters are drawn texel for texel from a glyph atlas, so any font and any charset work, including your own name.
126
+
127
+ ```ts
128
+ import { mountGlyphField } from 'asciify-engine/field';
129
+
130
+ const field = mountGlyphField(canvas, {
131
+ source: '/media/hero.mp4',
132
+ charset: ' .,:-+ACME',
133
+ color: 'ink', ink: '#f3ba32', shade: 1,
134
+ fluid: { radius: 0.08, refraction: 0.03, glow: 0.6 },
135
+ });
136
+ // field.update({ charset: ' .:ASCIIFY' }); field.destroy();
137
+ ```
138
+
139
+ It needs WebGL2 on a GPU: `isGlyphFieldSupported()` is false without it or on software WebGL, and slow devices step down to 1× pixels and then still ambient motion. Keep a poster or the `/studio` renderer as the fallback. A still field stops drawing once its wake settles. Measured in Playwright Chromium on an Apple M4 Pro at 1440 × 900 and device pixel ratio 2, a full-viewport field held 120 fps (9 ms 95th-percentile frame) under continuous pointer movement; measure your own targets. See the [field guide](skills/asciify-engine/references/glyph-field.md) and [brand field example](examples/glyph-field.ts). It is a separate entry: the root, `/core`, `/hover` and `/studio` never load it.
140
+
141
+ ## 4.10: More life for still images
142
+
143
+ Three additional pointer responses—Lens wake, Smudge and Ripple rings—and four autonomous motions—Relight, Shimmer, Breeze and Unfold—bring the catalogs to 14 each, plus Off. Source images, art styles and colors remain yours. Six editable combinations in `STUDIO_ANIMATION_PRESETS` help choose a starting point without replacing your look.
144
+
145
+ ```ts
146
+ import { STUDIO_ANIMATION_PRESETS } from 'asciify-engine/studio';
147
+ const preset = STUDIO_ANIMATION_PRESETS.find(p => p.id === 'quiet-light')!;
148
+ player.update({ motion: preset.motion, hover: preset.hover });
149
+ ```
150
+
151
+ Use one Studio player for live rendering, settings persistence and independent animation export. See [the complete interaction guide](skills/asciify-engine/references/studio-effects.md#lively-images-410) and [living-image helper](examples/living-image.ts). CPU simulation is bounded and wakes settle; device frame rates and visual fidelity still require browser measurement. Existing defaults and saved IDs are unchanged.
152
+
153
+ ## 4.9: Print and illustration
154
+
155
+ Stipple, Engraving, Crosshatch, Woodblock, Risograph and Pointillism add distinct print geometry to `/studio`. All share hover, living-image motion, masks, source shaping, saved settings and exports. Tune coverage, mark weight, angle, repeatable texture, light/dark ink polarity and two-ink registration with `print`. Use `STUDIO_PRINT_STYLES` for labels and [the print guide](skills/asciify-engine/references/print-styles.md) for a live still-image example, bounds and performance limits. ASCII remains the default.
156
+
157
+ ## 4.8: Layered projects
158
+
159
+ Compose up to eight image, video, GIF or text layers with independent styles, motion, hover, placement, opacity and blend modes. `mountStudioProject` owns one playback loop and a shared cell/raster budget; hidden and unchanged layers skip work. Root/core/hover entry points remain unchanged.
160
+
161
+ ```ts
162
+ import { mountStudioProject } from 'asciify-engine/studio';
163
+ const player = await mountStudioProject(canvas, { layers: [
164
+ { id: 'photo', source: 'image', settings: { motion: { type: 'parallax' } } },
165
+ { id: 'title', source: 'text', placement: { width: .8, height: .25 },
166
+ settings: { ink: '#b3ed82', hover: { effect: 'elastic' } } },
167
+ ] }, { image: '/your-photo.webp', text: { text: 'HELLO', font: 'Small' } });
168
+ player.updateLayer('photo', { settings: { hover: { effect: 'water' } } });
169
+ // player.destroy() on unmount
170
+ ```
171
+
172
+ `exportStudioProject` owns independent export media, so it does not disturb the live preview. Save layouts with `serializeStudioProject`, retain/rebind source assets separately, and restore with `parseStudioProject`. See the [layered-project guide](skills/asciify-engine/references/layered-projects.md) and [typed live/export example](examples/layered-composition.ts) for geometry, picking, ownership, cancellation and performance limits. This is an optional local composition API, not a claim of complete competitor-style or FPS parity.
173
+
174
+ ## 4.7: Ordered source shaping
175
+
176
+ Combine up to eight source transformations before ASCII, dither or any Studio style: Twirl, Pinch, Spherize, Ripple, Zigzag, Shear, Smudge, Polar and Fragment. Edit strength, position and radius, plus direction/frequency where applicable. Reorder or disable stages without losing their settings; choose extended or transparent edges. Generate controls from `STUDIO_WARPS` and `MAX_STUDIO_WARPS`.
177
+
178
+ ```ts
179
+ player.update({
180
+ warps: [{type:'sphere',amount:.3,radius:.7}, {type:'shear',amount:.15,angle:25}],
181
+ warpEdge:'clamp',
182
+ motion:{type:'parallax',amount:.5},
183
+ });
184
+ ```
185
+
186
+ The stack is static shaping; motion and pointer hover remain independent. Coordinate maps are cached across video frames, and stills reuse shaped pixels during interaction. Empty stacks are free of additional pixel work. Defaults and root/core/hover behavior remain unchanged. Dither motion also gains alpha-correct interpolation at transparent edges. See [parameters, order, persistence/export and measured CPU tradeoffs](skills/asciify-engine/references/source-shaping.md).
187
+
188
+ ## 4.6: Channel curves and source noise reduction
189
+
190
+ Studio adds editable RGB, red, green and blue curves, with up to 16 control points each, plus optional edge-preserving source noise reduction. They apply before every render style and travel with saved settings and exports. Defaults preserve existing output. Curves use small cached lookups; still images reuse filtered pixels while hover/motion run. Dense video filtering is an explicit CPU tradeoff.
191
+
192
+ ```ts
193
+ player.update({color:{
194
+ denoise:.25,
195
+ curves:{rgb:[[0,0],[.25,.2],[.75,.8],[1,1]]},
196
+ }});
197
+ const settings = player.settings; // detached snapshot for save/export
198
+ ```
199
+
200
+ See [settings, normalization, processing order and performance guidance](skills/asciify-engine/references/studio-workspace.md#channel-curves-and-source-noise-46). Curves are local source controls, not another art-style alias or AI restoration.
201
+
202
+ ## 4.5: Tonal detail and blue-noise dithering
203
+
204
+ Studio adds `dither.algorithm: 'blue-noise'`: a stable precomputed dispersed pattern with no runtime generation or asset download. `noise` remains white noise. Choose the algorithm from `DITHER_ALGORITHMS`; drift and shimmer remain independently controlled.
205
+
206
+ Recover usable shadow/highlight separation before conversion with `color.gamma`, `shadows`, `highlights`, `blackPoint` and `whitePoint`. All Studio styles share these controls and retain neutral defaults. They are a bounded monotone tonal curve, not arbitrary per-channel curve editing. See [exact ranges, sampling budgets and a live-project example](skills/asciify-engine/references/studio-workspace.md#tonal-detail-and-blue-noise-45).
207
+
208
+ ## 4.4: More ways to bring photos to life
209
+
210
+ Eleven pointer interactions and ten autonomous motions, plus Off. Emboss presses paired light and shadow into a fixed character grid; Elastic stores directional momentum and springs back; Rake combs the source into alternating ribbons. Parallax, Woven Flow, Print Shift and Contour Light join the still-image motions. Contour Light follows the actual source tones.
211
+
212
+ ```js
213
+ import { STUDIO_HOVERS, STUDIO_MOTIONS } from 'asciify-engine/studio';
214
+ // value / label / group / description: use these to build a complete picker.
215
+ player.update({
216
+ motion: { type: 'parallax', speed: 1, amount: .7 },
217
+ hover: { effect: 'elastic', radius: .45, strength: .65 },
218
+ });
219
+ ```
220
+
221
+ All motion choices repeat every `12 / speed` seconds. Still exports preserve the selected preview phase; animated exports include motion without pointer events. Grain, dust, glitch, animated dither and source video have separate timing. No external AI service is used. See [effect integration](skills/asciify-engine/references/studio-effects.md).
222
+
223
+ ## 4.3.1: Studio correctness and performance
224
+
225
+ Stationary compositions are reused during animated finishing. Hidden dither settings and zero-strength motion no longer keep still previews awake. Ordered dithering uses cached thresholds with byte-identical output; Scatter caches its spatial noise. CMYK now responds to tonal hovers and still motion. For a selected PNG/JPEG frame after changing motion speed, pass `time: player.time` and `motionTime: player.motionTime` to `exportStudio`. See the packaged project-integration skill reference for a live component and independent image/video export.
226
+
227
+ ## 4.3: More motion for still images
228
+
229
+ Studio includes six still-image motions plus Off: Caustics, Slow Current, Reveal & Reform, Sheen, Tidal Rings, and Living Grain. Sheen and Living Grain preserve the grid. Motion speed and strength are adjustable. Hover adds Magnetic Pull and Scatter alongside Trail, Water, Contour, Dissolve, Silk, and Vortex. Use `hover.effect` in Studio or `effect` in the optional `/hover` module; configure radius and strength separately. Existing defaults remain unchanged.
230
+
231
+ ## 4.2: Studio detail controls
232
+
233
+ The optional `asciify-engine/studio` entry includes 24 render styles, including hex mosaic, LED matrix and CMYK print. Dither supports pixel scale, custom palettes, RGB/luminance mapping, pattern speed and direction. Use `studioGrid` to report effective density and opt into a larger `maxCells` budget for one-pixel output; defaults stay performance-bounded. Mounts expose `setAdaptive` for an explicit detail/performance choice. Still-image motion has `amount`, and finishing adds `rgbSplit` and `sharpen` (WebGL required). See the [complete controls and export guidance](skills/asciify-engine/references/studio-workspace.md#fine-detail-and-controls-42). No AI service or server upload is introduced.
234
+
235
+ ## 4.1.0: Current catalogs only
236
+
237
+ This release removes `CHARSETS`, `ART_STYLE_PRESETS`, `CHARSET_SEQUENCES`, `LIVING_STYLE_PRESETS`, and their key types. **Although numbered 4.1.0 at the maintainer's request, these removals are breaking changes.** Update imports before upgrading. Removed core `artStyle` shortcuts throw with migration guidance.
238
+
239
+ Use `STUDIO_STYLES` from `asciify-engine/studio` for the 15 current render styles: ASCII, Braille, Dots, Lines, Blocks, Dither, Cross, Diagonal, Diamond, Mixed, Pixel, Mosaic, Lego, Voxel and Disco. Set `settings.style` with `mountStudio` / `createStudioRenderer`; these styles are actual rendering methods, not character ramps. Core media APIs remain ASCII-first.
240
+
241
+ Use `CHARACTER_SETS.standard.chars` (or another curated entry) from root or `/core` for an ASCII ramp; custom `options.charset` and `charsetFrames` arrays remain supported. Use explicit `options.colorMode`, `renderMode`, and hover/motion settings instead of the removed combined presets. No legacy catalog has been moved to a hidden compatibility bundle.
242
+
243
+ ## 4.0: Optional background templates
244
+
245
+ Procedural backgrounds no longer ship in the npm package or root exports. Download only the template you want from [the background gallery](https://asciify.org/backgrounds); its copied code and lifecycle belong to your application. Existing 3.x applications can remain pinned while migrating. `/backgrounds`, `asciiBackground`, `BACKGROUND_TYPES`, and procedural `render*Background` exports are removed; text/media background APIs remain. The default import and `/core` now expose the same media-first API. `CHARACTER_SETS` is the lightweight curated catalog shared by the hero and editor.
246
+
247
+ ## 3.0: Still-image motion
248
+
249
+ Use `motion: { type: 'current', speed: 1 }` with `/studio`, `motion: 'current'` with `/hover`, or `animationStyle: 'current'` with core. Choose one motion owner. The curated set is Off (`none`), Caustics (`caustics`, fixed-grid light), Slow Current (`current`, local flow), and Reveal & Reform (`reform`, staggered dissolve). All loop every 12 / speed seconds and preserve your chosen colors. Breathe, Fire, Rainbow and other old ambient motion IDs are retired. Old Studio presets restore with motion Off; update application-owned core options explicitly. Hover effects and optical finishes are independent. See [the 3.0 migration guide](skills/asciify-engine/references/upgrading.md).
250
+
251
+ ## 2.0.1: Size and export fixes
252
+
253
+ `studioGrid` exposes the effective grid and minimum cell size for a bounded preview. Dither uses `dither.scale`; other styles use `cellSize`. Pass `time` to `exportStudio` for a PNG/JPEG of the current frame. Animation exports continue to start at zero. See the Studio guide for the shared preview/export density contract.
254
+
255
+ ## 2.x: Studio composition tools
256
+
257
+ The `asciify-engine/studio` entry adds a reusable composition pipeline: alternate render styles, palette dithering, crop and masks, source/blurred/gradient backdrops, combined optical effects, saved looks, text fonts, and PNG/JPG/GIF/MP4/WebM export. Existing ASCII defaults and `/core` and `/hover` imports stay unchanged. Fonts and video encoders load on demand.
258
+
259
+ ```ts
260
+ import { mountStudio } from 'asciify-engine/studio';
261
+
262
+ const studio = await mountStudio(canvas, '/your-video.mp4', {
263
+ settings: {
264
+ style: 'ascii',
265
+ backdrop: { mode: 'blurred', opacity: 0.4 },
266
+ },
267
+ });
268
+ studio.update({ hover: { effect: 'water', radius: 0.35 } });
269
+ // On unmount:
270
+ studio.destroy();
271
+ ```
272
+
273
+ See the [Studio API guide](skills/asciify-engine/references/studio-workspace.md) for complete settings, import/export, media ownership, browser requirements, and performance budgets.
274
+
275
+ ## 1.3.0: Hero finish
276
+
277
+ Version 1.3.0 adds text-shaped charcoal cutouts (`textMask`), peripheral scanline/fringe control (`edgeEffect`), fixed accent ink, and velocity-driven Trail source flow. These additions ship in **npm 1.3.0**. Upgrade older applications before using them. See the [complete API, layering example, lifecycle, and fallback limits](skills/asciify-engine/references/hero-finish.md).
278
+
279
+ ## 1.2.0: Website hovers
280
+
281
+ Since **1.2.0**, import the enhanced interactions through `asciify-engine/hover`. No extra download is needed. This optional entry leaves root and `/core` browser bundles unchanged.
282
+
283
+ ```js
284
+ import { asciify } from 'asciify-engine/core';
285
+ import { mountHover } from 'asciify-engine/hover';
286
+
287
+ // <div id="art" style="position:relative;width:fit-content">
288
+ // <canvas id="ascii" style="display:block"></canvas>
289
+ // </div>
290
+ const host = document.querySelector('#art');
291
+ const canvas = document.querySelector('#ascii');
292
+ const charset = ' .:-=+*#%@';
293
+ const stop = await asciify('/image.jpg', canvas, {
294
+ fontSize: 7,
295
+ options: { charset, charAspect: 0.58, hoverStrength: 0, animationStyle: 'none' },
296
+ });
297
+ const hover = mountHover(host, canvas, {
298
+ effect: 'trail', strength: 0.55, radius: 0.2,
299
+ fontSize: 7, charAspect: 0.58, charset,
300
+ });
301
+ // Switch: hover.update({ effect: 'water' });
302
+ // Redraw a still: hover.invalidate();
303
+ // On unmount: hover.destroy(); stop();
304
+ ```
305
+
306
+ Effects: **Trail, Water, Contour, Dissolve, Silk, Vortex, Magnetic Pull, Scatter, Emboss, Elastic, Rake**, and `none`. Inspect `STUDIO_HOVERS` for typed IDs and behavior groups (4.4+). Pass `effect` to `mountHover`, rather than passing these names to the legacy engine `hoverEffect` option. Keep engine hover and animation disabled to avoid stacking two renderers. Match `fontSize`, `charAspect`, `charSpacing`, `charset`, `customText`, and dot settings to the backing canvas.
307
+
308
+ For video/GIF, set `animated: true, fps: 24` and coordinate `paused` with playback. For a still, optional `motion: 'caustics' | 'current' | 'reform'` (or the other IDs in `STUDIO_MOTIONS`) adds living-image motion; `fineDither: true` enables stationary grain. `mountStudioHover` remains an alias for the existing standalone integration. The module observes reduced motion, sleeps when idle/offscreen, and uses Canvas 2D when WebGL is unavailable (simpler spatial refraction). Call `destroy()` on unmount; use `hover.canvas` for overlay layering or snapshots.
309
+
310
+ See the [complete integration and lifecycle guide](skills/asciify-engine/references/studio-effects.md). A [standalone ES module](https://asciify.org/background-sources/studio-hover.js) remains available for projects without a bundler.
311
+
312
+ ## Earlier notes
313
+
314
+ `waveField` now animates the supplied media rather than replacing it with a generated scene. For the previous procedural scene, download the Wave template from https://asciify.org/backgrounds.
315
+