@zkmake/three-meter 0.9.1 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -22,19 +22,19 @@ load the scene up past the demo's triangle budget.
22
22
  <tr>
23
23
  <th>Dark</th>
24
24
  <td valign="top">
25
- <img src="https://raw.githubusercontent.com/zkmake/three-meter/main/docs/hud-full.png" width="318" alt="The HUD in full mode, dark theme. Option rows for theme (light, system, dark), explain metrics and a copy-report button; FPS, CPU and GPU sparklines with live values, the FPS graph showing a dashed budget line; then one row per metric, each with an icon, its value and a checkbox choosing whether the compact card shows it (FPS, calls, CPU, GPU, 1% low, frame p99, hitches, triangles, lines, points, render passes, geometries, textures, shaders), with the triangle count in amber for being over its budget; a top costs toggle; and a footer with the three-meter version, the three revision, a WebGL2 backend badge and the GPU name. Three discs beside it: a drag grip, the compact/full toggle and dim on leave." />
25
+ <img src="https://raw.githubusercontent.com/zkmake/three-kit/main/docs/hud-full.png" width="318" alt="The HUD in full mode, dark theme. Option rows for theme (light, system, dark), explain metrics and a copy-report button; FPS, CPU and GPU sparklines with live values, the FPS graph showing a dashed budget line; then one row per metric, each with an icon, its value and a checkbox choosing whether the compact card shows it (FPS, calls, CPU, GPU, 1% low, frame p99, hitches, triangles, lines, points, render passes, geometries, textures, shaders), with the triangle count in amber for being over its budget; a top costs toggle; and a footer with the three-meter version, the three revision, a WebGL2 backend badge and the GPU name. Three discs beside it: a drag grip, the compact/full toggle and dim on leave." />
26
26
  </td>
27
27
  <td valign="top">
28
- <img src="https://raw.githubusercontent.com/zkmake/three-meter/main/docs/hud-compact.png" width="314" alt="The HUD collapsed, dark theme: FPS and GPU sparklines with a dashed budget line on the FPS graph, a two-column grid of metrics with icons (FPS, calls, CPU, GPU, 1% low, frame p99, triangles in amber for being over budget, geometries, textures, shaders), and the footer with versions, backend and GPU. Three discs beside it: drag, expand and dim on leave." />
28
+ <img src="https://raw.githubusercontent.com/zkmake/three-kit/main/docs/hud-compact.png" width="314" alt="The HUD collapsed, dark theme: FPS and GPU sparklines with a dashed budget line on the FPS graph, a two-column grid of metrics with icons (FPS, calls, CPU, GPU, 1% low, frame p99, triangles in amber for being over budget, geometries, textures, shaders), and the footer with versions, backend and GPU. Three discs beside it: drag, expand and dim on leave." />
29
29
  </td>
30
30
  </tr>
31
31
  <tr>
32
32
  <th>Light</th>
33
33
  <td valign="top">
34
- <img src="https://raw.githubusercontent.com/zkmake/three-meter/main/docs/hud-full-light.png" width="318" alt="The HUD in full mode, light theme. Option rows for theme (light, system, dark), explain metrics and a copy-report button; FPS, CPU and GPU sparklines with live values, the FPS graph showing a dashed budget line; then one row per metric, each with an icon, its value and a checkbox choosing whether the compact card shows it (FPS, calls, CPU, GPU, 1% low, frame p99, hitches, triangles, lines, points, render passes, geometries, textures, shaders), with the triangle count in amber for being over its budget; a top costs toggle; and a footer with the three-meter version, the three revision, a WebGL2 backend badge and the GPU name. Three discs beside it: a drag grip, the compact/full toggle and dim on leave." />
34
+ <img src="https://raw.githubusercontent.com/zkmake/three-kit/main/docs/hud-full-light.png" width="318" alt="The HUD in full mode, light theme. Option rows for theme (light, system, dark), explain metrics and a copy-report button; FPS, CPU and GPU sparklines with live values, the FPS graph showing a dashed budget line; then one row per metric, each with an icon, its value and a checkbox choosing whether the compact card shows it (FPS, calls, CPU, GPU, 1% low, frame p99, hitches, triangles, lines, points, render passes, geometries, textures, shaders), with the triangle count in amber for being over its budget; a top costs toggle; and a footer with the three-meter version, the three revision, a WebGL2 backend badge and the GPU name. Three discs beside it: a drag grip, the compact/full toggle and dim on leave." />
35
35
  </td>
