@nika-js/onlymap 0.6.19 → 0.6.21

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 (34) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +1 -1
  3. package/dist/{LercDecode.es-Butn4LVX.js → LercDecode.es-B_dD2_mY.js} +1 -1
  4. package/dist/actions.d.ts +94 -1
  5. package/dist/attribute-resolution.d.ts +12 -0
  6. package/dist/{basemap-qZH_aNYE.js → basemap-DK0AJ6ZH.js} +341 -313
  7. package/dist/basemap.d.ts +17 -1
  8. package/dist/declarative-filter.d.ts +2 -16
  9. package/dist/effect-track.d.ts +94 -0
  10. package/dist/effects.d.ts +2 -0
  11. package/dist/elements/om-map.d.ts +11 -8
  12. package/dist/elements/om-story.d.ts +18 -0
  13. package/dist/{geoparquet-DWQCUg6N.js → geoparquet-fc2daxMh.js} +1 -1
  14. package/dist/{index-CeeQ7CH4.js → index-9EEyGbU1.js} +1 -1
  15. package/dist/{index-4St6BumW.js → index-BNZFF535.js} +2 -2
  16. package/dist/{index-BTM6Mblt.js → index-BwoceNAo.js} +1 -1
  17. package/dist/{index-CagRqDDL.js → index-CuBGRyG-.js} +13970 -13685
  18. package/dist/{index-CNlULiHm.js → index-DOPjev5l.js} +1 -1
  19. package/dist/internal-ids.d.ts +2 -0
  20. package/dist/{lerc-cWjnr__g.js → lerc-CMJO8KZO.js} +2 -2
  21. package/dist/onlymap.standalone.js +24388 -24075
  22. package/dist/onlymapjs.js +1 -1
  23. package/dist/programmatic.d.ts +1 -2
  24. package/dist/{raster-BxxtJxxs.js → raster-GMsuQARC.js} +2 -2
  25. package/dist/{raster-pipeline-DlppdBYw.js → raster-pipeline-DNpKXgO3.js} +1 -1
  26. package/dist/runtime-core.d.ts +22 -0
  27. package/dist/snapshot.d.ts +15 -0
  28. package/dist/version.d.ts +1 -1
  29. package/dist/{zarr-BtxMPczZ.js → zarr-KiXluGoJ.js} +2 -2
  30. package/docs/stories.md +2 -0
  31. package/llms.txt +2 -2
  32. package/package.json +1 -1
  33. package/skills/onlymapjs/SKILL.md +1 -1
  34. package/skills/onlymapjs/references/syntax.md +3 -3
package/dist/basemap.d.ts CHANGED
@@ -49,8 +49,24 @@ export declare class MapLibreBasemapAdapter {
49
49
  pitch?: number;
50
50
  bearing?: number;
51
51
  }, deckProps: DeckProps, showAttribution?: boolean, attributionHost?: HTMLElement, deterministic?: boolean);
52
- /** whenSettled's basemap gate (issue #37 follow-up): style + all raster/vector tiles for the current view fully loaded. */
52
+ /**
53
+ * whenSettled's basemap gate (issue #37 follow-up), as an EVENT LATCH
54
+ * rather than a polling predicate: MapLibre's `idle` event is its own
55
+ * definition of done — camera transitions finished, all requested tiles
56
+ * loaded, all fades/transitions complete — which is strictly stronger
57
+ * than `loaded() && areTilesLoaded()` (those say nothing about label
58
+ * fade/collision animation, the measured source of warm-page frame
59
+ * nondeterminism). The latch clears on anything that restarts work
60
+ * (camera writes, a source starting to load, a style change) and sets
61
+ * again only on the next `idle`, so `isIdle()` stays a synchronous read —
62
+ * settleOnce's `loaded()` shape — and both lanes plus `onlymapjs record`
63
+ * inherit it unchanged.
64
+ */
65
+ private idleLatch;
66
+ private wireIdleLatch;
53
67
  isIdle(): boolean;
68
+ /** Camera writes from OUR side must clear the latch immediately — the map's own movestart fires a tick later, and a settle read in that gap would see stale idle. */
69
+ private markBusy;
54
70
  /** The overlay deck's live layers — whenSettled's readiness gate (issue #37). */
