@czap/quantizer 0.1.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 (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +19 -0
  3. package/dist/animated-quantizer.d.ts +108 -0
  4. package/dist/animated-quantizer.d.ts.map +1 -0
  5. package/dist/animated-quantizer.js +196 -0
  6. package/dist/animated-quantizer.js.map +1 -0
  7. package/dist/evaluate.d.ts +79 -0
  8. package/dist/evaluate.d.ts.map +1 -0
  9. package/dist/evaluate.js +128 -0
  10. package/dist/evaluate.js.map +1 -0
  11. package/dist/index.d.ts +18 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +16 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/memo-cache.d.ts +35 -0
  16. package/dist/memo-cache.d.ts.map +1 -0
  17. package/dist/memo-cache.js +39 -0
  18. package/dist/memo-cache.js.map +1 -0
  19. package/dist/quantizer.d.ts +223 -0
  20. package/dist/quantizer.d.ts.map +1 -0
  21. package/dist/quantizer.js +260 -0
  22. package/dist/quantizer.js.map +1 -0
  23. package/dist/schemas.d.ts +44 -0
  24. package/dist/schemas.d.ts.map +1 -0
  25. package/dist/schemas.js +46 -0
  26. package/dist/schemas.js.map +1 -0
  27. package/dist/testing.d.ts +15 -0
  28. package/dist/testing.d.ts.map +1 -0
  29. package/dist/testing.js +15 -0
  30. package/dist/testing.js.map +1 -0
  31. package/dist/transition.d.ts +67 -0
  32. package/dist/transition.d.ts.map +1 -0
  33. package/dist/transition.js +49 -0
  34. package/dist/transition.js.map +1 -0
  35. package/package.json +58 -0
  36. package/src/animated-quantizer.ts +272 -0
  37. package/src/evaluate.ts +160 -0
  38. package/src/index.ts +26 -0
  39. package/src/memo-cache.ts +58 -0
  40. package/src/quantizer.ts +503 -0
  41. package/src/schemas.ts +50 -0
  42. package/src/testing.ts +15 -0
  43. package/src/transition.ts +97 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memo-cache.d.ts","sourceRoot":"","sources":["../src/memo-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,UAAU,cAAc,CAAC,CAAC;IACxB,GAAG,CAAC,GAAG,EAAE,cAAc,GAAG,CAAC,GAAG,SAAS,CAAC;IACxC,GAAG,CAAC,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IACzC,GAAG,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,iBAAS,KAAK,CAAC,CAAC,KAAK,cAAc,CAAC,CAAC,CAAC,CAoBrC;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS;IACpB,mDAAmD;;CAEpD,CAAC;AAEF,MAAM,CAAC,OAAO,WAAW,SAAS,CAAC;IACjC,mEAAmE;IACnE,KAAY,KAAK,CAAC,CAAC,IAAI,cAAc,CAAC,CAAC,CAAC,CAAC;CAC1C"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * MemoCache -- content-address memoization layer.
3
+ *
4
+ * Boundaries and quantizer configs are already content-addressed via FNV-1a.
5
+ * This cache ensures identical configs never recompute. Content-addressed keys
6
+ * mean the cache is auto-invalidating: change definition → hash changes → miss.
7
+ *
8
+ * @module
9
+ */
10
+ function _make() {
11
+ const store = new Map();
12
+ return {
13
+ get(key) {
14
+ return store.get(key);
15
+ },
16
+ set(key, value) {
17
+ store.set(key, value);
18
+ },
19
+ has(key) {
20
+ return store.has(key);
21
+ },
22
+ get size() {
23
+ return store.size;
24
+ },
25
+ };
26
+ }
27
+ /**
28
+ * Content-address memoization cache.
29
+ *
30
+ * Keys are {@link ContentAddress} values, so the cache is auto-invalidating:
31
+ * any change to an upstream definition produces a new hash and a guaranteed
32
+ * miss. Backed by an unbounded {@link Map}; callers are responsible for
33
+ * lifetime and eviction if needed.
34
+ */
35
+ export const MemoCache = {
36
+ /** Construct a fresh cache with value type `V`. */
37
+ make: _make,
38
+ };
39
+ //# sourceMappingURL=memo-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memo-cache.js","sourceRoot":"","sources":["../src/memo-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAWH,SAAS,KAAK;IACZ,MAAM,KAAK,GAAG,IAAI,GAAG,EAAqB,CAAC;IAE3C,OAAO;QACL,GAAG,CAAC,GAAmB;YACrB,OAAO,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC;QAED,GAAG,CAAC,GAAmB,EAAE,KAAQ;YAC/B,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACxB,CAAC;QAED,GAAG,CAAC,GAAmB;YACrB,OAAO,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC;QAED,IAAI,IAAI;YACN,OAAO,KAAK,CAAC,IAAI,CAAC;QACpB,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,mDAAmD;IACnD,IAAI,EAAE,KAAK;CACZ,CAAC"}
@@ -0,0 +1,223 @@
1
+ /**
2
+ * `Q.from(boundary).outputs({ ... })` builder API.
3
+ * Creates {@link QuantizerConfig} with content-addressed identity, and
4
+ * {@link LiveQuantizer} with reactive output streams.
5
+ *
6
+ * Wired: MotionTier-gated output routing, springToLinearCSS auto-generation,
7
+ * content-address memoization via {@link MemoCache}.
8
+ *
9
+ * @module
10
+ */
11
+ import type { Scope } from 'effect';
12
+ import { Effect, Stream } from 'effect';
13
+ import type { Boundary, ContentAddress, Quantizer, OutputsFor } from '@czap/core';
14
+ import type { MotionTier } from '@czap/core';
15
+ /**
16
+ * Compilation target for quantizer per-state outputs.
17
+ *
18
+ * `css` emits style declarations, `glsl`/`wgsl` emit shader uniforms,
19
+ * `aria` emits accessibility attributes, `ai` emits model-facing signals.
20
+ * MotionTier gates which targets a device is permitted to receive; see
21
+ * `TIER_TARGETS` (in `@czap/quantizer/testing`).
22
+ */
23
+ export type OutputTarget = 'css' | 'glsl' | 'wgsl' | 'aria' | 'ai';
24
+ export type { MotionTier } from '@czap/core';
25
+ /**
26
+ * MotionTier → allowed {@link OutputTarget} set.
27
+ *
28
+ * Higher tiers include lower-tier targets. `none` only allows ARIA; `compute`
29
+ * unlocks every target including WGSL and AI signal routing. `force()` can
30
+ * override this gating per-target for prototype and test scenarios.
31
+ */
32
+ export declare const TIER_TARGETS: Record<MotionTier, ReadonlySet<OutputTarget>>;
33
+ /**
34
+ * Per-target output tables keyed by boundary state.
35
+ *
36
+ * Each optional field is a record mapping every state in `B` to a target-
37
+ * specific value shape: CSS allows `string | number`, GLSL/WGSL are numeric
38
+ * only, ARIA is string only, AI is unconstrained. Missing fields simply
39
+ * skip that target during dispatch.
40
+ */
41
+ export interface QuantizerOutputs<B extends Boundary.Shape> {
42
+ /** CSS property map per state (values are raw CSS, e.g. `'16px'` or `1`). */
43
+ readonly css?: OutputsFor<B, Record<string, string | number>>;
44
+ /** GLSL uniform values per state (numeric only). */
45
+ readonly glsl?: OutputsFor<B, Record<string, number>>;
46
+ /** WGSL uniform values per state (numeric only). */
47
+ readonly wgsl?: OutputsFor<B, Record<string, number>>;
48
+ /** ARIA attribute map per state (string values only). */
49
+ readonly aria?: OutputsFor<B, Record<string, string>>;
50
+ /** AI-facing signals per state (free-form; consumed by LLMAdapter). */
51
+ readonly ai?: OutputsFor<B, Record<string, unknown>>;
52
+ }
53
+ /**
54
+ * Spring physics parameters for CSS easing auto-generation.
55
+ *
56
+ * When a {@link QuantizerConfig} carries a spring, its CSS outputs receive an
57
+ * injected `--czap-easing` custom property derived via `Easing.springToLinearCSS`
58
+ * so native `linear()` timing matches the physical spring response.
59
+ */
60
+ export interface SpringConfig {
61
+ /** Spring constant (force per unit displacement); higher = snappier. */
62
+ readonly stiffness: number;
63
+ /** Damping coefficient; higher = less oscillation. */
64
+ readonly damping: number;
65
+ /** Mass of the animated body; defaults to `1`. */
66
+ readonly mass?: number;
67
+ }
68
+ /**
69
+ * Options accepted by {@link Q.from}.
70
+ *
71
+ * `tier` gates which output targets get produced (see `TIER_TARGETS` (in `@czap/quantizer/testing`)).
72
+ * `spring` enables automatic CSS `--czap-easing` injection on CSS outputs.
73
+ */
74
+ export interface QuantizerFromOptions {
75
+ /** MotionTier for output gating; omit to allow all targets. */
76
+ readonly tier?: MotionTier;
77
+ /** Spring config that drives CSS easing generation for CSS outputs. */
78
+ readonly spring?: SpringConfig;
79
+ }
80
+ /**
81
+ * Immutable, content-addressed quantizer definition.
82
+ *
83
+ * The `id` is an FNV-1a hash over the boundary id and outputs, so two
84
+ * configs with identical definitions share the same address and are
85
+ * deduplicated by the internal memo cache. `create()` materializes a
86
+ * fresh {@link LiveQuantizer} within an Effect scope.
87
+ */
88
+ export interface QuantizerConfig<B extends Boundary.Shape, O extends QuantizerOutputs<B> = QuantizerOutputs<B>> {
89
+ /** Boundary this config quantizes against. */
90
+ readonly boundary: B;
91
+ /** Per-target output tables keyed by state. */
92
+ readonly outputs: O;
93
+ /** Content-addressed identity (FNV-1a of boundary id + outputs). */
94
+ readonly id: ContentAddress;
95
+ /** Motion tier gating active targets; see `TIER_TARGETS` (in `@czap/quantizer/testing`). */
96
+ readonly tier?: MotionTier;
97
+ /** Spring config driving CSS easing injection. */
98
+ readonly spring?: SpringConfig;
99
+ /** Instantiate a reactive {@link LiveQuantizer} scoped to an Effect fiber. */
100
+ create(): Effect.Effect<LiveQuantizer<B, O>, never, Scope.Scope>;
101
+ }
102
+ /**
103
+ * Runtime-instantiated quantizer with reactive output dispatch.
104
+ *
105
+ * Extends the core {@link Quantizer} with a reactive outputs table: as
106
+ * boundary crossings are detected, `currentOutputs` updates and
107
+ * `outputChanges` streams the new per-target record. Consumers typically
108
+ * subscribe via `Stream.runForEach(liveQuantizer.outputChanges, …)`.
109
+ *
110
+ * @example
111
+ * ```ts
112
+ * import { Boundary } from '@czap/core';
113
+ * import { Q } from '@czap/quantizer';
114
+ * import { Effect, Stream } from 'effect';
115
+ *
116
+ * const b = Boundary.make({
117
+ * input: 'w', states: ['sm', 'lg'] as const, thresholds: [0, 768],
118
+ * });
119
+ * const config = Q.from(b).outputs({
120
+ * css: { sm: { fontSize: '14px' }, lg: { fontSize: '18px' } },
121
+ * });
122
+ * Effect.runSync(Effect.scoped(Effect.gen(function* () {
123
+ * const live = yield* config.create();
124
+ * live.evaluate(900); // triggers crossing; outputs stream emits CSS
125
+ * })));
126
+ * ```
127
+ */
128
+ export interface LiveQuantizer<B extends Boundary.Shape, O extends QuantizerOutputs<B> = QuantizerOutputs<B>> extends Quantizer<B> {
129
+ /** The config this quantizer was created from. */
130
+ readonly config: QuantizerConfig<B, O>;
131
+ /** Read the currently-active per-target output record. */
132
+ readonly currentOutputs: Effect.Effect<Partial<{
133
+ [K in OutputTarget]: Record<string, unknown>;
134
+ }>>;
135
+ /** Stream of per-target output records emitted on each boundary crossing. */
136
+ readonly outputChanges: Stream.Stream<Partial<{
137
+ [K in OutputTarget]: Record<string, unknown>;
138
+ }>>;
139
+ }
140
+ /**
141
+ * Fluent builder returned by {@link Q.from}.
142
+ *
143
+ * Call `.outputs({ ... })` to produce a content-addressed
144
+ * {@link QuantizerConfig}, optionally preceded by `.force(targets)` to
145
+ * override MotionTier gating for specific targets (e.g., enabling AI
146
+ * signals at the `none` tier for testing).
147
+ */
148
+ export interface QuantizerBuilder<B extends Boundary.Shape> {
149
+ /** Attach per-target output tables and produce a {@link QuantizerConfig}. */
150
+ outputs<O extends QuantizerOutputs<B>>(outputs: O): QuantizerConfig<B, O>;
151
+ /** Force-enable specific targets regardless of the current tier's gating set. */
152
+ force(...targets: OutputTarget[]): QuantizerBuilder<B>;
153
+ }
154
+ /**
155
+ * Create a quantizer builder from a boundary definition.
156
+ *
157
+ * Starts a fluent chain: `Q.from(boundary).outputs({...})` produces a
158
+ * content-addressed `QuantizerConfig` whose `.create()` method yields a
159
+ * reactive `LiveQuantizer` inside an Effect scope.
160
+ *
161
+ * @example
162
+ * ```ts
163
+ * import { Boundary } from '@czap/core';
164
+ * import { Q } from '@czap/quantizer';
165
+ * import { Effect } from 'effect';
166
+ *
167
+ * const boundary = Boundary.make({
168
+ * input: 'width', states: ['sm', 'md', 'lg'] as const,
169
+ * thresholds: [0, 640, 1024],
170
+ * });
171
+ * const config = Q.from(boundary).outputs({
172
+ * css: { sm: { fontSize: '14px' }, md: { fontSize: '16px' }, lg: { fontSize: '18px' } },
173
+ * });
174
+ * const state = Effect.scoped(
175
+ * Effect.gen(function* () {
176
+ * const live = yield* config.create();
177
+ * return live.evaluate(800); // 'md'
178
+ * }),
179
+ * );
180
+ * const result = Effect.runSync(state);
181
+ * ```
182
+ *
183
+ * @param boundary - The boundary definition to quantize against
184
+ * @param options - Optional motion tier and spring configuration
185
+ * @returns A {@link QuantizerBuilder} for chaining `.outputs()` and `.force()`
186
+ */
187
+ declare function fromBoundary<B extends Boundary.Shape>(boundary: B, options?: QuantizerFromOptions): QuantizerBuilder<B>;
188
+ /**
189
+ * Quantizer builder namespace.
190
+ *
191
+ * `Q.from(boundary)` starts a fluent builder that produces a content-addressed
192
+ * {@link QuantizerConfig}. Calling `config.create()` within an Effect scope
193
+ * yields a reactive {@link LiveQuantizer} that evaluates numeric input values
194
+ * against boundary thresholds, dispatches state transitions, and routes
195
+ * per-state outputs (CSS, GLSL, WGSL, ARIA, AI) gated by MotionTier.
196
+ *
197
+ * @example
198
+ * ```ts
199
+ * import { Boundary } from '@czap/core';
200
+ * import { Q } from '@czap/quantizer';
201
+ * import { Effect } from 'effect';
202
+ *
203
+ * const boundary = Boundary.make({
204
+ * input: 'width', states: ['sm', 'lg'] as const,
205
+ * thresholds: [0, 768],
206
+ * });
207
+ * const config = Q.from(boundary).outputs({
208
+ * css: { sm: { display: 'block' }, lg: { display: 'grid' } },
209
+ * });
210
+ * const result = Effect.runSync(Effect.scoped(
211
+ * Effect.gen(function* () {
212
+ * const live = yield* config.create();
213
+ * live.evaluate(1024);
214
+ * return yield* live.currentOutputs;
215
+ * }),
216
+ * ));
217
+ * // result.css => { display: 'grid' }
218
+ * ```
219
+ */
220
+ export declare const Q: {
221
+ readonly from: typeof fromBoundary;
222
+ };
223
+ //# sourceMappingURL=quantizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quantizer.d.ts","sourceRoot":"","sources":["../src/quantizer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,260 @@
1
+ /**
2
+ * `Q.from(boundary).outputs({ ... })` builder API.
3
+ * Creates {@link QuantizerConfig} with content-addressed identity, and
4
+ * {@link LiveQuantizer} with reactive output streams.
5
+ *
6
+ * Wired: MotionTier-gated output routing, springToLinearCSS auto-generation,
7
+ * content-address memoization via {@link MemoCache}.
8
+ *
9
+ * @module
10
+ */
11
+ import { Effect, Stream, SubscriptionRef, Queue } from 'effect';
12
+ import { ContentAddress as mkContentAddress, StateName as mkStateName, TypedRef, Easing, fnv1aBytes, } from '@czap/core';
13
+ import { evaluate } from './evaluate.js';
14
+ import { MemoCache } from './memo-cache.js';
15
+ // ---------------------------------------------------------------------------
16
+ // Internal helpers
17
+ // ---------------------------------------------------------------------------
18
+ /**
19
+ * Typed accessor for the initial state of a boundary. Boundary.make guarantees
20
+ * the states tuple is non-empty, so `states[0]` is always defined; this contains
21
+ * the one unavoidable cast where a generic index access meets noUncheckedIndexedAccess.
22
+ */
23
+ function firstState(boundary) {
24
+ return boundary.states[0];
25
+ }
26
+ /**
27
+ * MotionTier → allowed {@link OutputTarget} set.
28
+ *
29
+ * Higher tiers include lower-tier targets. `none` only allows ARIA; `compute`
30
+ * unlocks every target including WGSL and AI signal routing. `force()` can
31
+ * override this gating per-target for prototype and test scenarios.
32
+ */
33
+ export const TIER_TARGETS = {
34
+ none: new Set(['aria']),
35
+ transitions: new Set(['css', 'aria']),
36
+ animations: new Set(['css', 'aria']),
37
+ physics: new Set(['css', 'glsl', 'aria']),
38
+ compute: new Set(['css', 'glsl', 'wgsl', 'aria', 'ai']),
39
+ };
40
+ // ---------------------------------------------------------------------------
41
+ // Content-address via CBOR canonical encoding + FNV-1a hash (matches @czap/core)
42
+ // ---------------------------------------------------------------------------
43
+ function contentAddress(boundary, outputs) {
44
+ const payload = { boundaryId: boundary.id, outputs };
45
+ return fnv1aBytes(TypedRef.canonicalize(payload));
46
+ }
47
+ // ---------------------------------------------------------------------------
48
+ // Memoization caches
49
+ // ---------------------------------------------------------------------------
50
+ const configCache = MemoCache.make();
51
+ const outputCache = MemoCache.make();
52
+ const springCSSCache = new Map();
53
+ // ---------------------------------------------------------------------------
54
+ // Resolve outputs for the current state, gated by tier
55
+ // ---------------------------------------------------------------------------
56
+ /**
57
+ * Read `outputs[target][state]` through the target-agnostic shape
58
+ * `Record<string, Record<string, unknown>>`. Each QuantizerOutputs target
59
+ * has a different value type (CSS allows `string | number`, GLSL is
60
+ * number-only, etc.), so indexing at the `OutputTarget` union level
61
+ * produces a wide union that TS cannot collapse. This helper performs
62
+ * the one bridging cast so callers stay type-clean.
63
+ */
64
+ function readTargetState(outputs, target, state) {
65
+ const table = outputs[target];
66
+ return table?.[state];
67
+ }
68
+ function resolveOutputs(outputs, state, allowedTargets, forcedTargets, configId, springCSS) {
69
+ // Check output cache
70
+ const cacheKey = mkContentAddress(`${configId}:${state}:${springCSS ? '1' : '0'}`);
71
+ const cached = outputCache.get(cacheKey);
72
+ if (cached)
73
+ return cached;
74
+ const result = {};
75
+ const targets = ['css', 'glsl', 'wgsl', 'aria', 'ai'];
76
+ for (const target of targets) {
77
+ // Check tier gating
78
+ if (allowedTargets !== null && !allowedTargets.has(target)) {
79
+ // Check force escape hatch
80
+ if (forcedTargets === null || !forcedTargets.has(target)) {
81
+ continue;
82
+ }
83
+ }
84
+ const stateOutputs = readTargetState(outputs, target, state);
85
+ if (stateOutputs !== undefined) {
86
+ if (target === 'css' && springCSS) {
87
+ // Inject the spring easing CSS custom property alongside CSS outputs
88
+ result[target] = { ...stateOutputs, '--czap-easing': springCSS };
89
+ }
90
+ else {
91
+ result[target] = stateOutputs;
92
+ }
93
+ }
94
+ }
95
+ outputCache.set(cacheKey, result);
96
+ return result;
97
+ }
98
+ // ---------------------------------------------------------------------------
99
+ // Monotonic HLC for sync evaluate() -- uses Date.now() + incrementing counter
100
+ // ---------------------------------------------------------------------------
101
+ let hlcCounter = 0;
102
+ // ---------------------------------------------------------------------------
103
+ // Spring CSS computation with caching
104
+ // ---------------------------------------------------------------------------
105
+ function getSpringCSS(spring) {
106
+ const key = `${spring.stiffness}:${spring.damping}:${spring.mass ?? 1}`;
107
+ let css = springCSSCache.get(key);
108
+ if (!css) {
109
+ css = Easing.springToLinearCSS(spring);
110
+ springCSSCache.set(key, css);
111
+ }
112
+ return css;
113
+ }
114
+ // ---------------------------------------------------------------------------
115
+ // Q.from(boundary) builder factory
116
+ // ---------------------------------------------------------------------------
117
+ /**
118
+ * Create a quantizer builder from a boundary definition.
119
+ *
120
+ * Starts a fluent chain: `Q.from(boundary).outputs({...})` produces a
121
+ * content-addressed `QuantizerConfig` whose `.create()` method yields a
122
+ * reactive `LiveQuantizer` inside an Effect scope.
123
+ *
124
+ * @example
125
+ * ```ts
126
+ * import { Boundary } from '@czap/core';
127
+ * import { Q } from '@czap/quantizer';
128
+ * import { Effect } from 'effect';
129
+ *
130
+ * const boundary = Boundary.make({
131
+ * input: 'width', states: ['sm', 'md', 'lg'] as const,
132
+ * thresholds: [0, 640, 1024],
133
+ * });
134
+ * const config = Q.from(boundary).outputs({
135
+ * css: { sm: { fontSize: '14px' }, md: { fontSize: '16px' }, lg: { fontSize: '18px' } },
136
+ * });
137
+ * const state = Effect.scoped(
138
+ * Effect.gen(function* () {
139
+ * const live = yield* config.create();
140
+ * return live.evaluate(800); // 'md'
141
+ * }),
142
+ * );
143
+ * const result = Effect.runSync(state);
144
+ * ```
145
+ *
146
+ * @param boundary - The boundary definition to quantize against
147
+ * @param options - Optional motion tier and spring configuration
148
+ * @returns A {@link QuantizerBuilder} for chaining `.outputs()` and `.force()`
149
+ */
150
+ function fromBoundary(boundary, options) {
151
+ const tier = options?.tier;
152
+ const spring = options?.spring;
153
+ const allowedTargets = tier ? (TIER_TARGETS[tier] ?? null) : null;
154
+ let forcedTargets = null;
155
+ const builder = {
156
+ outputs(outputs) {
157
+ const id = contentAddress(boundary, outputs);
158
+ // Check config cache
159
+ const cachedConfig = configCache.get(id);
160
+ if (cachedConfig)
161
+ return cachedConfig;
162
+ // Compute spring CSS if spring config present and CSS outputs exist
163
+ const springCSS = spring && outputs.css ? getSpringCSS(spring) : null;
164
+ const frozenForced = forcedTargets;
165
+ const config = {
166
+ boundary,
167
+ outputs,
168
+ id,
169
+ tier,
170
+ spring,
171
+ create() {
172
+ return Effect.gen(function* () {
173
+ // Boundary.make guarantees non-empty states; head access widens to StateUnion<B>.
174
+ const initialState = firstState(boundary);
175
+ const initialOutputs = resolveOutputs(outputs, initialState, allowedTargets, frozenForced, id, springCSS);
176
+ const stateRef = yield* SubscriptionRef.make(initialState);
177
+ const outputRef = yield* SubscriptionRef.make(initialOutputs);
178
+ const crossingQueue = yield* Queue.unbounded();
179
+ let previousState = initialState;
180
+ const crossingStream = Stream.fromQueue(crossingQueue);
181
+ const liveQuantizer = {
182
+ _tag: 'Quantizer',
183
+ boundary,
184
+ config,
185
+ state: SubscriptionRef.get(stateRef),
186
+ stateSync: () => previousState,
187
+ changes: crossingStream,
188
+ evaluate(value) {
189
+ const result = evaluate(boundary, value, previousState);
190
+ if (result.crossed) {
191
+ const crossing = {
192
+ from: mkStateName(previousState),
193
+ to: mkStateName(result.state),
194
+ timestamp: { wall_ms: Date.now(), counter: hlcCounter++, node_id: 'quantizer' },
195
+ value,
196
+ };
197
+ previousState = result.state;
198
+ const newOutputs = resolveOutputs(outputs, result.state, allowedTargets, frozenForced, id, springCSS);
199
+ Effect.runSync(Effect.all([
200
+ SubscriptionRef.set(stateRef, result.state),
201
+ SubscriptionRef.set(outputRef, newOutputs),
202
+ ]));
203
+ Queue.offerUnsafe(crossingQueue, crossing);
204
+ }
205
+ return result.state;
206
+ },
207
+ currentOutputs: SubscriptionRef.get(outputRef),
208
+ outputChanges: SubscriptionRef.changes(outputRef),
209
+ };
210
+ return liveQuantizer;
211
+ });
212
+ },
213
+ };
214
+ configCache.set(id, config);
215
+ forcedTargets = null;
216
+ return config;
217
+ },
218
+ force(...targets) {
219
+ forcedTargets = new Set(targets);
220
+ return builder;
221
+ },
222
+ };
223
+ return builder;
224
+ }
225
+ /**
226
+ * Quantizer builder namespace.
227
+ *
228
+ * `Q.from(boundary)` starts a fluent builder that produces a content-addressed
229
+ * {@link QuantizerConfig}. Calling `config.create()` within an Effect scope
230
+ * yields a reactive {@link LiveQuantizer} that evaluates numeric input values
231
+ * against boundary thresholds, dispatches state transitions, and routes
232
+ * per-state outputs (CSS, GLSL, WGSL, ARIA, AI) gated by MotionTier.
233
+ *
234
+ * @example
235
+ * ```ts
236
+ * import { Boundary } from '@czap/core';
237
+ * import { Q } from '@czap/quantizer';
238
+ * import { Effect } from 'effect';
239
+ *
240
+ * const boundary = Boundary.make({
241
+ * input: 'width', states: ['sm', 'lg'] as const,
242
+ * thresholds: [0, 768],
243
+ * });
244
+ * const config = Q.from(boundary).outputs({
245
+ * css: { sm: { display: 'block' }, lg: { display: 'grid' } },
246
+ * });
247
+ * const result = Effect.runSync(Effect.scoped(
248
+ * Effect.gen(function* () {
249
+ * const live = yield* config.create();
250
+ * live.evaluate(1024);
251
+ * return yield* live.currentOutputs;
252
+ * }),
253
+ * ));
254
+ * // result.css => { display: 'grid' }
255
+ * ```
256
+ */
257
+ export const Q = {
258
+ from: fromBoundary,
259
+ };
260
+ //# sourceMappingURL=quantizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quantizer.js","sourceRoot":"","sources":["../src/quantizer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Effect Schema definitions for quantizer configuration types.
3
+ *
4
+ * Note: TransitionConfigSchema validates runtime shape (number fields).
5
+ * The branded Millis type is enforced at the TypeScript level via
6
+ * TransitionConfig interface. Decoded values should be wrapped with
7
+ * Millis() at the consumer site.
8
+ */
9
+ import { Schema } from 'effect';
10
+ /**
11
+ * Runtime schema for {@link TransitionConfig}.
12
+ *
13
+ * Validates numeric `duration` and optional `easing`/`delay`. The branded
14
+ * `Millis` type is not enforced here; wrap decoded durations with `Millis()`
15
+ * at the consumer site for type safety.
16
+ */
17
+ export declare const TransitionConfigSchema: Schema.Struct<{
18
+ readonly duration: Schema.Number;
19
+ readonly easing: Schema.optionalKey<Schema.Any>;
20
+ readonly delay: Schema.optionalKey<Schema.Number>;
21
+ }>;
22
+ /** Runtime schema for a {@link TransitionMap} record. */
23
+ export declare const TransitionMapSchema: Schema.$Record<Schema.String, Schema.Struct<{
24
+ readonly duration: Schema.Number;
25
+ readonly easing: Schema.optionalKey<Schema.Any>;
26
+ readonly delay: Schema.optionalKey<Schema.Number>;
27
+ }>>;
28
+ /** Runtime schema for the {@link OutputTarget} literal union. */
29
+ export declare const OutputTargetSchema: Schema.Union<readonly [Schema.Literal<"css">, Schema.Literal<"glsl">, Schema.Literal<"wgsl">, Schema.Literal<"aria">, Schema.Literal<"ai">]>;
30
+ /**
31
+ * Runtime schema for {@link QuantizerOutputs}.
32
+ *
33
+ * Each target is an optional record whose values are unchecked at the
34
+ * schema level; target-specific value constraints live in the TypeScript
35
+ * types on {@link QuantizerOutputs}.
36
+ */
37
+ export declare const QuantizerOutputsSchema: Schema.Struct<{
38
+ readonly css: Schema.optionalKey<Schema.$Record<Schema.String, Schema.Unknown>>;
39
+ readonly glsl: Schema.optionalKey<Schema.$Record<Schema.String, Schema.Unknown>>;
40
+ readonly wgsl: Schema.optionalKey<Schema.$Record<Schema.String, Schema.Unknown>>;
41
+ readonly aria: Schema.optionalKey<Schema.$Record<Schema.String, Schema.Unknown>>;
42
+ readonly ai: Schema.optionalKey<Schema.$Record<Schema.String, Schema.Unknown>>;
43
+ }>;
44
+ //# sourceMappingURL=schemas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB;;;;EAIjC,CAAC;AAEH,yDAAyD;AACzD,eAAO,MAAM,mBAAmB;;;;GAAuD,CAAC;AAExF,iEAAiE;AACjE,eAAO,MAAM,kBAAkB,8IAM7B,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB;;;;;;EAMjC,CAAC"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Effect Schema definitions for quantizer configuration types.
3
+ *
4
+ * Note: TransitionConfigSchema validates runtime shape (number fields).
5
+ * The branded Millis type is enforced at the TypeScript level via
6
+ * TransitionConfig interface. Decoded values should be wrapped with
7
+ * Millis() at the consumer site.
8
+ */
9
+ import { Schema } from 'effect';
10
+ /**
11
+ * Runtime schema for {@link TransitionConfig}.
12
+ *
13
+ * Validates numeric `duration` and optional `easing`/`delay`. The branded
14
+ * `Millis` type is not enforced here; wrap decoded durations with `Millis()`
15
+ * at the consumer site for type safety.
16
+ */
17
+ export const TransitionConfigSchema = Schema.Struct({
18
+ duration: Schema.Number,
19
+ easing: Schema.optionalKey(Schema.Any),
20
+ delay: Schema.optionalKey(Schema.Number),
21
+ });
22
+ /** Runtime schema for a {@link TransitionMap} record. */
23
+ export const TransitionMapSchema = Schema.Record(Schema.String, TransitionConfigSchema);
24
+ /** Runtime schema for the {@link OutputTarget} literal union. */
25
+ export const OutputTargetSchema = Schema.Union([
26
+ Schema.Literal('css'),
27
+ Schema.Literal('glsl'),
28
+ Schema.Literal('wgsl'),
29
+ Schema.Literal('aria'),
30
+ Schema.Literal('ai'),
31
+ ]);
32
+ /**
33
+ * Runtime schema for {@link QuantizerOutputs}.
34
+ *
35
+ * Each target is an optional record whose values are unchecked at the
36
+ * schema level; target-specific value constraints live in the TypeScript
37
+ * types on {@link QuantizerOutputs}.
38
+ */
39
+ export const QuantizerOutputsSchema = Schema.Struct({
40
+ css: Schema.optionalKey(Schema.Record(Schema.String, Schema.Unknown)),
41
+ glsl: Schema.optionalKey(Schema.Record(Schema.String, Schema.Unknown)),
42
+ wgsl: Schema.optionalKey(Schema.Record(Schema.String, Schema.Unknown)),
43
+ aria: Schema.optionalKey(Schema.Record(Schema.String, Schema.Unknown)),
44
+ ai: Schema.optionalKey(Schema.Record(Schema.String, Schema.Unknown)),
45
+ });
46
+ //# sourceMappingURL=schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAC,MAAM,CAAC;IAClD,QAAQ,EAAE,MAAM,CAAC,MAAM;IACvB,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC;IACtC,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC;CACzC,CAAC,CAAC;AAEH,yDAAyD;AACzD,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;AAExF,iEAAiE;AACjE,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC,KAAK,CAAC;IAC7C,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;IACrB,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;IACtB,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;IACtB,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;IACtB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;CACrB,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAC,MAAM,CAAC;IAClD,GAAG,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACrE,IAAI,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACtE,IAAI,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACtE,IAAI,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACtE,EAAE,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;CACrE,CAAC,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Test-only entrypoint for `@czap/quantizer`. Imported as
3
+ * `@czap/quantizer/testing`.
4
+ *
5
+ * `MemoCache` and `TIER_TARGETS` are implementation primitives that
6
+ * power the public `Q.from()` builder internally. Consumers don't need
7
+ * direct access; tests do (for content-address cache assertions and
8
+ * tier-gating verification). Partitioning them off the main entry keeps
9
+ * the public surface focused on the builder.
10
+ *
11
+ * @module
12
+ */
13
+ export { MemoCache } from './memo-cache.js';
14
+ export { TIER_TARGETS } from './quantizer.js';
15
+ //# sourceMappingURL=testing.d.ts.map