36
36
  <td valign="top">
37
- <img src="https://raw.githubusercontent.com/zkmake/three-meter/main/docs/hud-compact-light.png" width="314" alt="The HUD collapsed, light theme: FPS and GPU sparklines with a dashed budget line on the FPS graph, a two-column grid of metrics with icons (FPS, calls, CPU, GPU, 1% low, frame p99, triangles in amber for being over budget, geometries, textures, shaders), and the footer with versions, backend and GPU. Three discs beside it: drag, expand and dim on leave." />
37
+ <img src="https://raw.githubusercontent.com/zkmake/three-kit/main/docs/hud-compact-light.png" width="314" alt="The HUD collapsed, light theme: FPS and GPU sparklines with a dashed budget line on the FPS graph, a two-column grid of metrics with icons (FPS, calls, CPU, GPU, 1% low, frame p99, triangles in amber for being over budget, geometries, textures, shaders), and the footer with versions, backend and GPU. Three discs beside it: drag, expand and dim on leave." />
38
38
  </td>
39
39
  </tr>
40
40
  </table>
@@ -142,18 +142,30 @@ second, like a hidden tab, are left out. Read them with `monitor.getFrameStats()
142
142
 
143
143
  ```ts
144
144
  monitor.getFrameStats();
145
- // { frames: 1000, lowFps: 97.6, p99Ms: 10.2, hitches: 3 }
145
+ // { frames: 1000, lowFps: 97.6, p99Ms: 10.2, hitches: 3, refreshHz: 120 }
146
146
  ```
147
147
 
148
+ ## Refresh rate and headroom
149
+
150
+ **Refresh** is the rate the loop runs at when it keeps up: the display's refresh rate, or the app's
151
+ own cap if it throttles itself. It comes from the fastest tenth of recent frames, with each interval
152
+ averaged against the next so a late frame and the early one after it don't read as a faster display,
153
+ then snapped to a common rate (60, 120, 144, …). It needs 60 frames.
154
+
155
+ **Headroom** is the spare time in each frame: the frame budget minus whichever of CPU and GPU took
156
+ longer. At 120 Hz with 3 ms of GPU work that's 5.3 ms. Below zero, frames miss the display's refresh,
157
+ and the row turns amber.
158
+
148
159
  ## Budgets
149
160
 
150
161
  A value past its budget turns amber in the full view and the compact HUD, and its tooltip names the
151
162
  budget. The FPS, CPU and GPU graphs draw the budget as a dashed line once the series reaches it; the
152
163
  scale never stretches to fit it, so a quiet graph keeps its detail.
153
164
 
154
- Timing budgets come from `targetFps` (60 by default): FPS at least 95% of it, 1% low at least half,
155
- CPU and GPU within one frame (16.7 ms), frame p99 within one and a half. Counts have no default,
156
- since what's reasonable depends on the scene. Set your own:
165
+ Timing budgets come from `targetFps`: FPS at least 95% of it, 1% low at least half, CPU and GPU
166
+ within one frame, frame p99 within one and a half, headroom at least zero. Leave `targetFps` out and
167
+ they follow the detected refresh rate, so a 120 Hz display gets 8.3 ms budgets (60 until it's
168
+ detected). Counts have no default, since what's reasonable depends on the scene. Set your own:
157
169
 
158
170
  ```ts
159
171
  mountPerfHud(monitor, { budgets: { targetFps: 120, calls: 500, triangles: 2_000_000 } });
@@ -166,7 +178,7 @@ hud.setBudgets({ gpu: null }); // null drops a default; false drops them all
166
178
 
