diff --git a/index.html b/index.html index 834f66a..0c703a9 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ - + diff --git a/package.json b/package.json index 8d3bde9..0edbd9e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "amerc-site", - "version": "0.52.0-changelog", + "version": "0.53.0-livescreen", "private": true, "type": "module", "scripts": { diff --git a/src/Scene2D.jsx b/src/Scene2D.jsx index 83e5a97..fec6328 100644 --- a/src/Scene2D.jsx +++ b/src/Scene2D.jsx @@ -7,7 +7,7 @@ import Account from './Account.jsx'; import TavernGame from './TavernGame.jsx'; import { api } from './api.js'; -const RELEASE = '0.52.0-changelog'; +const RELEASE = '0.53.0-livescreen'; const NAV = [ { id: 'home', label: 'Tavern' }, @@ -103,7 +103,7 @@ function Home({ setRoute }) { return (
Hire, run, and deliver AI agents across any software boundary — as an embedded chatbox, a live web terminal, or a public URL. No infrastructure, just skills.
diff --git a/src/TavernGame.jsx b/src/TavernGame.jsx index 6ac8ed0..3b0d4be 100644 --- a/src/TavernGame.jsx +++ b/src/TavernGame.jsx @@ -51,8 +51,10 @@ function buildStatic(buf, S) { ctx.fillStyle = '#0c2030'; ctx.fillRect(198, 6, 116, 50); ctx.strokeStyle = '#46c8e0'; ctx.lineWidth = 2; ctx.strokeRect(199, 7, 114, 48); ctx.fillStyle = '#16415e'; ctx.fillRect(202, 10, 108, 42); } -export default function TavernGame({ onHotspot }) { +export default function TavernGame({ onHotspot, stats }) { const canvasRef = useRef(null); + const statsRef = useRef(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; @@ -79,9 +81,20 @@ export default function TavernGame({ onHotspot }) { // spotlight const g = ctx.createRadialGradient(256, 230, 6, 256, 236, 56); g.addColorStop(0, 'rgba(255,244,210,0.26)'); g.addColorStop(1, 'rgba(255,244,210,0)'); ctx.fillStyle = g; ctx.beginPath(); ctx.ellipse(256, 244, 40, 44, 0, 0, 7); ctx.fill(); chr(ctx, S.princess, dframe, 224 + sway, 184); - // screen content (chart + scanline) - for (let i = 0; i < 13; i++) { const bh = 4 + ((Math.sin(f * 0.09 + i) + 1) * 6 + (i % 3)) | 0; ctx.fillStyle = i % 2 ? '#7fe9ff' : '#2f9fd0'; ctx.fillRect(206 + i * 8, 48 - bh, 5, bh); } - ctx.fillStyle = 'rgba(127,233,255,0.5)'; ctx.fillRect(202, 10 + (f % 42), 108, 1); + // screen content: LIVE platform stats, cycling, over a dim sparkline + const st = statsRef.current; + const items = st ? [['CLASSES', st.classes], ['ONLINE', st.online], ['SESSIONS', st.sessions]] : [['LIVE', '·']]; + const phase = Math.floor(f / 150) % items.length; + const [label, val] = items[phase]; + for (let i = 0; i < 13; i++) { const bh = 3 + ((Math.sin(f * 0.09 + i) + 1) * 4 + (i % 3)) | 0; ctx.fillStyle = 'rgba(70,170,210,0.30)'; ctx.fillRect(206 + i * 8, 50 - bh, 5, bh); } + const pf = (f % 150) / 150, fade = Math.min(1, Math.min(pf, 1 - pf) * 8 + 0.25); + ctx.textAlign = 'center'; + ctx.fillStyle = `rgba(174,242,255,${fade})`; ctx.font = 'bold 18px Georgia, serif'; + ctx.fillText(String(val), 256, 33); + ctx.fillStyle = `rgba(95,208,232,${fade})`; ctx.font = '7px Georgia, serif'; + ctx.fillText(label, 256, 45); + ctx.textAlign = 'left'; ctx.font = '10px serif'; + ctx.fillStyle = 'rgba(127,233,255,0.4)'; ctx.fillRect(202, 10 + (f % 42), 108, 1); // warm lighting + screen glow ctx.globalCompositeOperation = 'lighter'; for (const [lx, ly, lr, a] of [[256, 30, 64, 0.16], [40, 40, 30, 0.18], [432, 40, 30, 0.18]]) { const aa = a * (0.85 + 0.15 * Math.sin(f * 0.1 + lx)); const gg = ctx.createRadialGradient(lx, ly, 0, lx, ly, lr); gg.addColorStop(0, `rgba(255,180,90,${aa})`); gg.addColorStop(1, 'rgba(255,170,80,0)'); ctx.fillStyle = gg; ctx.beginPath(); ctx.arc(lx, ly, lr, 0, 7); ctx.fill(); }