55
71
  getDeckLayers(): {
56
72
  isLoaded: boolean;
@@ -1,22 +1,8 @@
1
- /**
2
- * CPU-side mirror of the GPU `DataFilterExtension` test (spec: "Filter-aware
3
- * stats & data (the coherence rule)") — `ctx.stats`/`ctx.dataInViewport`
4
- * apply the SAME field+range/category test(s) by default, so a chart/stat
5
- * reflects what the map visibly shows. A row whose field isn't a finite
6
- * number (numeric) or isn't in the keep-list (categorical) is treated as
7
- * filtered-out, matching the GPU path. With more than one dimension of
8
- * EITHER kind a row passes only if every dimension's test passes (AND
9
- * across dimensions) — the same semantics deck.gl's own packed
10
- * `filterRange`/`filterCategories` arrays apply GPU-side. Numeric and
11
- * categorical are independent mechanisms (see `applyFilterWiring`'s doc
12
- * comment) but combine the same way: a row must pass BOTH kinds when both
13
- * are active on a layer.
14
- */
15
- import type { Shape, LayerFilter, LayerCategoryFilter } from "./ir";
1
+ import type { Shape, LayerFilter, LayerCategoryFilter, LayerData } from "./ir";
16
2
  export declare function applyDeclarativeFilter(rows: readonly unknown[], shape: Shape, filter: LayerFilter): unknown[];
17
3
  /** The same test as a reusable predicate — the columnar viewport filter runs it inside its index-aligned loop. */
18
4
  export declare function declarativeFilterPredicate(shape: Shape, filter: LayerFilter): (row: unknown) => boolean;
19
5
  export declare function applyDeclarativeCategoryFilter(rows: readonly unknown[], shape: Shape, categoryFilter: LayerCategoryFilter): unknown[];
20
6
  /** Categorical twin of `declarativeFilterPredicate` — set membership instead of a range test. */
21
7
  export declare function declarativeCategoryFilterPredicate(shape: Shape, categoryFilter: LayerCategoryFilter): (row: unknown) => boolean;
22
- export declare function warnCategoryCardinality(categoryFilter: LayerCategoryFilter | undefined, rows: readonly unknown[], shape: Shape, warnLabel: string): void;
8
+ export declare function warnCategoryCardinality(categoryFilter: LayerCategoryFilter | undefined, data: LayerData, shape: Shape, warnLabel: string): void;
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Story-time effect evaluation (spec: "Map Stories" / issue #37's pull
3
+ * model, completed for layer effects). `buildCameraLegs`/`cameraAtTime`
4
+ * already make the camera a pure function of story time; this module does
5
+ * the same for the animated verbs (fade / pulse / trace / populate). When
6
+ * the story owns the clock — a paced story (the recorder) or the
7
+ * determinism switch (frame renderers seeking) — those steps are NOT
8
+ * dispatched as actions: the story builds one EffectTrack from its timeline
9
+ * and evaluates every leg at the current story time on each tick or seek.
10
+ * A trace 40% drawn is then just a scene, reproducible at any t, instead
11
+ * of a wall-clock rAF loop racing the capture.
12
+ *
13
+ * Interactive wall-clock playback is untouched: it keeps dispatching the
14
+ * verbs through actions.ts, whose rAF path (effects.ts) remains the clock
15
+ * for anything without a timeline (click-to-trace behaviors, ctx.emit).
16
+ * Both clocks share the same underlying builders — the pure math
17
+ * (traceProgress, pulseOpacity, EASINGS), the populate sweep, the trace
18
+ * target/temp element — so a verb renders identically whichever clock
19
+ * drives it.
20
+ *
21
+ * Evaluation contract: legs are stateless functions of t, EXCEPT the
22
+ * documented enter/exit hooks (temp-layer DOM, trace hide sets), which the
23
+ * evaluator invokes on phase transitions. Seek resets are handled by the
24
+ * story's existing scrub model — restore-initial clears every channel patch
25
+ * and temp layer, then resetState() forgets all phases and applyAt(t)
26
+ * rebuilds the scene from pristine. Follow cameras are the one exception:
27
+ * during a paced run the driver owns the camera, so `follow` is skipped
28
+ * (warned once per track).
29
+ */
30
+ import type { RuntimeCore } from "./runtime-core";
31
+ import type { LayerIR } from "./ir";
32
+ import type { StepInterval } from "./timeline";
33
+ /** The verbs the track owns — fireDueSteps suppresses exactly these while the story clock drives effects. */
34
+ export declare const EFFECT_TRACK_ACTIONS: Set<string>;
35
+ export interface EffectTrackDeps {
36
+ core: RuntimeCore;
37
+ mapEl: Element;
38
+ /**
39
+ * LIVE accessor, never a snapshot: om-map REASSIGNS its IR map on every
40
+ * reconcile (`this.layerIRs = next`), so a captured reference goes stale
41
+ * after the first reconcile of a run — which is guaranteed (the trace
42
+ * leg's own temp-element append triggers one). Legs re-init when a
43
+ * layer's data identity changes (URL arrival), which only works read
44
+ * through here.
45
+ */
46
+ getLayerIRs(): ReadonlyMap<string, LayerIR>;
47
+ }
48
+ /** A leg's resolved behavior — chosen lazily on first need, when the layer's data is in hand. */
49
+ interface LegImpl {
50
+ /** Eased t01 → per-layer patches (the same shapes the wall-clock path writes through patchAnimatedProps). */
51
+ frame(t01: number): Record<string, Record<string, unknown>>;
52
+ /** "hold": past the leg, keep frame(1) applied. "clear": past the leg, the authored state IS the end state. */
53
+ end: "hold" | "clear";
54
+ /** Phase-entry hook (idempotent per activation): temp layers, trace hides. */
55
+ enter?(): void;
56
+ /** Phase-exit hook: teardown of whatever enter() built. */
57
+ exit?(): void;
58
+ }
59
+ interface Leg {
60
+ layerId: string;
61
+ start: number;
62
+ duration: number;
63
+ easing?: (t: number) => number;
64
+ init(deps: EffectTrackDeps): LegImpl | null;
65
+ }
66
+ export declare class EffectTrack {
67
+ private readonly legs;
68
+ private readonly deps;
69
+ private states;
70
+ /** Set by deactivate() (including ensureImpl's re-init teardown) — the heal pass re-applies what a removeEffectKeys may have stripped from a shared layer. */
71
+ private keysRemoved;
72
+ constructor(legs: Leg[], deps: EffectTrackDeps);
73
+ /** Forget all phase state WITHOUT teardown — call only after the story's restore-initial has already cleared patches and temp layers. */
74
+ resetState(): void;
75
+ /**
76
+ * Evaluate every leg at story time t. CONTRACT: t is monotonically
77
+ * non-decreasing between resetState() calls — every caller guarantees it
78
+ * (advanceBy is monotone; seek and the loop restart reset first), so
79
+ * phases only ever move forward here and no backward transition exists.
80
+ * Legs are pre-sorted by start, so cross-leg chains resolve in timeline
81
+ * order.
82
+ */
83
+ applyAt(t: number): void;
84
+ /** Re-applies leg i's current value: frame(1) for a settled hold, the eased frame at t for an active leg, nothing otherwise. Idempotent. */
85
+ private applyLegFrame;
86
+ private ensureImpl;
87
+ private apply;
88
+ private deactivate;
89
+ }
90
+ export declare function buildEffectTrack(steps: readonly {
91
+ action: string;
92
+ payload: Record<string, unknown>;
93
+ }[], intervals: readonly StepInterval[], deps: EffectTrackDeps): EffectTrack;
94
+ export {};
package/dist/effects.d.ts CHANGED
@@ -18,6 +18,8 @@ export declare const EASINGS: Record<string, (t: number) => number>;
18
18
  export declare function traceProgress(t01: number, t0: number, t1: number): number;
19
19
  /** Oscillates 1 → low → 1 per cycle (cosine), ending exactly at 1 for whole cycles. */
20
20
  export declare function pulseOpacity(t01: number, cycles: number, low?: number): number;
21
+ /** Removes exactly one effect's keys from the layer's channel entry, preserving keys other writers own. (Exported for the story-time EffectTrack, which manages its own written-key sets.) */
22
+ export declare function removeEffectKeys(core: RuntimeCore, layerId: string, keys: Set<string>): void;
21
23
  export declare function prefersReducedMotion(): boolean;
22
24
  export interface LayerEffect {
23
25
  /** t01 ∈ [0, 1] → the plain-prop patch for this frame. */
@@ -1,4 +1,5 @@
1
1
  import { HTMLElementBase } from "../env";
2
+ import { RuntimeCore } from "../runtime-core";
2
3
  import { type RuntimeContext } from "../ctx";
3
4
  import { type LightingIR } from "../scene-lighting";
4
5
  import { type ClipBoxIR } from "../clip-box";
@@ -54,7 +55,6 @@ export declare class OmMapElement extends HTMLElementBase {
54
55
  /** Dedup guard for the no-terrain-for-elevation error — same shape as `warnedApproximatePlacement`. */
55
56
  private erroredNoTerrainForElevation;
56
57
  private readyFired;
57
- private firstSettleDrawDone;
58
58
  /** Custom-state holder for the `om-collapsed` height-floor marker — see applyHeightFloor. */
59
59
  private internals;
60
60
  private resolveReady;
@@ -260,19 +260,22 @@ export declare class OmMapElement extends HTMLElementBase {
260
260
  * same path a real deck click/hover coordinate takes, so the om-map-point
261
261
  * event and custom capture tools are testable without a GPU. */
262
262
  /**
263
- * The map's "done drawing" promise (issue #37): resolves once every live
264
- * 3D tileset has refined for the CURRENT view and one further animation
265
- * frame has been painted — the await a pull-model frame renderer (or a
266
- * consumer Playwright test) needs before screenshotting. Resolves
267
- * `{settled:false}` with a console warning on timeout rather than
268
- * rejecting (a late frame is ordinary pop-in, not an error). v1 gates 3D
269
- * tilesets only — basemap raster tiles are not yet awaited.
263
+ * The map's "done drawing" promise (issue #37) delegates to
264
+ * RuntimeCore.whenSettled, the single owner of the settle contract.
270
265
  */
271
266
  whenSettled(opts?: {
272
267
  timeout?: number;
273
268
  }): Promise<{
274
269
  settled: boolean;
275
270
  }>;
271
+ /** Test surface: is the determinism switch active on the core (issue #37 — must be true BEFORE the first render when data-om-recording is authored; the basemap adapter reads it in its constructor). */
272
+ isDeterministicInternal(): boolean;
273
+ /** What the story-time EffectTrack needs to evaluate legs (om-story builds one when the story clock owns effects — paced stories, determinism). getLayerIRs is a LIVE accessor: reconcile REASSIGNS this.layerIRs, so a captured map reference would go stale after the first reconcile of a run. */
274
+ getEffectDepsInternal(): {
275
+ core: RuntimeCore;
276
+ mapEl: Element;
277
+ getLayerIRs(): ReadonlyMap<string, LayerIR>;
278
+ } | null;
276
279
  injectMapPointInternal(coordinate: [number, number] | null, kind?: "click" | "hover", pointerType?: string): void;
277
280
  /** Harness setView (spec: "Consumer Testing Surface") — the one path that reaches pitch/bearing. */
278
281
  setViewInternal(partial: {
@@ -15,6 +15,8 @@ export declare class OmStoryElement extends HTMLElementBase {
15
15
  private pacedGen;
16
16
  /** True while the paced driver owns the camera — fireDueSteps must not dispatch camera actions against it. */
17
17
  private pacedDriving;
18
+ /** Story-time effect evaluation (effect-track.ts) — built lazily when the story clock owns effects, invalidated whenever steps rebuild. */
19
+ private effectTrack;
18
20
  private warnedPacedCameraSkip;
19
21
  private pacedCapture;
20
22
  private captured;
@@ -64,6 +66,22 @@ export declare class OmStoryElement extends HTMLElementBase {
64
66
  */
65
67
  private startPaced;
66
68
  private advanceBy;
69
+ /**
70
+ * The story clock owns effects when playback is pull-model: a PACED STORY
71
+ * (the recorder — wall-clock rAF effects would race the capture clock) or
72
+ * the determinism switch (frame renderers seek; runLayerEffect snaps
73
+ * there). Keyed on the `paced` ATTRIBUTE, deliberately not the transient
74
+ * pacedDriving flag: the flag drops asynchronously on pause, and a
75
+ * scrubber seek in that window would otherwise dispatch the verbs
76
+ * wall-clock (stamping end-state attributes, starting real rAF runners)
77
+ * that the resumed track then double-drives. The clock authority must be
78
+ * stable for a whole playback; flipping it mid-story is out of contract
79
+ * (the next seek re-evaluates cleanly). Interactive wall-clock playback
80
+ * keeps dispatching the verbs as actions — the rAF path in effects.ts is
81
+ * untouched.
82
+ */
83
+ private storyClockOwnsEffects;
84
+ private ensureEffectTrack;
67
85
  private fireDueSteps;
68
86
  /** Steps and the timeline are (re)built lazily when idle — mid-play DOM edits apply on the next play/seek. */
69
87
  private ensureBuilt;
@@ -1,4 +1,4 @@
1
- import { r as p, n as d } from "./index-CagRqDDL.js";
1
+ import { r as p, n as d } from "./index-CuBGRyG-.js";
2
2
  function g(t) {
3
3
  if (t == null) return !0;
4
4
  const e = t, n = e.id?.code;
@@ -1,4 +1,4 @@
1
- import { ae as _t, af as Ct } from "./index-CagRqDDL.js";
1
+ import { ae as _t, af as Ct } from "./index-CuBGRyG-.js";
2
2
  function Yt(e, r, t = 2, i, o = "xy") {
3
3
  const s = r && r.length, l = s ? r[0] * t : e.length;
4
4
  let c = Ut(e, 0, l, t, !0, i && i[0], o);
@@ -1,5 +1,5 @@
1
- import { i as E, j as S, k as R, o as N, p as h, q as w, s as O, t as W, v as x, w as I, x as B, y as _, A as P, B as k, E as $, F as z, H as v, I as F, J as C, K as U, N as p, O as M } from "./index-CagRqDDL.js";
2
- import { P as $e, R as ze, _ as ve, Q as Ce, S as Ue, T as Me, U as je, X as De, Y as Je, Z as qe, $ as He, a0 as Ve, a1 as Ge, a2 as Ke, a3 as Qe, a4 as Xe, a5 as Ye, a6 as Ze, a7 as et, a8 as tt, a9 as nt, aa as rt, ab as at, ac as st, ad as ot } from "./index-CagRqDDL.js";
1
+ import { i as E, j as S, k as R, o as N, p as h, q as w, s as O, t as W, v as x, w as I, x as B, y as _, A as P, B as k, E as $, F as z, H as v, I as F, J as C, K as U, N as p, O as M } from "./index-CuBGRyG-.js";
2
+ import { P as $e, R as ze, _ as ve, Q as Ce, S as Ue, T as Me, U as je, X as De, Y as Je, Z as qe, $ as He, a0 as Ve, a1 as Ge, a2 as Ke, a3 as Qe, a4 as Xe, a5 as Ye, a6 as Ze, a7 as et, a8 as tt, a9 as nt, aa as rt, ab as at, ac as st, ad as ot } from "./index-CuBGRyG-.js";
3
3
  import { g as j, i as D } from "./table-accessors-CYWTzpQI.js";
4
4
  async function J(t, e, n = {}, r = {}) {
5
5
  const a = E(t), s = S.getWorkerFarm(n), { source: o } = n, c = { name: a, source: o };
@@ -1,4 +1,4 @@
1
- import { ag as Be, ah as le, ai as ce, aj as De, ak as Oe, al as ke } from "./index-CagRqDDL.js";
1
+ import { ag as Be, ah as le, ai as ce, aj as De, ak as Oe, al as ke } from "./index-CuBGRyG-.js";
2
2
  import { y as ve, a as he, z as G, R as J, A as ue, C as Fe, F as je, n as xe, S as Ie, E as Ne } from "./recordbatch-Bpc0uxFn.js";
3
3
  import { g as V, a as fe, b as Le, c as Ue, d as Me, e as qe, m as Ve } from "./table-accessors-CYWTzpQI.js";
4
4
  import { c as $e } from "./convert-arrow-schema-DrAihRf9.js";