167
179
  The HUD tells you there are 400 draw calls; **top costs** tells you which objects they come from.
168
180
  Tick it in the full view for the five biggest costs in the main render pass, grouped by **meshes** or
169
- **materials**, sorted by draw calls or triangles. Click a row to log its three objects to the
181
+ **materials**, sorted by draw calls or triangles. Click a row's name to log its three objects to the
170
182
  console.
171
183
 
172
184
  ```text
@@ -186,9 +198,18 @@ walks the scene only while open, twice a second.
186
198
 
187
199
  ```ts
188
200
  monitor.getSceneCost();
189
- // { calls: 309, triangles: 57548, meshes: [{ label: "tree", calls: 300, … }, …], materials: […] }
201
+ // { calls: 309, triangles: 57548, meshes: [{ key: "mesh:tree…", label: "tree", calls: 300, … }, …], materials: […] }
190
202
  ```
191
203
 
204
+ ### Test a cost by hiding it
205
+
206
+ Calls and triangles aren't time. The eye on each row hides its objects, every copy in the scene
207
+ including ones off screen, and the row then shows what that saved: GPU time averaged over 30 frames
208
+ before and after hiding (CPU time where there's no GPU timer), like `−4.3 ms GPU`. Hidden rows stay
209
+ listed so you can show them again. Everything comes back when you untick top costs or the HUD is
210
+ disposed, and objects that were already invisible stay that way. `monitor.getObjectsForKey(key)`
211
+ returns the same objects for a row's `key`.
212
+
192
213
  ## Bug reports
193
214
 
194
215
  The **report** row's copy button puts a Markdown snapshot on the clipboard: versions, backend, GPU,
@@ -196,9 +217,9 @@ the current metrics, the stutter stats, the top three meshes, the viewport and t
196
217
  `formatReport(monitor)` from `@zkmake/three-meter/ui` returns the same text.
197
218
 
198
219
  ```text
199
- three-meter v0.7.0 · three r186 · WebGL2 · Apple M4 Max
220
+ three-meter v0.10.0 · three r186 · WebGL2 · Apple M4 Max
200
221
  FPS 120 · 1% low 98 · p99 10.2 ms · hitches 3 / 1,000 frames
201
- CPU 0.2 ms · GPU 0.7 ms
222
+ CPU 0.2 ms · GPU 0.7 ms · refresh 120 Hz · headroom 7.6 ms
202
223
  Calls 1 · passes 1 · triangles 24,000 · lines 0 · points 0
203
224
  Geometries 1 · textures 1 · shaders 1
204
225
  Top: tree ×300 (300 calls, 9,600 tris) · house (6 calls, 12 tris) · dome (2 calls, 7,936 tris)
