Field benchmark: three browsers
This page measures a Temporeum timeline and a Temporeum Gantt chart in Chromium, Firefox and WebKit, on the same data, in the same box, with the same real input. Every number on this page, the list of what goes over the frame budget included, is generated from one file, site/benchmark/field/results.json, which one script run writes; the release check rebuilds the page and reads every number back from that file. No number on this page is typed by hand.
It measures this library only. Each page answers the script through a small contract, described at the top of packages/docs/bench/field/kit.js, so a page built the same way for another library can be measured with the same data and the same input.
What is measured
- First render. From navigation until the items are on screen and the drawing has stopped changing.
- Pan. Missed frames and the slowest frames while the view is moved along time, the way each chart moves: a mouse drag for the timeline, a horizontal wheel for the Gantt chart, which scrolls.
- Zoom. The same while zooming with
Controland the wheel. - Size of the page. Elements in the box after load, item nodes, and how many items are on screen.
- Memory. The JavaScript heap after load and after the pan, in Chromium, the one browser that reports it.
- Bytes. The JavaScript each page loaded for the library, minified and gzipped.
Method
Each workload runs on a page of its own, with the defaults and editing on, as users ship it. The timeline workload is items in interleaved streams across groups; the Gantt workload is one task per row, chained in runs. The run is not blind: it fails, and writes no results, if a page shows too few items, if a pan does not move the view and bring it back, if a zoom does not zoom and come back, if a pan or a zoom edits an item, or if a page throws.
There is no CPU slowdown in this run: only Chromium has one, and the point here is to measure the three browsers like for like. The slowed-down measurement, in Chromium, is the benchmark.
| Measured | 2026-11-07T17:48:23.144Z |
|---|---|
| CPU | Apple M4, 10 cores, 17 GB |
| OS | Darwin Kernel Version 25.6.0: Fri Jul 31 19:11:03 PDT 2026; root:xnu-12377.161.14~5/RELEASE_ARM64_T8132 (darwin 25.6.0 arm64) |
| Browsers | chromium 156.0.8078.4, firefox 157.0, webkit 27.2 |
| CPU slowdown | none, in every browser |
| Viewport | 1440 × 900 CSS pixels, device pixel ratio 1 |
| Repetitions | 3 fresh pages per workload, size, scenario and browser |
| Sizes | timeline: 1000 and 10000; gantt: 500 and 2000 |
| First render | navigationStart -> the rAF at which item nodes are in the box AND visible, and two consecutive rAFs have seen no DOM mutation in it |
| Pan | 24 strokes of 240 px, 12 towards later time and back, each 400 ms with 100 ms between; the chart's own: drag (mouse down, move, up) or wheel-x (horizontal wheel steps), as the page says. How each chart pans: timeline drag, gantt wheel-x. |
| Zoom | 8 notches in and 8 out, 50 ms apart; Control held + mouse wheel at the chart's centre, the page's |deltaY| per notch in and out: one 1.2x step. |
| Missed frame | V = 1000/60 ms. An rAF interval d > 1.5 V counts round(d / V) - 1 lost frames. missed % = lost frames / (lost frames + recorded rAF intervals) x 100, over the whole recording window. |
| Heap | Chromium only: CDP HeapProfiler.collectGarbage, then Performance.getMetrics JSHeapUsedSize |
| Over the budget | A pan or a zoom whose median misses more than 5% of its frames. |
| Run | 735 s, Temporeum 1.0.0 |
Reproduce:
npm run bench:field -w @temporeum/timeline-docsIt builds the library, serves every page from its own server, runs the three browsers, writes the results, and checks them.
Results
Timeline
| Metric | Items | Unit | chromium 156.0.8078.4 | firefox 157.0 | webkit 27.2 |
|---|---|---|---|---|---|
| First render | 1000 | ms | 71.4 (70.3–111) | 84.0 (69.0–171) | 64.5 (51.0–128) |
| Elements after load | 1000 | elements | 871 (871–871) | 871 (871–871) | 871 (871–871) |
| Item nodes after load | 1000 | nodes | 203 (203–203) | 203 (203–203) | 203 (203–203) |
| Items visible after load | 1000 | items | 197 (197–197) | 197 (197–197) | 197 (197–197) |
| Pan: missed frames | 1000 | % | 0.00 (0.00–0.13) | 0.00 (0.00–0.00) | 0.21 (0.00–0.21) |
| Pan: 95th percentile frame | 1000 | ms | 16.8 (16.7–16.8) | 16.7 (16.7–16.7) | 15.0 (15.0–15.0) |
| Zoom: missed frames | 1000 | % | 0.00 (0.00–0.00) | 0.00 (0.00–0.00) | 0.00 (0.00–0.00) |
| Zoom: 95th percentile frame | 1000 | ms | 16.7 (16.7–16.8) | 16.7 (16.7–17.1) | 17.0 (17.0–17.0) |
| Zoom: peak reached | 1000 | x | 4.30 (4.30–4.30) | 3.58 (3.58–3.58) | 3.53 (3.53–3.53) |
| Heap after load | 1000 | MB | 2.67 (2.67–2.68) | — | — |
| Heap after the pan | 1000 | MB | 4.06 (4.06–4.08) | — | — |
| First render | 10000 | ms | 88.1 (86.6–106) | 116 (108–121) | 97.5 (92.0–105) |
| Elements after load | 10000 | elements | 3340 (3340–3340) | 3340 (3340–3340) | 3340 (3340–3340) |
| Item nodes after load | 10000 | nodes | 1629 (1629–1629) | 1629 (1629–1629) | 1629 (1629–1629) |
| Items visible after load | 10000 | items | 1577 (1577–1577) | 1578 (1578–1578) | 1577 (1577–1577) |
| Pan: missed frames | 10000 | % | 0.00 (0.00–0.13) | 0.00 (0.00–0.12) | 0.00 (0.00–0.00) |
| Pan: 95th percentile frame | 10000 | ms | 16.8 (16.7–16.8) | 16.7 (16.7–16.7) | 16.0 (15.0–16.0) |
| Zoom: missed frames | 10000 | % | 0.00 (0.00–1.56) | 0.00 (0.00–0.00) | 0.00 (0.00–0.00) |
| Zoom: 95th percentile frame | 10000 | ms | 16.7 (16.7–16.8) | 16.7 (16.7–16.7) | 16.0 (15.0–16.0) |
| Zoom: peak reached | 10000 | x | 4.30 (4.30–4.30) | 3.58 (3.58–3.58) | 3.53 (3.53–3.53) |
| Heap after load | 10000 | MB | 6.73 (6.72–6.73) | — | — |
| Heap after the pan | 10000 | MB | 11.2 (11.2–11.2) | — | — |
Gantt chart
| Metric | Items | Unit | chromium 156.0.8078.4 | firefox 157.0 | webkit 27.2 |
|---|---|---|---|---|---|
| First render | 500 | ms | 71.6 (71.4–72.1) | 75.0 (71.0–94.0) | 55.5 (52.0–64.0) |
| Elements after load | 500 | elements | 166 (166–166) | 166 (166–166) | 166 (166–166) |
| Item nodes after load | 500 | nodes | 13.0 (13.0–13.0) | 13.0 (13.0–13.0) | 13.0 (13.0–13.0) |
| Items visible after load | 500 | items | 13.0 (13.0–13.0) | 13.0 (13.0–13.0) | 13.0 (13.0–13.0) |
| Pan: missed frames | 500 | % | 0.00 (0.00–0.00) | 0.00 (0.00–0.08) | 0.00 (0.00–0.00) |
| Pan: 95th percentile frame | 500 | ms | 16.7 (16.7–16.8) | 16.7 (16.7–16.7) | 15.0 (15.0–15.0) |
| Zoom: missed frames | 500 | % | 0.00 (0.00–0.00) | 0.00 (0.00–0.00) | 0.00 (0.00–0.00) |
| Zoom: 95th percentile frame | 500 | ms | 16.8 (16.7–16.8) | 16.7 (16.7–16.8) | 15.0 (15.0–15.0) |
| Zoom: peak reached | 500 | x | 4.30 (4.30–4.30) | 3.58 (3.58–3.58) | 3.53 (3.53–3.53) |
| Heap after load | 500 | MB | 2.52 (2.52–2.53) | — | — |
| Heap after the pan | 500 | MB | 3.45 (3.45–3.45) | — | — |
| First render | 2000 | ms | 71.5 (70.1–72.7) | 76.0 (74.0–80.0) | 55.5 (51.0–62.0) |
| Elements after load | 2000 | elements | 166 (166–166) | 166 (166–166) | 166 (166–166) |
| Item nodes after load | 2000 | nodes | 13.0 (13.0–13.0) | 13.0 (13.0–13.0) | 13.0 (13.0–13.0) |
| Items visible after load | 2000 | items | 13.0 (13.0–13.0) | 13.0 (13.0–13.0) | 13.0 (13.0–13.0) |
| Pan: missed frames | 2000 | % | 0.00 (0.00–0.00) | 0.00 (0.00–0.00) | 0.00 (0.00–0.00) |
| Pan: 95th percentile frame | 2000 | ms | 16.8 (16.7–16.8) | 16.7 (16.7–16.7) | 15.0 (15.0–15.0) |
| Zoom: missed frames | 2000 | % | 0.00 (0.00–0.00) | 0.00 (0.00–0.00) | 0.00 (0.00–0.00) |
| Zoom: 95th percentile frame | 2000 | ms | 16.7 (16.7–16.7) | 16.7 (16.7–16.8) | 15.0 (15.0–15.0) |
| Zoom: peak reached | 2000 | x | 4.30 (4.30–4.30) | 3.58 (3.58–3.58) | 3.53 (3.53–3.53) |
| Heap after load | 2000 | MB | 3.36 (3.36–3.36) | — | — |
| Heap after the pan | 2000 | MB | 4.28 (4.28–4.46) | — | — |
Bytes
| Page | Metric | Size |
|---|---|---|
| Timeline | JavaScript, minified | 164 kB |
| Timeline | JavaScript, minified and gzipped | 58.4 kB |
| Gantt chart | JavaScript, minified | 184 kB |
| Gantt chart | JavaScript, minified and gzipped | 66.3 kB |
Over the frame budget
Generated from the results: every pan and zoom — the same workload, size and browser — whose median misses more frames than the budget the performance guide sets.
None of the 24 pans and zooms misses more than 5% of its frames.
What this measurement does not cover
- A slowed-down CPU, a real phone, touch. Every browser runs on the same desktop machine at full speed; the charts are dragged with a mouse, and nothing is pinched.
- Features. The pages show a plain timeline with groups and a Gantt chart with dependencies; the other plugins are not loaded.
- Editing, data changes, long sessions, bundled builds. No item is dragged; nothing is added or removed; the heap is read once after a pan; the library is measured as the files a no-build page loads.