Stabilize solver metrics and run notes

This commit is contained in:
Meta Vens 2026-04-25 02:31:17 +01:00
commit 2c4721a96f
3 changed files with 89 additions and 18 deletions

View file

@ -458,6 +458,7 @@ function renderInference(): void {
function renderStatusMetrics(): void {
statusMetrics.innerHTML = "";
statusMetrics.classList.toggle("status-metrics-fixed", state.stageKey === "solver");
const items: Array<[string, string]> = [];
const frame = getSelectedFrame();
if (state.stageKey === "inference") {
@ -505,15 +506,30 @@ function renderStatusMetrics(): void {
items.push(["Confidence", formatNumber(state.phaseRerank.confidence, 3)]);
}
} else if (state.stageKey === "solver") {
if (state.phaseFieldPrep) {
items.push(["Grid", `${state.phaseFieldPrep.targetWidth} x ${state.phaseFieldPrep.targetHeight}`]);
items.push(["Cell pitch", `${formatNumber(state.phaseFieldPrep.cellX, 1)} x ${formatNumber(state.phaseFieldPrep.cellY, 1)} px`]);
}
if (frame) {
items.push(["Loss", frame.loss === null ? "n/a" : formatNumber(frame.loss, 4)]);
for (const [key, value] of Object.entries(frame.terms).slice(0, 4)) {
items.push([key.replaceAll("_", " "), formatNumber(value, 4)]);
}
const solverTerms: Array<[string, number | null]> = [
["Coherence", frame?.terms.local_coherence ?? null],
["Edge", frame?.terms.local_edge ?? null],
["Smoothness", frame?.terms.smoothness ?? null],
["Collapse", frame?.terms.collapse ?? null],
["Magnitude", frame?.terms.magnitude ?? null],
];
items.push([
"Grid",
state.phaseFieldPrep ? `${state.phaseFieldPrep.targetWidth} x ${state.phaseFieldPrep.targetHeight}` : "pending",
]);
items.push([
"Step",
frame ? `${frame.step} / ${frame.totalSteps}` : `0 / ${Math.max(0, state.solverStepBudget)}`,
]);
items.push([
"Cell pitch",
state.phaseFieldPrep
? `${formatNumber(state.phaseFieldPrep.cellX, 1)} x ${formatNumber(state.phaseFieldPrep.cellY, 1)} px`
: "pending",
]);
items.push(["Loss", frame?.loss === null || frame?.loss === undefined ? "n/a" : formatNumber(frame.loss, 4)]);
for (const [label, value] of solverTerms) {
items.push([label, formatNumber(value, 4)]);
}
}
for (const [label, value] of items) {

View file

@ -322,6 +322,7 @@ function renderInference() {
}
function renderStatusMetrics() {
statusMetrics.innerHTML = "";
statusMetrics.classList.toggle("status-metrics-fixed", state.stageKey === "solver");
const items = [];
const frame = getSelectedFrame();
if (state.stageKey === "inference") {
@ -372,15 +373,30 @@ function renderStatusMetrics() {
}
}
else if (state.stageKey === "solver") {
if (state.phaseFieldPrep) {
items.push(["Grid", `${state.phaseFieldPrep.targetWidth} x ${state.phaseFieldPrep.targetHeight}`]);
items.push(["Cell pitch", `${formatNumber(state.phaseFieldPrep.cellX, 1)} x ${formatNumber(state.phaseFieldPrep.cellY, 1)} px`]);
}
if (frame) {
items.push(["Loss", frame.loss === null ? "n/a" : formatNumber(frame.loss, 4)]);
for (const [key, value] of Object.entries(frame.terms).slice(0, 4)) {
items.push([key.replaceAll("_", " "), formatNumber(value, 4)]);
}
const solverTerms = [
["Coherence", frame?.terms.local_coherence ?? null],
["Edge", frame?.terms.local_edge ?? null],
["Smoothness", frame?.terms.smoothness ?? null],
["Collapse", frame?.terms.collapse ?? null],
["Magnitude", frame?.terms.magnitude ?? null],
];
items.push([
"Grid",
state.phaseFieldPrep ? `${state.phaseFieldPrep.targetWidth} x ${state.phaseFieldPrep.targetHeight}` : "pending",
]);
items.push([
"Step",
frame ? `${frame.step} / ${frame.totalSteps}` : `0 / ${Math.max(0, state.solverStepBudget)}`,
]);
items.push([
"Cell pitch",
state.phaseFieldPrep
? `${formatNumber(state.phaseFieldPrep.cellX, 1)} x ${formatNumber(state.phaseFieldPrep.cellY, 1)} px`
: "pending",
]);
items.push(["Loss", frame?.loss === null || frame?.loss === undefined ? "n/a" : formatNumber(frame.loss, 4)]);
for (const [label, value] of solverTerms) {
items.push([label, formatNumber(value, 4)]);
}
}
for (const [label, value] of items) {

View file

@ -201,6 +201,15 @@ p {
gap: 10px;
}
.sidebar,
.section-block,
.summary-panel,
.candidate-list,
.event-log,
.info-stack {
min-width: 0;
}
:is(.hero, .card, .metric-chip, .summary-card, .app-shell-header, .viz-card, .loss-canvas, .editor-toolbar, .editor-surface, .dropzone, .field input, .field select, .button, .toggle-row) {
position: relative;
overflow: hidden;
@ -728,8 +737,14 @@ p {
gap: 10px;
}
.status-metrics.status-metrics-fixed {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.status-metric {
min-width: 0;
width: 100%;
box-sizing: border-box;
padding: 8px 10px;
border: 2px solid rgba(8, 36, 62, 0.88);
background: linear-gradient(180deg, rgba(9, 27, 44, 0.96), rgba(5, 16, 28, 0.95));
@ -748,6 +763,8 @@ p {
font-size: 1rem;
line-height: 1.12;
color: var(--ui-text);
overflow-wrap: anywhere;
word-break: break-word;
}
@keyframes status-sweep {
@ -764,6 +781,9 @@ p {
.event-item,
.metric-chip,
.summary-card {
min-width: 0;
width: 100%;
box-sizing: border-box;
border: 3px solid rgba(8, 36, 62, 0.88);
background:
linear-gradient(180deg, rgba(11, 32, 52, 0.96), rgba(6, 19, 35, 0.94));
@ -781,6 +801,17 @@ p {
font-size: 0.72rem;
color: var(--ui-accent);
text-transform: uppercase;
overflow-wrap: anywhere;
word-break: break-word;
}
.candidate-card span,
.event-item span,
.summary-card span {
display: block;
min-width: 0;
overflow-wrap: anywhere;
word-break: break-word;
}
.editor-actions {
@ -919,6 +950,10 @@ select:focus-visible {
grid-template-columns: 1fr;
}
.status-metrics.status-metrics-fixed {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.card-head {
flex-wrap: wrap;
}
@ -967,4 +1002,8 @@ select:focus-visible {
.button {
width: 100%;
}
.status-metrics.status-metrics-fixed {
grid-template-columns: 1fr;
}
}