Getting started
Quickstart
Create an engine, add data and mount a chart, with a script tag or with npm and React.
Without a license key everything works and each chart shows a small “Powered by Kymoscope” badge; add your key when you have one, as licenseKey, or pass license.get to fetch fresh keys from your backend (see Automatic renewal).
Script tag
Serve kymoscope-embed.js, its assets/ folder and styles/charts.css (see Installation). React is bundled inside the script; your page does not need it.
<link rel="stylesheet" href="/vendor/kymoscope/styles/charts.css" />
<div id="chart" style="height: 360px"></div>
<script src="/vendor/kymoscope/kymoscope-embed.js"></script>
<script>
const engine = Kymoscope.createEngine({ licenseKey: window.KYMOSCOPE_LICENSE_KEY })
// 1. Data: numeric columns of equal length.
const n = 2000
const t = new Float64Array(n), rpm = new Float64Array(n)
for (let i = 0; i < n; i++) {
t[i] = i * 0.05
rpm[i] = 6000 + 2500 * Math.sin(t[i] / 1.3)
}
engine.datasets.addColumns({ name: 'Run 42', columns: { t, rpm }, units: { t: 's', rpm: '1/min' } })
// 2. A chart model in the active worksheet, with one series.
const chartId = engine.charts.add('multiband', { title: 'RPM' })
engine.charts.addSeries(chartId, 'rpm')
// 3. A view of that chart in your element. It fills the element.
const view = engine.charts.mount(chartId, document.getElementById('chart'))
</script>The first numeric column (t) became the worksheet’s X axis. The chart has no toolbar or menu: the mouse wheel zooms it, and everything else (reset zoom, add a series, export) comes from your own buttons calling the engine.
npm and React
import { useEffect, useState } from 'react'
import { createEngine, type KymoscopeEngine } from '@kymoscope/sdk'
import { Chart, KymoscopeProvider, useEngineState } from '@kymoscope/sdk/react'
import '@kymoscope/sdk/styles/charts.css'
export function Analysis({ run }: { run: { name: string; t: number[]; rpm: number[] } }) {
const [engine, setEngine] = useState<KymoscopeEngine | null>(null)
useEffect(() => {
const e = createEngine({ licenseKey: import.meta.env.VITE_KYMOSCOPE_LICENSE_KEY })
e.datasets.addColumns({ name: run.name, columns: { t: run.t, rpm: run.rpm } })
void e.charts.addSeries(e.charts.add('multiband'), 'rpm')
setEngine(e)
return () => e.dispose()
}, [run])
if (!engine) return null
return (
<KymoscopeProvider engine={engine}>
<Charts />
</KymoscopeProvider>
)
}
function Charts() {
const charts = useEngineState((s) => s.worksheets.find((w) => w.id === s.activeWorksheetId)!.charts)
return charts.map((c) => <Chart key={c.id} id={c.id} style={{ height: 320 }} />)
}Creating the engine in an effect gives React StrictMode’s second mount a fresh engine and disposes the first. See React bindings.
Push a live signal
A local stream is fed by your page: no server and no encryption involved. It is plotted as soon as it opens.
const live = engine.live.openLocal('Rig A')
let t = 0
setInterval(() => {
t += 1 / 30
live.push({ t, signals: [{ name: 'load', unit: 'kN', value: 5 + 3 * Math.sin(t) }] })
}, 1000 / 30)For data coming from devices, see Live streams.
Save what users build
// Worksheets and chart settings as JSON (datasets are not included).
engine.subscribe(debounce(() => {
const { json } = engine.io.exportWorkspace()
fetch('/api/workspaces/42', { method: 'PUT', body: JSON.stringify(json) })
}, 500))
// Later, in a new engine:
await engine.io.importWorkspace(await (await fetch('/api/workspaces/42')).json())subscribe fires once per effective state change; debounce it yourself. See Import and export.