asciify-engine 4.5.0 → 4.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -566,3 +566,31 @@ All motion choices repeat every `12 / speed` seconds. Still exports preserve the
566
566
  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.
567
567
 
568
568
  Recover usable shadow/highlight separation before conversion with `color.gamma`, `shadows`, `highlights`, `blackPoint` and `whitePoint`. All 18 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).
569
+
570
+ ### Channel curves and source noise reduction (4.6)
571
+
572
+ 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.
573
+
574
+ ```ts
575
+ player.update({color:{
576
+ denoise:.25,
577
+ curves:{rgb:[[0,0],[.25,.2],[.75,.8],[1,1]]},
578
+ }});
579
+ const settings = player.settings; // detached snapshot for save/export
580
+ ```
581
+
582
+ 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.
583
+
584
+ ### Ordered source shaping (4.7)
585
+
586
+ 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`.
587
+
588
+ ```ts
589
+ player.update({
590
+ warps: [{type:'sphere',amount:.3,radius:.7}, {type:'shear',amount:.15,angle:25}],
591
+ warpEdge:'clamp',
592
+ motion:{type:'parallax',amount:.5},
593
+ });
594
+ ```
595
+
596
+ 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).
package/dist/core.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { a as AsciiOptions, A as AsciiFrame, b as ArtStyle, H as HoverEffect } from './types-D38BMBRB.cjs';
2
2
  export { c as AnimationStyle, d as AsciiCell, e as AsciiResult, C as ColorMode, D as DEFAULT_OPTIONS, f as HOVER_PRESETS, g as HoverPreset, h as HoverShape, P as PALETTE_THEMES, i as PaletteTheme, R as RenderMode, S as SourceType } from './types-D38BMBRB.cjs';
3
- export { C as CHARACTER_SETS, f as STUDIO_STYLES, i as StudioStyle } from './model-BLvrvOKA.cjs';
3
+ export { C as CHARACTER_SETS, g as STUDIO_STYLES, n as StudioStyle } from './model-fP9NdG-w.cjs';
4
4
  import './hover-catalog-BeIkNwhH.cjs';
5
5
 
6
6
  /**
package/dist/core.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { a as AsciiOptions, A as AsciiFrame, b as ArtStyle, H as HoverEffect } from './types-C05AfrjT.js';
2
2
  export { c as AnimationStyle, d as AsciiCell, e as AsciiResult, C as ColorMode, D as DEFAULT_OPTIONS, f as HOVER_PRESETS, g as HoverPreset, h as HoverShape, P as PALETTE_THEMES, i as PaletteTheme, R as RenderMode, S as SourceType } from './types-C05AfrjT.js';
3
- export { C as CHARACTER_SETS, f as STUDIO_STYLES, i as StudioStyle } from './model-DVm46H2S.js';
3
+ export { C as CHARACTER_SETS, g as STUDIO_STYLES, n as StudioStyle } from './model-CMKdRB30.js';
4
4
  import './hover-catalog-BeIkNwhH.js';
5
5
 
6
6
  /**
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { c as AnimationStyle, b as ArtStyle, d as AsciiCell, A as AsciiFrame, a as AsciiOptions, e as AsciiResult, C as ColorMode, D as DEFAULT_OPTIONS, f as HOVER_PRESETS, H as HoverEffect, g as HoverPreset, h as HoverShape, P as PALETTE_THEMES, i as PaletteTheme, R as RenderMode, S as SourceType } from './types-D38BMBRB.cjs';
2
2
  export { AsciiTextFrame, AsciifyLiveVideoOptions, AsciifySimpleOptions, AsciifyVideoOptions, BigTextOptions, CanvasBleed, CanvasObjectFit, CanvasRenderSizeInput, SnapshotOptions, TextBackgroundOptions, VideoScrollScrubOptions, WebcamOptions, asciiText, asciiTextAnsi, asciify, asciifyGif, asciifyLiveVideo, asciifyText, asciifyVideo, asciifyWebcam, buildTextFrame, captureSnapshot, clearAsciifyCaches, computeCanvasRenderSize, createVideoScrollScrub, gifToAsciiFrames, gifToAsciiTextFrames, imageToAsciiFrame, imageToAsciiTextFrame, renderFrameToCanvas, renderTextBackground, renderTextFrameToCanvas, renderTextToCanvas, snapshotAndDownload, videoToAsciiFrames, videoToAsciiTextFrames } from './core.cjs';
3
- export { C as CHARACTER_SETS, f as STUDIO_STYLES, i as StudioStyle } from './model-BLvrvOKA.cjs';
3
+ export { C as CHARACTER_SETS, g as STUDIO_STYLES, n as StudioStyle } from './model-fP9NdG-w.cjs';
4
4
  import './hover-catalog-BeIkNwhH.cjs';
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { c as AnimationStyle, b as ArtStyle, d as AsciiCell, A as AsciiFrame, a as AsciiOptions, e as AsciiResult, C as ColorMode, D as DEFAULT_OPTIONS, f as HOVER_PRESETS, H as HoverEffect, g as HoverPreset, h as HoverShape, P as PALETTE_THEMES, i as PaletteTheme, R as RenderMode, S as SourceType } from './types-C05AfrjT.js';
2
2
  export { AsciiTextFrame, AsciifyLiveVideoOptions, AsciifySimpleOptions, AsciifyVideoOptions, BigTextOptions, CanvasBleed, CanvasObjectFit, CanvasRenderSizeInput, SnapshotOptions, TextBackgroundOptions, VideoScrollScrubOptions, WebcamOptions, asciiText, asciiTextAnsi, asciify, asciifyGif, asciifyLiveVideo, asciifyText, asciifyVideo, asciifyWebcam, buildTextFrame, captureSnapshot, clearAsciifyCaches, computeCanvasRenderSize, createVideoScrollScrub, gifToAsciiFrames, gifToAsciiTextFrames, imageToAsciiFrame, imageToAsciiTextFrame, renderFrameToCanvas, renderTextBackground, renderTextFrameToCanvas, renderTextToCanvas, snapshotAndDownload, videoToAsciiFrames, videoToAsciiTextFrames } from './core.js';
3
- export { C as CHARACTER_SETS, f as STUDIO_STYLES, i as StudioStyle } from './model-DVm46H2S.js';
3
+ export { C as CHARACTER_SETS, g as STUDIO_STYLES, n as StudioStyle } from './model-CMKdRB30.js';
4
4
  import './hover-catalog-BeIkNwhH.js';
@@ -70,6 +70,93 @@ declare const STUDIO_CHARACTER_SETS: {
70
70
  };
71
71
  };
72
72
 
73
+ /** Input/output coordinates use 0–1. Curves have at most 16 points, including endpoints. */
74
+ type StudioCurvePoint = [number, number];
75
+ declare const STUDIO_CURVE_CHANNELS: readonly ["rgb", "red", "green", "blue"];
76
+ type StudioCurveChannel = typeof STUDIO_CURVE_CHANNELS[number];
77
+ type StudioCurves = Record<StudioCurveChannel, StudioCurvePoint[]>;
78
+ /** Accept saved settings safely. Repeated inputs keep the last valid point. */
79
+ declare function normalizeStudioCurve(input: unknown): StudioCurvePoint[];
80
+ declare function normalizeStudioCurves(input: unknown): StudioCurves;
81
+ /** Shape-preserving cubic interpolation: no overshoot between control points.
82
+ * The same 256 samples drive the editor graph and the pre-conversion transform.
83
+ * Build on settings changes, never inside the per-pixel loop.
84
+ */
85
+ declare function createStudioCurveLookup(input: unknown): Uint8Array;
86
+
87
+ /** Source transformations, applied in list order before style conversion. */
88
+ declare const STUDIO_WARPS: readonly [{
89
+ readonly value: "twirl";
90
+ readonly label: "Twirl";
91
+ readonly description: "Rotate the center into a smooth spiral; the outer boundary stays fixed.";
92
+ readonly direction: false;
93
+ readonly frequency: false;
94
+ }, {
95
+ readonly value: "pinch";
96
+ readonly label: "Pinch";
97
+ readonly description: "Contract the center, or expand it with negative strength.";
98
+ readonly direction: false;
99
+ readonly frequency: false;
100
+ }, {
101
+ readonly value: "sphere";
102
+ readonly label: "Spherize";
103
+ readonly description: "Magnify a rounded lens through the source; negative strength recedes.";
104
+ readonly direction: false;
105
+ readonly frequency: false;
106
+ }, {
107
+ readonly value: "ripple";
108
+ readonly label: "Ripple";
109
+ readonly description: "Bend the image through concentric, soft-edged waves.";
110
+ readonly direction: false;
111
+ readonly frequency: true;
112
+ }, {
113
+ readonly value: "zigzag";
114
+ readonly label: "Zigzag";
115
+ readonly description: "Alternate the twist in sharp, concentric bands.";
116
+ readonly direction: false;
117
+ readonly frequency: true;
118
+ }, {
119
+ readonly value: "shear";
120
+ readonly label: "Shear";
121
+ readonly description: "Slant a region along an adjustable direction.";
122
+ readonly direction: true;
123
+ readonly frequency: false;
124
+ }, {
125
+ readonly value: "smudge";
126
+ readonly label: "Smudge";
127
+ readonly description: "Draw a soft region of the source along one direction.";
128
+ readonly direction: true;
129
+ readonly frequency: false;
130
+ }, {
131
+ readonly value: "polar";
132
+ readonly label: "Polar";
133
+ readonly description: "Unwrap a region into polar coordinates; negative strength wraps it.";
134
+ readonly direction: true;
135
+ readonly frequency: false;
136
+ }, {
137
+ readonly value: "fragment";
138
+ readonly label: "Fragment";
139
+ readonly description: "Offset small source tiles into a stable fractured texture.";
140
+ readonly direction: true;
141
+ readonly frequency: true;
142
+ }];
143
+ type StudioWarpType = typeof STUDIO_WARPS[number]['value'];
144
+ interface StudioWarp {
145
+ type: StudioWarpType;
146
+ enabled?: boolean;
147
+ amount?: number;
148
+ x?: number;
149
+ y?: number;
150
+ /** Radius as a fraction of the canvas's shorter side. */
151
+ radius?: number;
152
+ angle?: number;
153
+ frequency?: number;
154
+ }
155
+ type StudioWarpEdge = 'clamp' | 'transparent';
156
+ declare const MAX_STUDIO_WARPS = 8;
157
+ /** Unknown types are omitted, never silently converted into a different warp. */
158
+ declare function normalizeStudioWarps(input: unknown): Required<StudioWarp>[];
159
+
73
160
  /** Serializable, media-independent editing state. No DOM work at import time. */
74
161
  declare const STUDIO_STYLES: readonly ["ascii", "blocks", "braille", "dots", "lines", "cross", "diagonal", "diamond", "mixed", "pixel", "mosaic", "lego", "voxel", "disco", "dither", "hex", "led", "cmyk"];
75
162
  type StudioStyle = (typeof STUDIO_STYLES)[number];
@@ -107,6 +194,8 @@ interface StudioSettings {
107
194
  zoom: number;
108
195
  rotation: number;
109
196
  };
197
+ warps?: StudioWarp[];
198
+ warpEdge?: StudioWarpEdge;
110
199
  backdrop: {
111
200
  mode: "solid" | "transparent" | "source" | "blurred" | "gradient";
112
201
  color: string;
@@ -127,6 +216,8 @@ interface StudioSettings {
127
216
  gamma?: number;
128
217
  shadows?: number;
129
218
  highlights?: number;
219
+ curves?: Partial<StudioCurves>;
220
+ denoise?: number;
130
221
  };
131
222
  dither: {
132
223
  algorithm: DitherAlgorithm;
@@ -209,4 +300,4 @@ declare function studioGrid(width: number, height: number, settings: Pick<Studio
209
300
  limited: boolean;
210
301
  };
211
302
 
212
- export { BLEND_MODES as B, CHARACTER_SETS as C, DEFAULT_STUDIO_SETTINGS as D, type StudioSettings as S, type StudioInput as a, DITHER_ALGORITHMS as b, type DitherAlgorithm as c, STUDIO_CHARACTER_SETS as d, STUDIO_PALETTES as e, STUDIO_STYLES as f, type StudioLight as g, type StudioMask as h, type StudioStyle as i, studioCrop as j, studioDimensions as k, studioGrid as l, normalizeStudioSettings as n, parseStudioSettings as p, serializeStudioSettings as s, updateStudioSettings as u };
303
+ export { studioGrid as A, BLEND_MODES as B, CHARACTER_SETS as C, DEFAULT_STUDIO_SETTINGS as D, updateStudioSettings as E, MAX_STUDIO_WARPS as M, type StudioSettings as S, type StudioInput as a, DITHER_ALGORITHMS as b, type DitherAlgorithm as c, STUDIO_CHARACTER_SETS as d, STUDIO_CURVE_CHANNELS as e, STUDIO_PALETTES as f, STUDIO_STYLES as g, STUDIO_WARPS as h, type StudioCurveChannel as i, type StudioCurvePoint as j, type StudioCurves as k, type StudioLight as l, type StudioMask as m, type StudioStyle as n, type StudioWarp as o, type StudioWarpEdge as p, type StudioWarpType as q, createStudioCurveLookup as r, normalizeStudioCurve as s, normalizeStudioCurves as t, normalizeStudioSettings as u, normalizeStudioWarps as v, parseStudioSettings as w, serializeStudioSettings as x, studioCrop as y, studioDimensions as z };
@@ -70,6 +70,93 @@ declare const STUDIO_CHARACTER_SETS: {
70
70
  };
71
71
  };
72
72
 
73
+ /** Input/output coordinates use 0–1. Curves have at most 16 points, including endpoints. */
74
+ type StudioCurvePoint = [number, number];
75
+ declare const STUDIO_CURVE_CHANNELS: readonly ["rgb", "red", "green", "blue"];
76
+ type StudioCurveChannel = typeof STUDIO_CURVE_CHANNELS[number];
77
+ type StudioCurves = Record<StudioCurveChannel, StudioCurvePoint[]>;
78
+ /** Accept saved settings safely. Repeated inputs keep the last valid point. */
79
+ declare function normalizeStudioCurve(input: unknown): StudioCurvePoint[];
80
+ declare function normalizeStudioCurves(input: unknown): StudioCurves;
81
+ /** Shape-preserving cubic interpolation: no overshoot between control points.
82
+ * The same 256 samples drive the editor graph and the pre-conversion transform.
83
+ * Build on settings changes, never inside the per-pixel loop.
84
+ */
85
+ declare function createStudioCurveLookup(input: unknown): Uint8Array;
86
+
87
+ /** Source transformations, applied in list order before style conversion. */
88
+ declare const STUDIO_WARPS: readonly [{
89
+ readonly value: "twirl";
90
+ readonly label: "Twirl";
91
+ readonly description: "Rotate the center into a smooth spiral; the outer boundary stays fixed.";
92
+ readonly direction: false;
93
+ readonly frequency: false;
94
+ }, {
95
+ readonly value: "pinch";
96
+ readonly label: "Pinch";
97
+ readonly description: "Contract the center, or expand it with negative strength.";
98
+ readonly direction: false;
99
+ readonly frequency: false;
100
+ }, {
101
+ readonly value: "sphere";
102
+ readonly label: "Spherize";
103
+ readonly description: "Magnify a rounded lens through the source; negative strength recedes.";
104
+ readonly direction: false;
105
+ readonly frequency: false;
106
+ }, {
107
+ readonly value: "ripple";
108
+ readonly label: "Ripple";
109
+ readonly description: "Bend the image through concentric, soft-edged waves.";
110
+ readonly direction: false;
111
+ readonly frequency: true;
112
+ }, {
113
+ readonly value: "zigzag";
114
+ readonly label: "Zigzag";
115
+ readonly description: "Alternate the twist in sharp, concentric bands.";
116
+ readonly direction: false;
117
+ readonly frequency: true;
118
+ }, {
119
+ readonly value: "shear";
120
+ readonly label: "Shear";
121
+ readonly description: "Slant a region along an adjustable direction.";
122
+ readonly direction: true;
123
+ readonly frequency: false;
124
+ }, {
125
+ readonly value: "smudge";
126
+ readonly label: "Smudge";
127
+ readonly description: "Draw a soft region of the source along one direction.";
128
+ readonly direction: true;
129
+ readonly frequency: false;
130
+ }, {
131
+ readonly value: "polar";
132
+ readonly label: "Polar";
133
+ readonly description: "Unwrap a region into polar coordinates; negative strength wraps it.";
134
+ readonly direction: true;
135
+ readonly frequency: false;
136
+ }, {
137
+ readonly value: "fragment";
138
+ readonly label: "Fragment";
139
+ readonly description: "Offset small source tiles into a stable fractured texture.";
140
+ readonly direction: true;
141
+ readonly frequency: true;
142
+ }];
143
+ type StudioWarpType = typeof STUDIO_WARPS[number]['value'];
144
+ interface StudioWarp {
145
+ type: StudioWarpType;
146
+ enabled?: boolean;
147
+ amount?: number;
148
+ x?: number;
149
+ y?: number;
150
+ /** Radius as a fraction of the canvas's shorter side. */
151
+ radius?: number;
152
+ angle?: number;
153
+ frequency?: number;
154
+ }
155
+ type StudioWarpEdge = 'clamp' | 'transparent';
156
+ declare const MAX_STUDIO_WARPS = 8;
157
+ /** Unknown types are omitted, never silently converted into a different warp. */
158
+ declare function normalizeStudioWarps(input: unknown): Required<StudioWarp>[];
159
+
73
160
  /** Serializable, media-independent editing state. No DOM work at import time. */
74
161
  declare const STUDIO_STYLES: readonly ["ascii", "blocks", "braille", "dots", "lines", "cross", "diagonal", "diamond", "mixed", "pixel", "mosaic", "lego", "voxel", "disco", "dither", "hex", "led", "cmyk"];
75
162
  type StudioStyle = (typeof STUDIO_STYLES)[number];
@@ -107,6 +194,8 @@ interface StudioSettings {
107
194
  zoom: number;
108
195
  rotation: number;
109
196
  };
197
+ warps?: StudioWarp[];
198
+ warpEdge?: StudioWarpEdge;
110
199
  backdrop: {
111
200
  mode: "solid" | "transparent" | "source" | "blurred" | "gradient";
112
201
  color: string;
@@ -127,6 +216,8 @@ interface StudioSettings {
127
216
  gamma?: number;
128
217
  shadows?: number;
129
218
  highlights?: number;
219
+ curves?: Partial<StudioCurves>;
220
+ denoise?: number;
130
221
  };
131
222
  dither: {
132
223
  algorithm: DitherAlgorithm;
@@ -209,4 +300,4 @@ declare function studioGrid(width: number, height: number, settings: Pick<Studio
209
300
  limited: boolean;
210
301
  };
211
302
 
212
- export { BLEND_MODES as B, CHARACTER_SETS as C, DEFAULT_STUDIO_SETTINGS as D, type StudioSettings as S, type StudioInput as a, DITHER_ALGORITHMS as b, type DitherAlgorithm as c, STUDIO_CHARACTER_SETS as d, STUDIO_PALETTES as e, STUDIO_STYLES as f, type StudioLight as g, type StudioMask as h, type StudioStyle as i, studioCrop as j, studioDimensions as k, studioGrid as l, normalizeStudioSettings as n, parseStudioSettings as p, serializeStudioSettings as s, updateStudioSettings as u };
303
+ export { studioGrid as A, BLEND_MODES as B, CHARACTER_SETS as C, DEFAULT_STUDIO_SETTINGS as D, updateStudioSettings as E, MAX_STUDIO_WARPS as M, type StudioSettings as S, type StudioInput as a, DITHER_ALGORITHMS as b, type DitherAlgorithm as c, STUDIO_CHARACTER_SETS as d, STUDIO_CURVE_CHANNELS as e, STUDIO_PALETTES as f, STUDIO_STYLES as g, STUDIO_WARPS as h, type StudioCurveChannel as i, type StudioCurvePoint as j, type StudioCurves as k, type StudioLight as l, type StudioMask as m, type StudioStyle as n, type StudioWarp as o, type StudioWarpEdge as p, type StudioWarpType as q, createStudioCurveLookup as r, normalizeStudioCurve as s, normalizeStudioCurves as t, normalizeStudioSettings as u, normalizeStudioWarps as v, parseStudioSettings as w, serializeStudioSettings as x, studioCrop as y, studioDimensions as z };