@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.
- package/CHANGELOG.md +18 -0
- package/README.md +1 -1
- package/dist/{LercDecode.es-Butn4LVX.js → LercDecode.es-B_dD2_mY.js} +1 -1
- package/dist/actions.d.ts +94 -1
- package/dist/attribute-resolution.d.ts +12 -0
- package/dist/{basemap-qZH_aNYE.js → basemap-DK0AJ6ZH.js} +341 -313
- package/dist/basemap.d.ts +17 -1
- package/dist/declarative-filter.d.ts +2 -16
- package/dist/effect-track.d.ts +94 -0
- package/dist/effects.d.ts +2 -0
- package/dist/elements/om-map.d.ts +11 -8
- package/dist/elements/om-story.d.ts +18 -0
- package/dist/{geoparquet-DWQCUg6N.js → geoparquet-fc2daxMh.js} +1 -1
- package/dist/{index-CeeQ7CH4.js → index-9EEyGbU1.js} +1 -1
- package/dist/{index-4St6BumW.js → index-BNZFF535.js} +2 -2
- package/dist/{index-BTM6Mblt.js → index-BwoceNAo.js} +1 -1
- package/dist/{index-CagRqDDL.js → index-CuBGRyG-.js} +13970 -13685
- package/dist/{index-CNlULiHm.js → index-DOPjev5l.js} +1 -1
- package/dist/internal-ids.d.ts +2 -0
- package/dist/{lerc-cWjnr__g.js → lerc-CMJO8KZO.js} +2 -2
- package/dist/onlymap.standalone.js +24388 -24075
- package/dist/onlymapjs.js +1 -1
- package/dist/programmatic.d.ts +1 -2
- package/dist/{raster-BxxtJxxs.js → raster-GMsuQARC.js} +2 -2
- package/dist/{raster-pipeline-DlppdBYw.js → raster-pipeline-DNpKXgO3.js} +1 -1
- package/dist/runtime-core.d.ts +22 -0
- package/dist/snapshot.d.ts +15 -0
- package/dist/version.d.ts +1 -1
- package/dist/{zarr-BtxMPczZ.js → zarr-KiXluGoJ.js} +2 -2
- package/docs/stories.md +2 -0
- package/llms.txt +2 -2
- package/package.json +1 -1
- package/skills/onlymapjs/SKILL.md +1 -1
- package/skills/onlymapjs/references/syntax.md +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,24 @@ Note: npm collapsed a few closely-spaced releases — the GPX/FlatGeobuf (0.5.4)
|
|
|
8
8
|
and GeoParquet (0.5.5) work shipped to npm together as **0.5.6**, so npm's
|
|
9
9
|
version list jumps 0.5.3 → 0.5.6. Each logical version is listed here regardless.
|
|
10
10
|
|
|
11
|
+
## 0.6.21 — 2026-08-26
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
- **Recordings now capture animations, not just end states.** Fade, pulse, trace, and populate steps animate frame-accurately in `onlymapjs record` output and paced story runs — a 2-second border trace draws itself on across 2 seconds of video instead of appearing fully drawn. Seeking a story under the recording switch lands mid-animation too (a half-drawn trace is just a scene), which external frame renderers rely on. One documented limit: the `trace follow` camera is skipped during recorded runs, since the paced route drives the camera.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
- **On-map labels (`anchor="surface"`) now sit on the landmass they belong to.** Ring selection previously favored densely-digitized slivers and could even pick a hole; features without a usable anchor point no longer draw a stray label at null island.
|
|
18
|
+
- **The `trace follow` camera stays glued to the drawing tip.** It previously sampled the path by distance while the ink advanced by timestamps, so routes with dwells or slow legs pulled the camera away from the head; layers with several separately-timed paths no longer make the camera jump between them.
|
|
19
|
+
- **Blob-format snapshots are byte-stable again.** Stability comparison silently never matched for blob output, so exactly the format video renderers request lost its guarantee.
|
|
20
|
+
- **Seeking a story no longer overwrites fit-bounds or zoom-to poses between camera legs.**
|
|
21
|
+
- **Paid-license render exemption is scoped to real local browser pages** — it no longer applies in environments without a page location at all.
|
|
22
|
+
|
|
23
|
+
## 0.6.20 — 2026-08-26
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
- **Paid licenses now apply when rendering video locally.** A key restricted to your domains couldn't take effect on the local host that `onlymapjs record` (and external frame renderers) serve from, so paid features didn't apply to rendered output. A verified paid key is now honored in local render contexts; unkeyed usage is unchanged.
|
|
27
|
+
- **Rendered frames settle faster and more reliably over basemaps.** `whenSettled()` now keys off the basemap's own idle signal (camera done, tiles loaded, fades complete) instead of a polling approximation, and the recording switch takes effect before the first render (previously a startup race could leave label fade-in enabled during a take).
|
|
28
|
+
|
|
11
29
|
## 0.6.19 — 2026-08-26
|
|
12
30
|
|
|
13
31
|
### Fixed
|
package/README.md
CHANGED
|
@@ -147,7 +147,7 @@ Built-in actions wire to picks, widget buttons (`data-emit`), or script (`ctx.em
|
|
|
147
147
|
|
|
148
148
|
**Animation:** camera moves accept a duration — `map.flyTo(coords, zoom, { duration: 1200, curve: true })`, or the `fly-to` action (`center`/`zoom`/`pitch`/`bearing`/`duration`) from any behavior or button; `prefers-reduced-motion` is honored (moves become instant, final state identical). Per-prop GPU transitions via the `transition` attribute: `transition="get-fill-color 800ms"` fades color changes; on a streaming layer, `transition="get-position 300ms"` makes entities glide between updates.
|
|
149
149
|
|
|
150
|
-
**Map stories:** a guided tour as markup — `<om-story>` holds `<om-step>` children that fire the same actions behaviors use, on a timeline (`duration`, `delay`, `parallel`); the built-in `type="player"` widget gives play/pause/scrub, seeking restores the scene's captured initial state, one story is active per map, and grabbing the map pauses playback. Effect verbs — `fade`, `pulse`, `trace` (progressive TripsLayer draw-on; with `feature-id`, a single polygon draws itself on inside its own layer), and `populate` (rows drop in one by one via a GPU filter sweep) — work as step shorthands or plain actions. The story is a sibling that references layers by id — delete it and the map is unchanged. For flybys over 3D tilesets, `warm-tiles` pre-loads the route's tiles in the background before playback, and `paced` goes further: the story steps its own clock and never advances a frame while a tileset is still refining, so no frame ever shows unrefined tiles — wall-clock stretches instead (built for recorded takes; emits `om-paced-tick {t, waitedMs}` per frame, and the two compose — warm first, wait less). `npx @nika-js/onlymap record map.html --out flyby.mp4` turns that guarantee into an actual video: one screenshot per paced frame in headless Chromium (widgets and attribution included), assembled with ffmpeg. Guide: [docs/stories.md](docs/stories.md).
|
|
150
|
+
**Map stories:** a guided tour as markup — `<om-story>` holds `<om-step>` children that fire the same actions behaviors use, on a timeline (`duration`, `delay`, `parallel`); the built-in `type="player"` widget gives play/pause/scrub, seeking restores the scene's captured initial state, one story is active per map, and grabbing the map pauses playback. Effect verbs — `fade`, `pulse`, `trace` (progressive TripsLayer draw-on; with `feature-id`, a single polygon draws itself on inside its own layer), and `populate` (rows drop in one by one via a GPU filter sweep) — work as step shorthands or plain actions. The story is a sibling that references layers by id — delete it and the map is unchanged. For flybys over 3D tilesets, `warm-tiles` pre-loads the route's tiles in the background before playback, and `paced` goes further: the story steps its own clock and never advances a frame while a tileset is still refining, so no frame ever shows unrefined tiles — wall-clock stretches instead (built for recorded takes; emits `om-paced-tick {t, waitedMs}` per frame, and the two compose — warm first, wait less). `npx @nika-js/onlymap record map.html --out flyby.mp4` turns that guarantee into an actual video: one screenshot per paced frame in headless Chromium (widgets and attribution included), assembled with ffmpeg — and effect verbs animate on the story clock, so recorded traces draw on frame by frame exactly as authored. Guide: [docs/stories.md](docs/stories.md).
|
|
151
151
|
|
|
152
152
|
**Classified symbology:** `classify-by="magnitude" classify-scale="jenks" classify-classes="5" classify-ramp="viridis"` computes class breaks *from the data* (quantile, equal-interval, or Jenks natural breaks), styles the layer with a named ramp, and auto-generates the classes legend — no domains or colors to hand-author; an explicit `get-fill-color`/`color` always wins. **Temporal playback:** `<om-widget type="time-slider" layer="…" field="time" duration="20s" window="86400000" format="date">` is a play/pause/scrub control over a layer's time field, driving the same `filter-layer` mechanics as the filter widget (stats stay coherent; `loop` restarts the sweep).
|
|
153
153
|
|
package/dist/actions.d.ts
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The action registry (spec: "Module Breakdown / Behavior Engine" — "Action
|
|
3
|
+
* payload contract"). One event name maps to one action handler with one
|
|
4
|
+
* payload schema, honored identically across all three emit surfaces —
|
|
5
|
+
* `ctx.emit(name, payload)`, `data-emit`, and `<om-behavior>` — an action
|
|
6
|
+
* reads the same keys regardless of how it was triggered. `registerAction`
|
|
7
|
+
* is re-exported from the package entry point (index.ts) as the public
|
|
8
|
+
* `OmMap.registerAction` surface.
|
|
9
|
+
*/
|
|
10
|
+
import { TRACE_TEMP_PREFIX } from "./internal-ids";
|
|
1
11
|
import type { RuntimeCore } from "./runtime-core";
|
|
2
12
|
import type { LayerIR } from "./ir";
|
|
3
13
|
export type ActionHandler = (payload: Record<string, unknown>, mapEl: Element, core: RuntimeCore, layerIRs: ReadonlyMap<string, LayerIR>) => void;
|
|
@@ -9,6 +19,16 @@ export declare function dispatchAction(name: string, payload: Record<string, unk
|
|
|
9
19
|
export { RUNTIME_INTERNAL_PREFIX } from "./internal-ids";
|
|
10
20
|
/** The overlay anchor for a feature: its bbox center for geojson geometry, else its point (flat lon/lat). */
|
|
11
21
|
export declare function featureAnchorPoint(feature: unknown): [number, number] | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Animated-camera payload coercion (spec: "Map Stories / Animation
|
|
24
|
+
* primitives"). Payloads arrive as strings from behavior/step attributes
|
|
25
|
+
* and data-emit, as real values from ctx.emit — coerce both. Durations
|
|
26
|
+
* accept "800", "800ms", or "2s".
|
|
27
|
+
*/
|
|
28
|
+
export declare function cameraOpts(payload: Record<string, unknown>): {
|
|
29
|
+
duration: number;
|
|
30
|
+
curve: boolean;
|
|
31
|
+
};
|
|
12
32
|
/**
|
|
13
33
|
* `trace` — progressive draw. Real tracing needs per-vertex time, which is
|
|
14
34
|
* TripsLayer's whole purpose: sweep `currentTime` across the data's
|
|
@@ -16,6 +36,79 @@ export declare function featureAnchorPoint(feature: unknown): [number, number] |
|
|
|
16
36
|
* back to `fade` with a warning (deck.gl has no dash-offset to fake a
|
|
17
37
|
* draw-on with — documented in the spec).
|
|
18
38
|
*/
|
|
19
|
-
export
|
|
39
|
+
export { TRACE_TEMP_PREFIX };
|
|
40
|
+
export declare function tracedHiddenSet(core: RuntimeCore, layerId: string): Set<string>;
|
|
41
|
+
/** Re-derive the source layer's `data` hide from the current hidden set: nothing hidden clears the hide, else data = rows minus the union. Clears ONLY the data key — a concurrent effect's keys on the same layer (a story-time fade hold, a pulse) must survive the reveal. */
|
|
42
|
+
export declare function applyTraceHide(core: RuntimeCore, ir: LayerIR, rows: readonly unknown[]): void;
|
|
20
43
|
/** Story scrub restore — drop all trace hide bookkeeping for this core (the channel props themselves are cleared separately by cancelAllLayerEffects). */
|
|
21
44
|
export declare function resetTraceHides(core: RuntimeCore): void;
|
|
45
|
+
/**
|
|
46
|
+
* The temp outline layer both trace clocks build (wall-clock traceFeature,
|
|
47
|
+
* story-time EffectTrack): a real runtime-managed <om-layer type="TripsLayer">
|
|
48
|
+
* riding the normal parse → IR → reconcile pipeline.
|
|
49
|
+
*/
|
|
50
|
+
export declare function buildTraceTempElement(mapEl: Element, tempId: string, outline: {
|
|
51
|
+
segments: unknown[];
|
|
52
|
+
total: number;
|
|
53
|
+
}, color: unknown): Element;
|
|
54
|
+
/** Fraction of a per-feature trace slot spent drawing; the rest reveals the real feature and dissolves the outline. */
|
|
55
|
+
export declare const TRACE_DRAW_FRACTION = 0.75;
|
|
56
|
+
/**
|
|
57
|
+
* Target resolution both trace clocks share — the two payload shapes
|
|
58
|
+
* (explicit `{ layer, featureId }`, or the pick-derived `{ feature }` a
|
|
59
|
+
* click behavior supplies; picked objects are FLATTENED by the selection
|
|
60
|
+
* path, so the pick only contributes an id and the real row is always
|
|
61
|
+
* looked up from the layer's own data), the row lookup, the outline, and
|
|
62
|
+
* the per-feature temp-layer id. Null = no traceable outline — callers
|
|
63
|
+
* fall back to fade.
|
|
64
|
+
*/
|
|
65
|
+
export interface TraceTarget {
|
|
66
|
+
featureId: string;
|
|
67
|
+
rows: readonly unknown[];
|
|
68
|
+
outline: {
|
|
69
|
+
segments: unknown[];
|
|
70
|
+
total: number;
|
|
71
|
+
};
|
|
72
|
+
tempId: string;
|
|
73
|
+
/** Columnar data never hides (its rows carry no geometry, so the outline already failed there). */
|
|
74
|
+
canHide: boolean;
|
|
75
|
+
}
|
|
76
|
+
export declare function resolveTraceTarget(payload: Record<string, unknown>, ir: LayerIR): TraceTarget | null;
|
|
77
|
+
/**
|
|
78
|
+
* `populate` (spec: "Effect verbs") — rows drop in one by one, the
|
|
79
|
+
* "populate" effect. Rides the ALWAYS-MOUNTED DataFilterExtension (see
|
|
80
|
+
* attribute-resolution): each frame only moves the filterRange upper bound
|
|
81
|
+
* — a uniform update, zero re-upload, the extension's design purpose.
|
|
82
|
+
* Appearance order:
|
|
83
|
+
* - authored `filter-field`: the sweep runs over the AUTHORED range, so
|
|
84
|
+
* rows appear in filter-dimension order and the end state IS the
|
|
85
|
+
* authored filter — nothing to restore;
|
|
86
|
+
* - payload `field`: a one-shot getFilterValue buffer over that field;
|
|
87
|
+
* - neither: data order (ordinal index accessor).
|
|
88
|
+
* GeoJSON without an authored filter falls back to fade: a live composite
|
|
89
|
+
* does not forward a patched getFilterValue to its sub-layers (the
|
|
90
|
+
* per-feature-trace lesson).
|
|
91
|
+
*/
|
|
92
|
+
/** Everything a populate sweep needs, computed once up front — `null` means "no sweepable dimension; fall back to fade" (both clocks share this). */
|
|
93
|
+
export interface PopulateSweep {
|
|
94
|
+
lo: number;
|
|
95
|
+
hi: number;
|
|
96
|
+
accessorPatch?: Record<string, unknown>;
|
|
97
|
+
/** Authored filter dimensions beyond the swept one — held fixed each frame (see the packed filterRange comment below). */
|
|
98
|
+
otherDimRanges?: [number, number][];
|
|
99
|
+
}
|
|
100
|
+
export declare function preparePopulateSweep(payload: Record<string, unknown>, ir: LayerIR): PopulateSweep | null;
|
|
101
|
+
/**
|
|
102
|
+
* The populate sweep's per-frame patch: the accessor patch (same references
|
|
103
|
+
* every frame — the buffer computes once, keyed by its trigger) plus the
|
|
104
|
+
* swept upper bound. With other authored dimensions present, `filterRange`
|
|
105
|
+
* must be the FULL packed array (deck.gl's own multi-dimension shape) — the
|
|
106
|
+
* swept dimension's range first, matching `ir.filter[0]`'s position, then
|
|
107
|
+
* the rest fixed at their authored ranges.
|
|
108
|
+
*/
|
|
109
|
+
export declare function populateSweepFrame(sweep: PopulateSweep, t01: number): Record<string, unknown>;
|
|
110
|
+
/** Timestamp range of a TripsLayer's data via its own compiled getTimestamps accessor — the trace sweep's domain (shared by both trace clocks). */
|
|
111
|
+
export declare function tripsTimestampRange(ir: LayerIR): {
|
|
112
|
+
t0: number;
|
|
113
|
+
t1: number;
|
|
114
|
+
} | null;
|
|
@@ -206,6 +206,18 @@ export declare const FULL_JS_COLUMNAR_RULE: {
|
|
|
206
206
|
};
|
|
207
207
|
/** Coerce a raw attribute string to a primitive: bare/true/false, JSON array/object, number, or string. */
|
|
208
208
|
export declare function coerceValue(raw: string, hint?: PropDescriptor["type"], attrName?: string): unknown;
|
|
209
|
+
/**
|
|
210
|
+
* Schema defaults must be assigned BY VALUE: several descriptors carry
|
|
211
|
+
* deck's own defaultProps objects (e.g. `extensions: []`), and assigning
|
|
212
|
+
* that array by reference aliases it across EVERY layer of the type — one
|
|
213
|
+
* layer's extension push then mutates deck's class default and leaks into
|
|
214
|
+
* all siblings (found via the atlas demo: a trace temp that verifiably
|
|
215
|
+
* skipped filter wiring still built with a DataFilterExtension, because the
|
|
216
|
+
* defaults pass handed it the type's shared, already-polluted array).
|
|
217
|
+
* Shallow clone is exactly right: entries (extension instances) may share,
|
|
218
|
+
* the CONTAINER must not.
|
|
219
|
+
*/
|
|
220
|
+
export declare function cloneDefault(value: unknown): unknown;
|
|
209
221
|
export interface ResolvedAttributes {
|
|
210
222
|
props: Record<string, unknown>;
|
|
211
223
|
meta: LayerMeta;
|