@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.
- package/LICENSE +21 -0
- package/README.md +19 -0
- package/dist/animated-quantizer.d.ts +108 -0
- package/dist/animated-quantizer.d.ts.map +1 -0
- package/dist/animated-quantizer.js +196 -0
- package/dist/animated-quantizer.js.map +1 -0
- package/dist/evaluate.d.ts +79 -0
- package/dist/evaluate.d.ts.map +1 -0
- package/dist/evaluate.js +128 -0
- package/dist/evaluate.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/memo-cache.d.ts +35 -0
- package/dist/memo-cache.d.ts.map +1 -0
- package/dist/memo-cache.js +39 -0
- package/dist/memo-cache.js.map +1 -0
- package/dist/quantizer.d.ts +223 -0
- package/dist/quantizer.d.ts.map +1 -0
- package/dist/quantizer.js +260 -0
- package/dist/quantizer.js.map +1 -0
- package/dist/schemas.d.ts +44 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +46 -0
- package/dist/schemas.js.map +1 -0
- package/dist/testing.d.ts +15 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +15 -0
- package/dist/testing.js.map +1 -0
- package/dist/transition.d.ts +67 -0
- package/dist/transition.d.ts.map +1 -0
- package/dist/transition.js +49 -0
- package/dist/transition.js.map +1 -0
- package/package.json +58 -0
- package/src/animated-quantizer.ts +272 -0
- package/src/evaluate.ts +160 -0
- package/src/index.ts +26 -0
- package/src/memo-cache.ts +58 -0
- package/src/quantizer.ts +503 -0
- package/src/schemas.ts +50 -0
- package/src/testing.ts +15 -0
- 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"}
|
package/dist/schemas.js
ADDED
|
@@ -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
|