Three surfaces show "how much of this type is on screen": the Overview
tab's hero cards (templates/overview.ts), their incremental patcher
(tabs/overview.ts), and the collapsed monitor's compact badge
(data-loading-monitor.ts). Each used to hard-code its own list of three
types with its own presence test and its own label strings, which is how
mesh came to be missing from all three at once while the counts it needed
were already being aggregated: visibleByType.mesh was pushed every update
cycle by monitor/visible-counts.ts and then dropped on the floor.
Record<GeometryTypeName, …> makes adding a geometry type a compile error
here rather than a silent omission in three places, and every consumer reads
labels, DOM field ids, unit nouns and presence from this one table — so a
card, its patch target and its badge entry cannot disagree.
The per-geometry headline counts, in one table.
Three surfaces show "how much of this type is on screen": the Overview tab's hero cards (
templates/overview.ts), their incremental patcher (tabs/overview.ts), and the collapsed monitor's compact badge (data-loading-monitor.ts). Each used to hard-code its own list of three types with its own presence test and its own label strings, which is how mesh came to be missing from all three at once while the counts it needed were already being aggregated:visibleByType.meshwas pushed every update cycle bymonitor/visible-counts.tsand then dropped on the floor.Record<GeometryTypeName, …>makes adding a geometry type a compile error here rather than a silent omission in three places, and every consumer reads labels, DOM field ids, unit nouns and presence from this one table — so a card, its patch target and its badge entry cannot disagree.