@@ -258,13 +279,13 @@ palette, override the `--perf-*` custom properties (`bg`, `fg`, `fg-dim`, `muted
258
279
 
259
280
  ## Examples
260
281
 
261
- [`examples/site`](examples/site) is what runs at [three-meter.pages.dev](https://three-meter.pages.dev/):
282
+ [`apps/three-meter-site`](https://github.com/zkmake/three-kit/tree/main/apps/three-meter-site) is what runs at [three-meter.pages.dev](https://three-meter.pages.dev/):
262
283
  one Vite app with both integrations of the same scene, swapped from the header.
263
- [`src/demos/vanilla.ts`](examples/site/src/demos/vanilla.ts) is plain three with `mountPerfHud`;
264
- [`src/demos/r3f.tsx`](examples/site/src/demos/r3f.tsx) is React Three Fiber with `PerfSampler` and
284
+ [`src/demos/vanilla.ts`](https://github.com/zkmake/three-kit/blob/main/apps/three-meter-site/src/demos/vanilla.ts) is plain three with `mountPerfHud`;
285
+ [`src/demos/r3f.tsx`](https://github.com/zkmake/three-kit/blob/main/apps/three-meter-site/src/demos/r3f.tsx) is React Three Fiber with `PerfSampler` and
265
286
  `PerfHud`. Both set a 250K triangle budget on top of the timing defaults. `?r3f` opens on Fiber,
266
287
  `?webgpu` uses `WebGPURenderer` in either, `?count=` scales the scene. The header's theme toggle sets the page theme and the HUD's `theme` layer together; the row
267
- inside the panel overrides the HUD alone. Run `bun run dev` inside it.
288
+ inside the panel overrides the HUD alone. Run `bun run dev` inside it after a `bun install` at the repo root.
268
289
 
269
290
  ## Shipping it
270
291
 
@@ -282,7 +303,7 @@ custom properties on `.perf-hud` and `.perf-monitor`, or the `theme` option.
282
303
 
283
304
  ## Contributing
284
305
 
285
- See [CONTRIBUTING.md](CONTRIBUTING.md). Changes ship with a changeset.
306
+ See [CONTRIBUTING.md](https://github.com/zkmake/three-kit/blob/main/CONTRIBUTING.md). Changes ship with a changeset.
286
307
 
287
308
  ## License
288
309
 
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as GpuTiming, c as RenderBackend, d as Sample, f as SceneCost, i as FrameStats, l as RenderCounts, n as CostEntry, o as PerfRenderer, p as TimingMetric, r as Environment, s as PerformanceMonitorOptions, t as PerformanceMonitor, u as ResourceCounts } from "./performance-monitor-DgHxeQ2X.js";
1
+ import { a as GpuTiming, c as RenderBackend, d as Sample, f as SceneCost, i as FrameStats, l as RenderCounts, n as CostEntry, o as PerfRenderer, p as TimingMetric, r as Environment, s as PerformanceMonitorOptions, t as PerformanceMonitor, u as ResourceCounts } from "./performance-monitor-BoY_-GTt.js";
2
2
  //#region src/core/ring-buffer.d.ts
3
3
  /**
4
4
  * Fixed-capacity numeric ring buffer. Backs the per-frame timing history the
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { n as RingBuffer, t as PerformanceMonitor } from "./performance-monitor-DsBp13ts.js";
1
+ import { n as RingBuffer, t as PerformanceMonitor } from "./performance-monitor-BqnoiLEs.js";
2
2
  //#region src/core/wrap-animation-loop.ts
3
3
  /**
4
4
  * Wrap a `renderer.setAnimationLoop` callback so each tick is one frame:
@@ -1,27 +1,32 @@
1
- import { p as TimingMetric, t as PerformanceMonitor } from "./performance-monitor-DgHxeQ2X.js";
1
+ import { p as TimingMetric, t as PerformanceMonitor } from "./performance-monitor-BoY_-GTt.js";
2
2
  //#region src/ui/budgets.d.ts
3
3
  /**
4
4
  * Budgets: the value each metric should stay within. A reading past its
5
5
  * budget turns amber in the card, and the FPS / CPU / GPU graphs draw the
6
- * line once the series reaches it. `fps` and `low` are floors (worse below);
7
- * everything else is a ceiling (worse above).
6
+ * line once the series reaches it. `fps`, `low` and `headroom` are floors
7
+ * (worse below); everything else is a ceiling (worse above).
8
8
  *
9
- * Timing budgets default from `targetFps` (60): FPS at least 95% of it, 1%
10
- * low at least half, CPU and GPU within one frame, p99 within one and a half.
9
+ * Timing budgets default from `targetFps`: FPS at least 95% of it, 1% low at
10
+ * least half, CPU and GPU within one frame, p99 within one and a half,
11
+ * headroom at least zero. Without a `targetFps`, the detected refresh rate is
12
+ * used, then 60 until one is detected.
11
13
  * Counts have no default, since what's reasonable depends on the scene. Pass
12
14
  * `null` for a key to drop its default, or `false` for no budgets at all.
13
15
  */
14
- type BudgetKey = "calls" | "cpu" | "fps" | "geometries" | "gpu" | "hitches" | "lines" | "low" | "p99" | "passes" | "points" | "shaders" | "textures" | "triangles";
16
+ type BudgetKey = "calls" | "cpu" | "fps" | "geometries" | "gpu" | "headroom" | "hitches" | "lines" | "low" | "p99" | "passes" | "points" | "refresh" | "shaders" | "textures" | "triangles";
15
17
  type Budgets = Partial<Record<BudgetKey, number | null>> & {
16
- /** The frame rate the defaults are derived from. Default 60. */
18
+ /** The frame rate the defaults are derived from. Default: the detected refresh rate, else 60. */
17
19
  targetFps?: number;
18
20
  };
19
21
  type ResolvedBudgets = {
20
22
  /** Frame budget in ms, `1000 / targetFps`. */
21
23
  frameMs: number;
24
+ /** The rate the timing budgets came from: `targetFps`, the detected refresh, or 60. */
25
+ targetFps: number;
22
26
  limits: Partial<Record<BudgetKey, number>>;
23
27
  };
24
- declare const resolveBudgets: (budgets: Budgets | false | undefined) => ResolvedBudgets;
28
+ /** `detectedHz` is the monitor's refresh reading; an explicit `targetFps` wins over it. */
29
+ declare const resolveBudgets: (budgets: Budgets | false | undefined, detectedHz?: number | null) => ResolvedBudgets;
25
30
  //#endregion
26
31
  //#region src/ui/dock-panel.d.ts
27
32
  declare const EDGES: readonly ["left", "right", "top", "bottom"];
@@ -200,6 +205,10 @@ declare class PerformanceView {
200
205
  private readonly hudGraphs;
201
206
  private readonly hudNumberEls;
202
207
  private budgets;
208
+ private budgetsInput;
209
+ private detectedHz;
210
+ private readonly hider;
211
+ private readonly hiddenRows;
203
212
  private rafId;
204
213
  private lastPaintAt;
205
214
  private readonly resizeObserver;
@@ -223,9 +232,20 @@ declare class PerformanceView {
223
232
  private frame;
224
233
  private render;
225
234
  private renderCosts;
235
+ /** Name button (logs the objects) in a row; the caller appends the value cells and the eye. */
236
+ private costRowShell;
237
+ /** A hidden row: what hiding it saved, measured from the timing history. */
238
+ private hiddenCostRow;
239
+ private eyeButton;
240
+ private hideRow;
241
+ private showRow;
242
+ /** Everything hidden goes back: on closing top costs and on dispose. */
243
+ private showAllHidden;
226
244
  private costsNote;
227
245
  /** The monitor caches the environment once its backend settles; until then this re-reads. */
228
246
  private renderFooter;
247
+ /** Budgets follow the detected refresh rate unless `targetFps` was given. */
248
+ private followRefresh;
229
249
  private renderHud;
230
250
  private paintNumber;
231
251
  /** Value and sparkline, with the budget line drawn once the series reaches it. */
@@ -301,4 +321,4 @@ type PerfHudHandle = {
301
321
  declare const mountPerfHud: (monitor: PerformanceMonitor, options?: MountPerfHudOptions) => PerfHudHandle;
302
322
  //#endregion
303
323
  export { dockPanel as C, resolveBudgets as D, ResolvedBudgets as E, ScreenEdge as S, Budgets as T, DefaultPlacement as _, PerformanceViewMode as a, DockPanelOptions as b, HudDefaults as c, HudSettingsOptions as d, HudTheme as f, isThemeMode as g, ThemeMode as h, PerformanceView as i, HudSelection as l, THEME_MODES as m, PerfHudHandle as n, PerformanceViewOptions as o, ResolvedTheme as p, mountPerfHud as r, DEFAULT_STORAGE_KEY as s, MountPerfHudOptions as t, HudSettings as u, DockAlign as v, BudgetKey as w, Placement as x, DockHandle as y };
304
- //# sourceMappingURL=mount-perf-hud-BKpk62Pp.d.ts.map
324
+ //# sourceMappingURL=mount-perf-hud-MTPYNhG9.d.ts.map