From 69ca0a91710f5c04c3313e9d816c70e7191404c1 Mon Sep 17 00:00:00 2001 From: Neko Date: Fri, 11 Sep 2026 01:46:40 +0800 Subject: [PATCH] feat(stage-web): show FPS history in performance visualizer (#2516) --- apps/stage-web/README.md | 17 +++++ .../Devtools/PerformanceOverlay.vue | 10 +++ .../Devtools/fps-history.browser.test.ts | 48 +++++++++++++ .../src/components/Devtools/fps-history.vue | 71 +++++++++++++++++++ .../pages/devtools/performance-visualizer.vue | 7 ++ .../src/locales/en/tamagotchi/settings.yaml | 10 ++- .../locales/zh-Hans/tamagotchi/settings.yaml | 10 ++- 7 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 apps/stage-web/src/components/Devtools/fps-history.browser.test.ts create mode 100644 apps/stage-web/src/components/Devtools/fps-history.vue diff --git a/apps/stage-web/README.md b/apps/stage-web/README.md index 3233e4cf2..819911820 100644 --- a/apps/stage-web/README.md +++ b/apps/stage-web/README.md @@ -5,3 +5,20 @@

> Heavily inspired by [Neuro-sama](https://www.youtube.com/@Neurosama) + +## Performance diagnostics + +Run `pnpm dev:web:https` from the repository root. Open `/devtools/performance-visualizer` and enable FPS. +The floating overlay shows the last 10 seconds of FPS history, with time and FPS axes. +The minimum, maximum, and latest values describe the visible samples. Other metrics retain their distribution charts. + +Start a recording, then navigate within the app to the scene you want to measure. +Stop the recording within 60 seconds, or let it stop automatically. +Return to the visualizer to inspect the recorded FPS history. Export the recording as CSV for individual timestamps and values. + +Each FPS sample is `1000 / frameIntervalMs`, from `requestAnimationFrame` callbacks. +Use these samples to locate changes in animation frame timing. They do not measure GPU presentation or native application FPS. +Keep the page in the foreground. Reloading the page clears the recording. + +For device comparisons, use the same scene, model, warm-up period, and recording duration. +The development server and the visible overlay affect performance, so record these conditions with the results. diff --git a/apps/stage-web/src/components/Devtools/PerformanceOverlay.vue b/apps/stage-web/src/components/Devtools/PerformanceOverlay.vue index 0f2518f62..da57d80ab 100644 --- a/apps/stage-web/src/components/Devtools/PerformanceOverlay.vue +++ b/apps/stage-web/src/components/Devtools/PerformanceOverlay.vue @@ -8,6 +8,8 @@ import { storeToRefs } from 'pinia' import { computed, shallowRef, useTemplateRef, watch } from 'vue' import { useI18n } from 'vue-i18n' +import FpsHistory from './fps-history.vue' + import { useDevtoolsLagStore } from '../../stores/devtools-lag' const { n, t } = useI18n() @@ -56,6 +58,7 @@ const metricsWithStats = computed(() => visibleMetrics.value.map(metric => ({ stats: metricStatsMap.value[metric.key], }))) const recordingElapsedSeconds = computed(() => Math.min(60, Math.floor(recordingElapsedMs.value / 1000))) +const fpsHistoryEnd = computed(() => buffers.value.fps.at(-1)?.ts ?? 0) const recordingButtonLabel = computed(() => recording.value ? t('tamagotchi.settings.devtools.pages.performance-visualizer.overlay.stop') : t('tamagotchi.settings.devtools.pages.performance-visualizer.overlay.record')) @@ -212,7 +215,14 @@ function resetPosition() { + +
diff --git a/packages/i18n/src/locales/en/tamagotchi/settings.yaml b/packages/i18n/src/locales/en/tamagotchi/settings.yaml index 596a5a681..d785dc99c 100644 --- a/packages/i18n/src/locales/en/tamagotchi/settings.yaml +++ b/packages/i18n/src/locales/en/tamagotchi/settings.yaml @@ -319,7 +319,7 @@ devtools: metrics: fps: label: FPS - description: Frames per second during the last 10 seconds. + description: Animation frame rate during the last 10 seconds. Each sample is 1000 divided by the frame interval in milliseconds. frame-duration: label: Frame time (ms) description: Time between animation frames during the last 10 seconds. @@ -335,6 +335,14 @@ devtools: title: Last recording duration: Duration {duration} ms limit: Recording stops after 60 seconds. + history: + title: FPS history + latest: Latest + minimum: Min + maximum: Max + seconds-ago: '-{seconds} s' + end: 0 s + empty: No FPS samples. Enable FPS to collect samples. overlay: title: Performance move: Move performance overlay diff --git a/packages/i18n/src/locales/zh-Hans/tamagotchi/settings.yaml b/packages/i18n/src/locales/zh-Hans/tamagotchi/settings.yaml index beaf08f07..79e45564d 100644 --- a/packages/i18n/src/locales/zh-Hans/tamagotchi/settings.yaml +++ b/packages/i18n/src/locales/zh-Hans/tamagotchi/settings.yaml @@ -68,7 +68,7 @@ devtools: metrics: fps: label: FPS - description: 最近 10 秒内的每秒帧数。 + description: 最近 10 秒内的动画帧率。每个样本为 1000 除以帧间隔(毫秒)。 frame-duration: label: 帧时间(毫秒) description: 最近 10 秒内动画帧之间的时间。 @@ -84,6 +84,14 @@ devtools: title: 上次录制 duration: 时长 {duration} 毫秒 limit: 录制会在 60 秒后停止。 + history: + title: FPS 历史 + latest: 最新 + minimum: 最低 + maximum: 最高 + seconds-ago: '-{seconds} 秒' + end: 0 秒 + empty: 暂无 FPS 样本,请启用 FPS 采集。 overlay: title: 性能 move: 移动性能浮窗