perf: pause tavern canvas when off-screen (0.60.0)
- the 60fps canvas render loop ran continuously even when scrolled out of view (the home page is long now — wasted CPU/battery while reading below) - IntersectionObserver pauses the rAF loop at 0% visibility and resumes it when the tavern scrolls back in; cleaned up on unmount - verified live: ~60 rAF/s on-screen → 0 off-screen → 60 on resume, 0 errors
This commit is contained in:
parent
3ddbc76dfc
commit
cf67af7131
@ -4,7 +4,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="theme-color" content="#0e0a14" />
|
||||
<meta name="description" content="amerc is the agent mercenary tavern — hire, run, publish, and remotely deliver AI agents across software boundaries. No infrastructure, just skills." />
|
||||
<meta name="version" content="0.59.0-a11y" />
|
||||
<meta name="version" content="0.60.0-canvasperf" />
|
||||
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
||||
<link rel="icon" href="/app-192.png" type="image/png" sizes="192x192" />
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "amerc-site",
|
||||
"version": "0.59.0-a11y",
|
||||
"version": "0.60.0-canvasperf",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@ -7,7 +7,7 @@ import Account from './Account.jsx';
|
||||
import TavernGame from './TavernGame.jsx';
|
||||
import { api } from './api.js';
|
||||
|
||||
const RELEASE = '0.59.0-a11y';
|
||||
const RELEASE = '0.60.0-canvasperf';
|
||||
|
||||
const NAV = [
|
||||
{ id: 'home', label: 'Tavern' },
|
||||
|
||||
@ -57,12 +57,13 @@ export default function TavernGame({ onHotspot, stats }) {
|
||||
useEffect(() => { statsRef.current = stats; }, [stats]);
|
||||
const [ready, setReady] = useState(false);
|
||||
useEffect(() => {
|
||||
const keys = Object.keys(SRC); const S = {}; let loaded = 0, raf, f = 0, buf;
|
||||
const keys = Object.keys(SRC); const S = {}; let loaded = 0, raf, f = 0, buf, paused = false, io;
|
||||
const start = () => {
|
||||
setReady(true);
|
||||
buf = document.createElement('canvas'); buf.width = W; buf.height = H; buildStatic(buf, S);
|
||||
const ctx = canvasRef.current.getContext('2d'); ctx.imageSmoothingEnabled = false;
|
||||
const render = () => {
|
||||
if (paused) return;
|
||||
f++;
|
||||
ctx.drawImage(buf, 0, 0);
|
||||
// bartender (a clothed guard tending bar) behind the bar (idle bob)
|
||||
@ -107,9 +108,15 @@ export default function TavernGame({ onHotspot, stats }) {
|
||||
raf = requestAnimationFrame(render);
|
||||
};
|
||||
render();
|
||||
// pause the 60fps loop while the tavern is scrolled out of view (CPU/battery)
|
||||
io = new IntersectionObserver(([e]) => {
|
||||
if (e.isIntersecting) { if (paused) { paused = false; render(); } }
|
||||
else if (!paused) { paused = true; cancelAnimationFrame(raf); }
|
||||
}, { threshold: 0 });
|
||||
io.observe(canvasRef.current);
|
||||
};
|
||||
keys.forEach((k) => { const im = new Image(); im.onload = () => { if (++loaded === keys.length) start(); }; im.src = SRC[k]; S[k] = im; });
|
||||
return () => cancelAnimationFrame(raf);
|
||||
return () => { cancelAnimationFrame(raf); if (io) io.disconnect(); };
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
||||
Loading…
Reference in New Issue
Block a user