Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 35 additions & 6 deletions web/src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,13 @@ import {
} catch (err) {
const userErr = toUserError(err, "REST");
setLiveError(userErr);
setMode("demo", `${userErr} - running in demo mode`);
if (state.mode === "live") {
setWarning(`${userErr} - staying in live mode`);
state.live.connected = false;
setModeBadge();
} else {
setMode("demo", `${userErr} - running in demo mode`);
}
}
}

Expand Down Expand Up @@ -272,7 +278,13 @@ import {
es.onerror = () => {
const errText = `SSE: network/CORS blocked (${state.live.beaconUrl})`;
setLiveError(errText);
setMode("demo", `${errText} - running in demo mode`);
if (state.mode === "live") {
setWarning(`${errText} - staying in live mode`);
state.live.connected = false;
setModeBadge();
} else {
setMode("demo", `${errText} - running in demo mode`);
}
};

const bindEvent = (name) => {
Expand All @@ -288,7 +300,13 @@ import {
} catch (err) {
const userErr = toUserError(err, "SSE");
setLiveError(userErr);
setMode("demo", `${userErr} - running in demo mode`);
if (state.mode === "live") {
setWarning(`${userErr} - staying in live mode`);
state.live.connected = false;
setModeBadge();
} else {
setMode("demo", `${userErr} - running in demo mode`);
}
return;
}

Expand All @@ -303,8 +321,15 @@ import {
if (state.mode !== "live") return;
const idleFor = Date.now() - state.live.lastEventAt;
if (idleFor > 20000) {
setLiveError("SSE: timeout waiting for events");
setMode("demo", "Live SSE timeout - running in demo mode");
const errText = "SSE: timeout waiting for events";
setLiveError(errText);
if (state.mode === "live") {
setWarning(`${errText} - staying in live mode`);
state.live.connected = false;
setModeBadge();
} else {
setMode("demo", "Live SSE timeout - running in demo mode");
}
}
}, 5000);
}
Expand Down Expand Up @@ -336,7 +361,7 @@ import {
nodes.settingsPanel.classList.toggle("open");
});

nodes.applySettings.addEventListener("click", () => {
const applySettingsFromInputs = () => {
state.live.beaconUrl = nodes.beaconInput.value.trim() || "http://localhost:5052";
state.live.metricsUrl = nodes.metricsInput.value.trim() || "http://localhost:9090";
state.live.apiNamespace = nodes.nsSelect.value === "eth" ? "eth" : "lean";
Expand All @@ -346,6 +371,10 @@ import {

const mode = nodes.modeSelect.value === "live" ? "live" : "demo";
setMode(mode);
};

nodes.applySettings.addEventListener("click", () => {
applySettingsFromInputs();
});
}

Expand Down
12 changes: 10 additions & 2 deletions web/src/render/chain.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ export function drawChainCanvas(now) {

visible.sort((a, b) => a.block.slot - b.block.slot);

ctx.save();
ctx.beginPath();
ctx.rect(0, 0, w, h);
ctx.clip();

for (let i = 1; i < visible.length; i++) {
const prev = visible[i - 1];
const cur = visible[i];
Expand All @@ -60,8 +65,10 @@ export function drawChainCanvas(now) {

for (const item of visible) {
const { block, x, y } = item;
if (x < 2 || (x + blockW) > (w - 2)) continue;
const status = getBlockStatus(block);
const fade = Math.max(0.1, Math.min(1, (x + 80) / (w * 0.52)));
const edgeGlowClamp = x < 8 || (x + blockW) > (w - 8);

let color = COLORS.blue;
if (status === "JUSTIFIED") color = COLORS.amber;
Expand All @@ -78,10 +85,10 @@ export function drawChainCanvas(now) {
ctx.stroke();
ctx.setLineDash([]);

ctx.shadowBlur = status === "MISSED" ? 0 : 18;
ctx.shadowBlur = (status === "MISSED" || edgeGlowClamp) ? 0 : 18;
ctx.shadowColor = status === "FINALIZED" ? "rgba(34,197,94,0.65)" : `${color}99`;
if (block.flashUntil > now) {
ctx.shadowBlur = 30;
ctx.shadowBlur = edgeGlowClamp ? 0 : 30;
ctx.shadowColor = "rgba(34,197,94,0.9)";
}
roundRect(ctx, x, y, blockW, blockH, 12);
Expand Down Expand Up @@ -138,4 +145,5 @@ export function drawChainCanvas(now) {
}
}
ctx.globalAlpha = 1;
ctx.restore();
}
27 changes: 23 additions & 4 deletions web/src/render/validators.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { COLORS, state } from "../state.js";
import { validatorCanvas, validatorCtx } from "../dom.js";
import { getValidatorCount } from "../sim/logic.js";
import { drawValidatorAvatar } from "./primitives.js";
import { drawValidatorAvatar, roundRect } from "./primitives.js";

export function drawValidatorCanvas(now) {
const ctx = validatorCtx;
Expand Down Expand Up @@ -31,12 +31,31 @@ export function drawValidatorCanvas(now) {
ctx.lineWidth = 1.2;
ctx.stroke();

const blockLabel = "BLOCK";
const slotLabel = String(state.currentSlot);
ctx.textAlign = "center";

ctx.font = "700 11px 'Space Mono'";
const labelW = ctx.measureText(blockLabel).width;
ctx.font = "700 13px 'Space Mono'";
const slotW = ctx.measureText(slotLabel).width;
const boxW = Math.max(labelW, slotW) + 18;
const boxH = 34;
const boxX = cx - boxW / 2;
const boxY = cy - boxH / 2;

roundRect(ctx, boxX, boxY, boxW, boxH, 8);
ctx.fillStyle = "rgba(6,10,18,0.85)";
ctx.fill();
ctx.lineWidth = 1;
ctx.strokeStyle = "rgba(0,255,204,0.35)";
ctx.stroke();

ctx.font = "700 11px 'Space Mono'";
ctx.fillStyle = "#c9fff4";
ctx.textAlign = "center";
ctx.fillText("BLOCK", cx, cy - 2);
ctx.fillText(blockLabel, cx, cy - 4);
ctx.font = "700 13px 'Space Mono'";
ctx.fillText(String(state.currentSlot), cx, cy + 12);
ctx.fillText(slotLabel, cx, cy + 11);

const count = getValidatorCount();
const nodePos = [];
Expand Down
2 changes: 1 addition & 1 deletion web/src/state.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const DEMO_SLOT_MS = 8000;
export const DEMO_SLOT_MS = 4000;
export const LIVE_SLOT_MS = 4000;
export const DEFAULT_VALIDATOR_COUNT = 24;

Expand Down
5 changes: 3 additions & 2 deletions web/styles/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@
}

.app {
width: min(1680px, calc(100vw - 24px));
margin: 12px auto;
width: 100%;
margin: 0;
border: 1px solid var(--border);
background: linear-gradient(180deg, rgba(255,255,255,0.02), rgba(255,255,255,0.005));
box-shadow: 0 24px 80px rgba(0, 0, 0, 0.55);
Expand Down Expand Up @@ -271,6 +271,7 @@
background: rgba(0,255,204,0.12);
}


.debug {
margin-top: 8px;
border-top: 1px solid var(--border);
Expand Down
Loading