/** * BoundaryDef -- the core primitive of constraint-based adaptive rendering. * * A boundary defines quantization: how a continuous signal value maps * to a discrete set of named states. Content-addressed via FNV-1a. * * @module */ import type { SignalInput, ThresholdValue, ContentAddress } from './brands.js'; import type { EvaluateResult } from './type-utils.js'; /** The core primitive. Source of truth for quantization boundaries. */ interface BoundaryDef { readonly _tag: 'BoundaryDef'; readonly _version: 1; readonly id: ContentAddress; readonly input: SignalInput; readonly thresholds: readonly ThresholdValue[]; readonly states: S; readonly hysteresis?: number; readonly spec?: BoundarySpec; } interface BoundaryFactory { make(config: { readonly input: I; readonly at: { readonly [K in keyof S]: readonly [number, S[K]]; }; readonly hysteresis?: number; readonly spec?: BoundarySpec; }): BoundaryDef; } /** * Evaluate which state a value falls into given a boundary. * * The cheap face of evaluation: returns just the resolved state name via the * single f32-canonical {@link rawIndexF32} kernel (no hysteresis, no crossing * detection). For the rich `{state, index, value, crossed}` result — and for * hysteresis — use {@link _evaluateResult}. * * @example * ```ts * const bp = Boundary.make({ input: 'viewport.width', at: [[0, 'sm'], [768, 'md'], [1024, 'lg']] }); * const state = Boundary.evaluate(bp, 800); * // state === 'md' * ``` */ declare function _evaluate(boundary: B, value: number): B['states'][number]; /** * Batch-evaluate many values against ONE boundary into their raw state * indices — the `i` such that `boundary.states[i]` is the state for that value. * * This is the WASM-accelerated face of {@link _evaluate}. It routes through * `WASMDispatch.kernels().batchBoundaryEval`: the Rust `czap-compute` kernel * once {@link WASMDispatch.load} has run, the pure-TS `fallbackKernels` * otherwise. BOTH select the identical index — the fallback IS the * {@link rawIndexF32} loop and the WASM kernel is locked to it by the * wasm-parity property suite — so the output is bit-identical to mapping * {@link _evaluate} over `values`, loaded or not. The win is throughput on * large value sets (offline frame precompute, scrub timelines, per-entity * scene signals), never different numbers. * * Stateless raw selection, like {@link _evaluate} (no hysteresis). Map indices * to state names with `boundary.states[i]` when you need them. * * @example * ```ts * const bp = Boundary.make({ input: 'scroll', at: [[0, 'top'], [500, 'mid'], [1500, 'deep']] }); * const idx = Boundary.evaluateBatch(bp, [120, 800, 2000]); * // idx → Uint32Array [0, 1, 2]; bp.states[idx[1]] === 'mid' * ``` */ declare function _evaluateBatch(boundary: B, values: ArrayLike): Uint32Array; /** * Evaluate a value against a boundary into the rich {@link EvaluateResult} * `{ state, index, value, crossed }`. * * This is the canonical home of `index` + `crossed` (consumed by the quantizer * and, downstream, by Stage pose-lowering). It is also the single hysteresis * implementation: `evaluateWithHysteresis` is its string projection. * * Raw state selection uses the f32-canonical {@link rawIndexF32} kernel; the * half-width dead-zone refinement (when a `previousState` and `hysteresis` are * supplied) compares in f64 against the un-rounded thresholds, matching the * prior `evaluateWithHysteresis` and quantizer semantics exactly. */ declare function _evaluateResult(boundary: B, value: number, previousState?: B['states'][number]): EvaluateResult; /** * Evaluate with hysteresis (requires previous state). Half-width dead zone algorithm. * * Prevents flickering at boundary edges by requiring the value to cross * beyond a dead zone (half the hysteresis width) before transitioning states. * * @example * ```ts * const bp = Boundary.make({ input: 'viewport.width', at: [[0, 'sm'], [768, 'md']], hysteresis: 20 }); * const state1 = Boundary.evaluateWithHysteresis(bp, 770, 'sm'); * // state1 === 'sm' (within dead zone, stays at previous) * const state2 = Boundary.evaluateWithHysteresis(bp, 780, 'sm'); * // state2 === 'md' (past dead zone, transitions) * ``` */ declare function _evaluateWithHysteresis(boundary: B, value: number, previousState: B['states'][number]): B['states'][number]; /** * Boundary namespace -- the core primitive of constraint-based adaptive rendering. * * Create boundaries that quantize continuous signal values into discrete named * states. Supports hysteresis for flicker-free transitions at threshold edges. * * @example * ```ts * import { Boundary } from '@czap/core'; * * const bp = Boundary.make({ * input: 'viewport.width', * at: [[0, 'mobile'], [768, 'tablet'], [1024, 'desktop']], * hysteresis: 20, * }); * const state = Boundary.evaluate(bp, 900); * // state === 'tablet' * const stableState = Boundary.evaluateWithHysteresis(bp, 770, 'mobile'); * // stableState === 'mobile' (within dead zone) * ``` */ /** * Check whether a boundary is active given its optional spec and current context. * Returns true if the boundary has no spec or the spec allows evaluation. */ declare function _isActive(boundary: B, context?: { capabilities?: Record; nowMs?: number; activeExperiments?: ReadonlyArray; }): boolean; /** * Boundary — core primitive of constraint-based adaptive rendering. * * A boundary quantizes a continuous signal (viewport, scroll, audio, …) into * a discrete set of named states. Every boundary is content-addressed via * FNV-1a, supports optional hysteresis to prevent flicker at thresholds, and * can be gated by a {@link BoundarySpec} for A/B or device-conditional activation. * * @example * ```ts * import { Boundary } from '@czap/core'; * * const viewport = Boundary.make({ * input: 'viewport.width', * at: [[0, 'mobile'], [640, 'tablet'], [1024, 'desktop']], * hysteresis: 16, * }); * Boundary.evaluate(viewport, 800); // 'tablet' * ``` */ export declare const Boundary: BoundaryFactory & { evaluate: typeof _evaluate; evaluateResult: typeof _evaluateResult; evaluateBatch: typeof _evaluateBatch; evaluateWithHysteresis: typeof _evaluateWithHysteresis; isActive: typeof _isActive; }; /** * BoundarySpec: optional filter that gates whether a boundary is active. * Enables A/B testing, time-bounded experiments, and device targeting * without external wrapping logic. * * Wired into the Astro runtime `evaluateBoundary` path (host-side gating before * state transitions). JSON-serializable fields * (`timeRange`, `experimentId`) round-trip through `data-czap-boundary`; * `deviceFilter` is host-only (functions cannot cross the wire). */ export interface BoundarySpec { /** Only evaluate this boundary when the device filter returns true. */ readonly deviceFilter?: (capabilities: Record) => boolean; /** Only evaluate this boundary within this time range (epoch ms). */ readonly timeRange?: { readonly from?: number; readonly until?: number; }; /** Only evaluate this boundary for participants in this experiment. */ readonly experimentId?: string; } /** Check if a BoundarySpec allows evaluation given current context. */ declare function _isSpecActive(spec: BoundarySpec | undefined, context?: { capabilities?: Record; nowMs?: number; activeExperiments?: ReadonlyArray; }): boolean; /** BoundarySpec namespace — helpers for working with the optional activation filter on a boundary. */ export declare const BoundarySpec: { /** Check whether a {@link BoundarySpec} allows evaluation in the given context. */ isActive: typeof _isSpecActive; }; export declare namespace Boundary { /** Structural shape of a boundary definition parameterized by input name `I` and state tuple `S`. */ type Shape = BoundaryDef; /** Alias for {@link BoundarySpec}. */ type Spec = BoundarySpec; } export {}; //# sourceMappingURL=boundary.d.ts.map