@nickpaustian/telemetry
v0.1.0
Published
An on-screen panel of live debug widgets: values, scrolling graphs and 2D plots, with an FPS binding, for watching what an app is doing while it runs
Maintainers
Readme
@nickpaustian/telemetry
An on-screen panel of live debug widgets, for watching what an app is doing while it runs: a value, a scrolling graph of a number over time, a 2D value on a grid, and groups of those. A HUD in a corner by default, or an overlay across the page. No dependencies.
import { Telemetry, Graph, Value, Cartesian, Group, bindFps, bind } from "@nickpaustian/telemetry"
const hud = new Telemetry({ hotkey: "F8" })
const fps = hud.add(new Graph("fps", { label: "FPS", min: 0 }))
const stick = hud.add(new Cartesian("stick", { label: "stick" }))
hud.add(new Value("entities", { label: "entities" }))
bindFps(fps)
bind(hud.get("entities")!, () => world.count)
function frame() {
stick.update({ x: input.x, y: input.y })
hud.data.entities = world.count // the same as the bind above
}The panel
new Telemetry(options) appends the panel to body or parent.
| option | default | |
|---|---|---|
| mode | hud | hud sits in a corner; overlay covers the parent with a dimmed, blurred sheet |
| corner | top-left | for hud |
| hotkey | none | a KeyboardEvent.key that toggles it, ignored while typing in a field |
| visible | true | |
| parent | body | an element or selector |
add(widget) returns the widget; get(id) finds one, inside groups too; set(id, values) updates one; remove(id), show(), hide(), toggle(), visible, dispose(). data is a proxy: hud.data.fps = 60 sets widget fps's value, hud.data.stick.x = 1 a field.
Widgets
Every widget has an id, an element, data (a live object: assign a field and the widget redraws), update(partial), current (the data, read-only) and dispose(). Options always take a label.
Value:label: valueon one line. Optionsformat(value)andunit; null shows as "—".Graph: a number over time. Samples are averaged into points (samplesPerPoint, default 20) so a per-frame value reads as a trend,points(8) are kept across the graph, the newest is smoothed and marked with ashape, a dashed line shows the average overhistoryLength(200) samples, and the range follows the data:min(0, or"auto") andmax("auto", rising to the highest point and easing down after).widthandheightare CSS pixels (75); the canvas draws at the device's pixel ratio.seriesandrangeare readable.Cartesian:{ x, y }as a point on a grid with axes.rangeis one[min, max]for both axes or{ x, y };gridis the line spacing in value units (0.25).Group: widgets together under one label, in aroworcolumn;add,get,remove,widgets.
A widget of your own extends Widget<Options, Data>: build the DOM in create() and react in onChange(key, value).
Bindings
bindFps(widget, { window })counts frames and writes the rate averaged overwindowms (500) to the widget's value.bind(widget, read, { every })writesread()to the widget's value each frame, or every so many ms.
Both return a function that stops them.
Drawing
History (a window of numbers by count or age, with average, min, max, latest), makeCanvas (sized in CSS pixels, drawing at the pixel ratio), drawShape and the shapes, and lerpColour are exported for widgets of your own.
Styling
Styles are injected once. The panel is .telemetry with .telemetry-hud or .telemetry-overlay and a corner class; widgets are .telemetry-widget with a class per kind (.telemetry-graph-widget and so on), .telemetry-label and .telemetry-value. The panel does not take pointer events, so it never gets in the way; set pointer-events on its element if you want it clickable.
