P20.1: FPS counter — env-gated dev overlay (M3TE_FPS), off by default
Add a small top-left FPS readout for gauging frame cost while tuning the organic animations. Gated behind the M3TE_FPS startup env pin (read like the other M3TE_* hooks); unset/=0 renders nothing, so default play and every committed golden stay byte-identical. - main.sx: g_fps_on (from M3TE_FPS) + g_fps_avg_dt, an EMA of delta_time (FPS_DT_SMOOTH=0.9) advanced only on the gated path; build_ui passes the smoothed FPS + flag into BoardView. delta_time is real wall-clock even when M3TE_ANIM_TIME pins the scene, so the counter stays live while frozen. - board_view.sx: BoardView.fps_on/fps fields + render_fps_overlay — "FPS n" in the top-left safe-area corner (clear of notch/Dynamic Island + the HUD), dark grape text over a bright halo. Drawn last, only when fps_on. - README.md: document M3TE_FPS (sim SIMCTL_CHILD_ + device devicectl env). - goldens/p20_fps.png: FPS overlay over the resting board (M3TE_FPS=1, M3TE_ANIM_TIME=0); FPS digits are dynamic, rest pinned == p6_idle_t0 region. Verified: ios-sim build + 22 logic tests green. Unset capture's board+HUD region is byte-identical to goldens/p6_idle_t0.png; the only ON-vs-OFF delta is the top-left FPS text box.
This commit is contained in:
@@ -60,6 +60,15 @@ HUD_PANEL :: Color.{ r = 92, g = 46, b = 150, a = 224 }; // bright grape ca
|
||||
HUD_PANEL_HI :: Color.{ r = 196, g = 138, b = 240, a = 92 }; // glossy top sheen
|
||||
HUD_PANEL_RIM:: Color.{ r = 236, g = 204, b = 255, a = 150 }; // bright candy rim
|
||||
|
||||
// FPS dev overlay (P20.1): a small corner readout, OFF unless M3TE_FPS pins it on
|
||||
// (so default play + every golden are unchanged). Pinned to the top-left of the
|
||||
// safe area — clear of the centered notch / Dynamic Island and the centered HUD.
|
||||
// Dark grape text over a bright halo keeps it legible on the light lavender art.
|
||||
FPS_FONT :f32: 22.0;
|
||||
FPS_PAD :f32: 8.0;
|
||||
FPS_TEXT :: Color.{ r = 40, g = 16, b = 64, a = 235 }; // dark grape, readable on lavender
|
||||
FPS_TEXT_SH:: Color.{ r = 255, g = 255, b = 255, a = 170 }; // bright halo for contrast
|
||||
|
||||
// Win/lose banner (P12.2): a warm dim over the board, a glossy candy panel, the
|
||||
// win/lose headline, and a playful restart button. Built from text + rects only —
|
||||
// the engine's image path can't tint/fade at draw time (issue 0002), but rects and
|
||||
@@ -229,6 +238,11 @@ BoardView :: struct {
|
||||
// Seed for `restart`: the same fixed seed main seeded the board with, so the
|
||||
// restart button reproduces the identical starting level.
|
||||
seed: s64;
|
||||
// FPS dev overlay (P20.1). `fps_on` gates the corner readout (off by default,
|
||||
// set only by the M3TE_FPS env pin); `fps` is the smoothed reciprocal frame
|
||||
// rate computed in the frame loop. Purely a render overlay.
|
||||
fps_on: bool;
|
||||
fps: f32;
|
||||
|
||||
// Where the grid sits + the touch↔cell mapping. Recomputed each render /
|
||||
// event from the current frame so the hit-test matches what was drawn.
|
||||
@@ -601,6 +615,21 @@ BoardView :: struct {
|
||||
ctx.add_text(bfr, btxt, bfont, BANNER_BTN_TEXT);
|
||||
}
|
||||
|
||||
// FPS dev overlay (P20.1): a small "FPS n" readout pinned to the top-left of
|
||||
// the safe area, on top of everything. Drawn only when fps_on (the M3TE_FPS
|
||||
// pin) is set, so the unset render path is byte-identical. A bright halo under
|
||||
// the dark text keeps the digits legible over the light background art.
|
||||
render_fps_overlay :: (self: *BoardView, ctx: *RenderContext, frame: Frame) {
|
||||
n := cast(s64) (self.fps + 0.5);
|
||||
txt := format("FPS {}", n);
|
||||
sz := measure_text(txt, FPS_FONT);
|
||||
x := frame.origin.x + self.safe.left + FPS_PAD;
|
||||
y := frame.origin.y + self.safe.top + FPS_PAD;
|
||||
f := Frame.make(x, y, sz.width, sz.height);
|
||||
ctx.add_text(Frame.make(f.origin.x + 1.0, f.origin.y + 1.5, f.size.width, f.size.height), txt, FPS_FONT, FPS_TEXT_SH);
|
||||
ctx.add_text(f, txt, FPS_FONT, FPS_TEXT);
|
||||
}
|
||||
|
||||
// Restart action behind the banner's button: reseed the SAME starting level
|
||||
// through the model (board.restart) and drop every transient view layer
|
||||
// (selection, in-flight drag, move animation, FX, and the per-gem landing
|
||||
@@ -694,6 +723,12 @@ impl View for BoardView {
|
||||
if self.banner_up() {
|
||||
self.render_banner(ctx, level_status(self.board));
|
||||
}
|
||||
|
||||
// 7. FPS dev overlay (P20.1), on top of everything. Off by default; only
|
||||
// renders when M3TE_FPS pinned it on, so the unset path is unchanged.
|
||||
if self.fps_on {
|
||||
self.render_fps_overlay(ctx, frame);
|
||||
}
|
||||
}
|
||||
|
||||
// Touch input. A press records the drag start; the release resolves the
|
||||
|
||||
Reference in New Issue
Block a user