A local, browser-based viewer for PocketMine-MP / Spigot timings reports
(FormatVersion 3). Drop in a timings .txt and read where your tick time
actually goes — without the endless scrolling of the raw tree dump.
Everything runs client-side. No report ever leaves your machine.
The app is built from ES modules, which browsers won't load directly off the
file system (file:// is blocked for modules). So serve the folder over a tiny
local HTTP server — pick whichever you have:
# Node (no dependencies to install)
node server.js
# then open http://localhost:8000
# …or with npm
npm start
# …or with Python, if you'd rather
python3 -m http.server 8000Then open http://localhost:8000, click Open report (or drag a file onto
the page), and choose your timings .txt. A sample is included at
examples/sample-timings.txt.
- Call tree — the global tick tree, collapsible. Bar width = share of the tick; bar color = self time (where CPU is actually burned, vs. just passed to children). The Share / Avg-per-call / per-tick / Peak columns are heat-colored: cold values stay muted, real costs glow.
- Hotspots — a ranked leaderboard, worst offenders on top. Rank by self time, total time, avg per call, or peak spike (great for finding lag spikes vs. sustained load).
- Flame graph — icicle layout. Width = share of time, color = self time, so the hot frames pop out. Click to zoom, breadcrumb to zoom back out, hover for details.
- Threads — the async worker threads, each with its heaviest timers.
Press / to jump to search. It filters every view and, in the tree, keeps the full ancestor path of each match.
A timings export is a flat list of records grouped under non-indented labels
(Minecraft, Events, plugin names, and Minecraft ThreadId: N for worker
threads). The tree is not the indentation — it's rebuilt from each record's
RecordId / ParentRecordId. All groups before the first Minecraft ThreadId:
share one global record namespace (events and plugin code hang off parents in
the main tick tree); each worker thread is its own namespace. The group label is
kept per-record as the timer's "origin" (shown as the colored tag/edge).
Per-tick, per-call, and peak durations are judged against a 50ms tick budget
(one tick at 20 TPS) to decide how hot they are. If you target a different tick
rate, change LAG_NS in js/heat.js.
tickscope/
├── index.html markup only
├── server.js zero-dependency static server
├── package.json
├── css/
│ └── styles.css
├── js/
│ ├── app.js entry point: loading, tab switching, event wiring
│ ├── parser.js timings format parser + tree builder
│ ├── format.js number/time formatting, escaping, search highlight
│ ├── heat.js heat color scales + tick-budget constant
│ ├── state.js shared app state + origin colors
│ └── views/
│ ├── summary.js
│ ├── legend.js
│ ├── tree.js
│ ├── hotspots.js
│ ├── flame.js
│ └── threads.js
└── examples/
└── sample-timings.txt
MIT — see LICENSE.
0 comments
log in to comment.