Deferred Optimizations
Performance optimizations that were considered but intentionally not
implemented, because the complexity they add outweighs their benefit at
the data sizes this fork targets — and the project explicitly values code that
stays readable and understandable at a human level.
Why this file exists: so the trade-offs are
recorded rather than rediscovered. If a real workload outgrows the current
approach, start here. Each entry notes the expected gain, the
complexity cost, and the trigger that would justify doing it.
Rendering & layout
Visible-only / incremental stacking
_recalculateStacking() runs over every item on each pan/zoom
(~8ms at 10k items, measured in the test suite). It could instead stack only
items overlapping the viewport, and cache row assignments so a pan that reveals
new items appends rather than recomputes.
Gain: High at 100k+ items ·
Cost: High — invalidation logic, edge cases around
fixed group heights, and the "stable rows during drag" guarantee all get
harder. Trigger: continuous pan drops below 60fps on the real
dataset. Mitigated already: stacking no longer runs per-frame during a
drag (rows are frozen until drop).
Spatial index for hit-testing & culling
Hit-testing and
_updateVisibleItems() are linear scans over all
items. An interval tree or a bucketed index keyed by time would make both
O(log n + k). Items are already sorted by
start, so a binary search
plus a "max end so far" augmentation would get most of the win cheaply.
Gain: Medium ·
Cost: Medium — an index to keep in sync on every
add/update/remove/edit. Trigger: hover/click latency becomes
noticeable, or visible-set computation dominates a frame.
Layer caching for static canvases
The axis, group-label panel, and minimap are redrawn on every frame even when
only the body changed (e.g. item hover). They could be cached to offscreen
canvases and only repainted when their inputs change (window, groups, theme,
yOffset).
Gain: Medium on hover-heavy use ·
Cost: Medium — dirty-flag bookkeeping per layer.
Trigger: profiling shows label/axis/minimap repaint is a
meaningful share of frame time.
Dirty-rectangle / partial redraw
Today every frame clears and repaints the whole body. Tracking dirty regions
(only the rows/columns that changed) would cut fill cost on large canvases.
Gain: Medium ·
Cost: High — bookkeeping touches every draw path and
is a classic source of "ghost" artifacts. Trigger: very large
canvases (4K, tall timelines) where clear+repaint is itself expensive.
Glyph / text atlas for item labels
Item text is drawn with
fillText each frame (widths are cached, the
raster is not). Pre-rendering labels to an offscreen atlas and blitting would
help when thousands of items are on screen with stable text.
Gain: Medium at high visible
counts · Cost: High — atlas allocation/eviction,
DPR and font-change invalidation, and it largely duplicates what the browser
already caches. Trigger: text fill shows up hot in a profile
with many visible items.
Concurrency & scheduling
Stacking in a Web Worker
Move
_recalculateStacking /
_computeFixedGroupHeights
off the main thread for very large datasets.
Gain: Medium (keeps the main thread
free) · Cost: High — serialization, async layout,
and races with live edits. Trigger: layout work alone exceeds a
frame budget and cannot be reduced by visible-only stacking first.
rAF-aligned follow-now
Follow-now uses a 1s
setInterval. A
requestAnimationFrame
loop would be smoother and naturally pause with the tab.
Gain: Low ·
Cost: Low — but unnecessary today. Already mitigated:
the tick is skipped while document.hidden. Trigger:
sub-second follow smoothness is required.
Correctness-adjacent (complexity, not just speed)
Calendar-aware / DST-correct axis stepping
Grid ticks step by fixed millisecond intervals, so DST transitions and
month/year boundaries can land slightly off a clean local label. Proper stepping
walks a calendar (variable-length months, DST-aware day boundaries).
Gain: Low (cosmetic for this use
case) · Cost: Medium — calendar math is fiddly.
Trigger: labels near DST/month boundaries are visibly wrong for
the audience.
← Risks & go/no-go ·
Future ideas → · Demos