Packages & adapters
Kinesis.js ships a tiny core plus opt-in adapters and wrappers. This page covers each package, how to write your own adapter, Web Worker mode, custom styling and performance tuning.
OpenLayers
@kinesisjs/openlayers manages an OpenLayers Feature<Point> per vehicle, with optional fading trails and gap visualisation. It can attach to an existing layer and scope itself to a set of feature ids so it co-exists with the rest of your map.
import { Tracker } from '@kinesisjs/core';
import { OpenLayersAdapter, createVehicleStyle } from '@kinesisjs/openlayers';
const adapter = new OpenLayersAdapter(map, {
style: createVehicleStyle({ icon: '/car.png', iconScale: 0.7 }),
trail: { enabled: true, maxPoints: 80, width: 4, opacity: 0.45 },
warningOpacity: 0.35,
});
const tracker = new Tracker({ adapter, interpolation: 'adaptive' });
tracker.start();Leaflet
@kinesisjs/leaflet manages an L.Marker per vehicle with heading-aware rotation baked into the icon. Remember Leaflet's coordinate order is [lat, lng] — the adapter converts your { lng, lat } positions for you — and import its stylesheet.
Leaflet references window at import time. In an SSR setup, import the Leaflet map component only on the client.
Angular
@kinesisjs/angular exposes a standalone kinesisMap directive plus a kinesisTracker() factory. Inputs accept a Signal or Observable; teardown is automatic via DestroyRef.
@Component({
standalone: true,
imports: [KinesisMapDirective],
template: `<div kinesisMap [positions]="positions" [interpolation]="'adaptive'"
[worker]="true" [trail]="trail" class="map"></div>`,
})
export class LiveMapComponent {
positions = inject(FeedService).positions; // Signal<Position[]>
trail = { enabled: true, maxPoints: 80, width: 4, opacity: 0.45 };
}React, Vue & other frameworks
Because the core is framework-agnostic, you can use it directly from any framework today — construct a Tracker in an effect and dispose it on unmount. Dedicated @kinesisjs/react and @kinesisjs/vue wrappers are on the roadmap for v0.3.
route-aware (OSRM)
@kinesisjs/route-aware is a drop-in CustomInterpolator that snaps positions to the road graph using OSRM. It prefetches polylines, caches them in an LRU, guards against detours, and always falls back to linear — never blocking the tick loop.
import { Tracker } from '@kinesisjs/core';
import { OpenLayersAdapter } from '@kinesisjs/openlayers';
import { OSRMInterpolator } from '@kinesisjs/route-aware';
const tracker = new Tracker({
adapter: new OpenLayersAdapter(map),
interpolation: new OSRMInterpolator({
baseUrl: 'https://your-osrm.example.com', // self-host for production
profile: 'driving',
cacheSize: 500,
maxDetourFactor: 2.5,
}),
});
tracker.start();Web Worker mode
At thousands of vehicles, the tick loop competes with the map's own pan/zoom rendering. Move it off-thread with one flag. The real tracker runs in the worker; the adapter stays on the main thread for DOM/map writes.
const tracker = new Tracker({ adapter, worker: true });
// or point at a hosted worker file:
const hosted = new Tracker({
adapter,
worker: { url: new URL('./kinesis.worker.js', import.meta.url) },
});| Caveat | Detail |
|---|---|
| Custom interpolators | Not supported — functions can't cross the worker boundary. |
| Fade animations | Degrade to snapping (no rAF on the worker). |
getStats() | Lags ~30 ticks behind. |
markCompleted / removeVehicle | Optimistic. |
Custom styling
Pass a style provider — a function of the TrailPoint — to colour or size markers from live data such as speed bands or a per-vehicle meta.color.
const adapter = new OpenLayersAdapter(map, {
style: createVehicleStyle({
speedColorBands: [
{ max: 30, color: '#22c55e' },
{ max: 80, color: '#eab308' },
{ max: 130, color: '#ef4444' },
],
}),
});Performance tuning
- Match
renderLagMsto your feed period. Too low and motion stutters; too high and it lags reality. - Raise
ingestThrottleif a bursty feed sends duplicate positions. - Enable
worker: trueonly for very large fleets — at typical sizes a 0.15 ms tick is already ~1% of the frame budget. - Cap trails with
maxPointsto keep memory flat. - Watch
getStats()—droppedTicksLast60sandtickHistoryP99tell you when to shed work.
Write your own adapter
The contract is small. Implement TrackAdapter — create, update and remove a feature per id, plus teardown — and you have a new map binding.