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
1 change: 1 addition & 0 deletions packages/extension/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
dev/pulseplot_harness/main.js
dev/brand_harness/main.js
131 changes: 131 additions & 0 deletions packages/extension/dev/brand_harness/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>brand harness — light-mode yellow</title>
<link rel="stylesheet" href="../../media/brand.css" />
<link rel="stylesheet" href="../../media/layout.css" />
<style>
/* Stand-ins for the VS Code theme variables the webview provides.
Light is the default (this study is about light mode); toggle adds
.dark. applyBrandAccent() reads --vscode-editor-background +
--vscode-foreground from here and solves fill/edge/ink at :root. */
body {
--vscode-foreground: #3b3b3b;
--vscode-editor-background: #ffffff;
--vscode-editorWidget-background: #f6f6f6;
--vscode-descriptionForeground: #6b6b6b;
--vscode-widget-border: #e2e2e2;
--vscode-panel-border: #e2e2e2;
--vscode-button-secondaryForeground: #3b3b3b;
--vscode-button-secondaryBackground: #eaeaea;
--vscode-button-secondaryHoverBackground: #dedede;
--vscode-button-border: transparent;
--vscode-focusBorder: #0090f1;
--vscode-progressBar-background: #0090f1;
--vscode-errorForeground: #e51400;
--vscode-testing-iconPassed: #2f8a52;
--vscode-charts-blue: #1a85ff;
--vscode-charts-orange: #a05a00;
--vscode-charts-purple: #8b47b7;
--vscode-charts-green: #2e7d32;
--vscode-charts-yellow: #b0881a;
--vscode-charts-red: #cc5a5a;
--vscode-scrollbarSlider-background: #c4c4c4;
background: var(--vscode-editor-background);
color: var(--vscode-foreground);
font-family: system-ui, sans-serif;
font-size: 13px;
margin: 0;
padding: 20px 24px 64px;
min-height: 100vh;
box-sizing: border-box;
}
body.dark {
--vscode-foreground: #cccccc;
--vscode-editor-background: #1e1e1e;
--vscode-editorWidget-background: #252526;
--vscode-descriptionForeground: #9d9d9d;
--vscode-widget-border: #303031;
--vscode-panel-border: #2b2b2b;
--vscode-button-secondaryForeground: #cccccc;
--vscode-button-secondaryBackground: #3a3d41;
--vscode-button-secondaryHoverBackground: #45494e;
--vscode-focusBorder: #007fd4;
--vscode-charts-blue: #3794ff;
--vscode-charts-orange: #c17800;
--vscode-charts-purple: #9b6bc4;
--vscode-charts-green: #4d9e51;
}
#controls {
display: flex;
gap: 10px;
align-items: center;
position: sticky;
top: 0;
padding: 10px 0;
background: var(--vscode-editor-background);
border-bottom: 1px solid var(--vscode-widget-border);
margin-bottom: 8px;
z-index: 10;
}
#controls button {
font: inherit;
padding: 5px 12px;
cursor: pointer;
border-radius: 4px;
border: 1px solid var(--vscode-widget-border);
background: var(--vscode-button-secondaryBackground);
color: var(--vscode-foreground);
}
#controls .now {
font-family: monospace;
color: var(--vscode-descriptionForeground);
}
h2 {
font-size: 11px;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--vscode-descriptionForeground);
margin: 26px 0 12px;
font-weight: 600;
}
.row {
display: flex;
gap: 12px;
align-items: center;
flex-wrap: wrap;
}
.cap {
font-family: monospace;
font-size: 11px;
color: var(--vscode-descriptionForeground);
margin-top: 6px;
}
</style>
</head>
<body>
<div id="controls">
<button id="theme">☀ / ☾ toggle theme</button>
<span class="now" id="now"></span>
</div>

<h2>Brand swatch — fill · 1px edge · dark ink</h2>
<div class="row" id="swatches"></div>
<div class="cap" id="swatch-cap"></div>

<h2>Metrics — hero flag (the Run Inspector's one hero) vs neutral</h2>
<div class="row" id="metrics"></div>

<h2>Buttons — hover to see the ink border/tint</h2>
<div class="row" id="buttons"></div>

<h2>Sparkline — ink stroke (neutral on light, lemon on dark)</h2>
<div class="row" id="sparkline"></div>

<h2>Catalog card — "proposed" metrics carry a dashed ink border</h2>
<div id="catalog" style="max-width: 640px"></div>

<script src="./main.js"></script>
</body>
</html>
91 changes: 91 additions & 0 deletions packages/extension/dev/brand_harness/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Brand accent dev harness — renders the real webview components against
// stubbed VS Code theme vars so the light/dark brand treatment can be eyeballed
// without a live run. NOT shipped in the VSIX (dev/ is excluded; see
// .vscodeignore). Run: `pnpm run dev:brand`.
//
// The solver (applyBrandAccent) reads --vscode-editor-background +
// --vscode-foreground from index.html and sets --color-accent-{fill,edge,ink}
// at :root; toggling .dark on <body> mutates an attribute, so its
// MutationObserver re-solves — the components react exactly as in the webview.

import { applyBrandAccent, solveBrandAccent } from "../../media/ui/brand_accent";
import { metric } from "../../media/ui/components/metric";
import { button } from "../../media/ui/atoms/button";
import { sparkline } from "../../media/ui/components/sparkline";
import { catalogcard, type CatalogEntry } from "../../media/ui/components/catalogcard";

// --- brand swatch: fill + edge + on-accent, straight from the tokens
function swatch(label: string): HTMLElement {
const d = document.createElement("div");
d.textContent = label;
d.style.cssText =
"display:inline-flex;align-items:center;padding:7px 14px;border-radius:6px;" +
"font-weight:600;font-size:14px;background:var(--color-accent-fill);" +
"color:var(--color-on-accent);border:var(--border-width) solid var(--color-accent-edge);";
return d;
}
const swatches = document.getElementById("swatches")!;
swatches.append(swatch("Solve complete"), swatch("CZ · 0.9994"), swatch("Promoted"));

// --- metrics: the flagged hero, a pending hero, and neutral (catalog-style)
const metricsHost = document.getElementById("metrics")!;
const heroFlag = metric("fidelity", { variant: "hero", flag: true });
heroFlag.value("0.9994");
const heroPending = metric("fidelity", { variant: "hero", flag: true }); // stays "–": no flag until it lands
const heroNeutral = metric("gate time", { variant: "hero" }); // catalog-style hero: no flag
heroNeutral.value("20 ns");
const small = metric("objective", { variant: "small" });
small.value("3.2e-4");
metricsHost.append(heroFlag.el, heroPending.el, heroNeutral.el, small.el);

// --- buttons (hover states are the point)
const buttonsHost = document.getElementById("buttons")!;
buttonsHost.append(
button("■ Stop", () => {}).el,
button("↓ Save pulse", () => {}).el,
button("↗ Open run dir", () => {}).el,
);

// --- sparkline: a converging (descending) objective trace
const sparkHost = document.getElementById("sparkline")!;
const spark = sparkline(60);
sparkHost.append(spark.el);
for (let i = 0; i < 60; i++) spark.update(10 ** (1 - (i / 60) * 4) * (1 + 0.15 * Math.sin(i)));

// --- catalog card: fidelity + gate-time heroes (neutral) + proposed dashed metrics
const entry: CatalogEntry = {
schema_version: "1",
run_id: "run-demo-0715",
lab_id: "lab-demo",
fidelity: 0.99942,
pulse_path: "catalog/pulses/transmon/cz.jld2",
gate: "CZ",
created_at: "2026-07-15",
params: { system: "transmon", T: 20 },
proposed: { tags: ["demo"], iterations: 320, wall_seconds: 45, system_name: "Demo transmon" },
};
document.getElementById("catalog")!.append(catalogcard(entry, { onAction: () => {} }).el);

// --- boot the solver + wire the theme toggle
applyBrandAccent();
const nowLabel = document.getElementById("now")!;
const refresh = (): void => {
const cs = getComputedStyle(document.body);
const r = solveBrandAccent(
cs.getPropertyValue("--vscode-editor-background"),
cs.getPropertyValue("--vscode-foreground"),
);
nowLabel.textContent = `${r.isLight ? "LIGHT" : "DARK"} · fill ${r.fill} · edge ${r.edge} · ink ${r.ink}`;
document.getElementById("swatch-cap")!.textContent = r.isLight
? "light: true lemon fill, 1px dark hairline edge, black text"
: "dark: true lemon fill, no edge (it separates itself), black text";
};
refresh();
document.getElementById("theme")!.addEventListener("click", () => {
document.body.classList.toggle("dark");
refresh();
});
if (location.hash.includes("dark")) {
document.body.classList.add("dark");
refresh();
}
16 changes: 12 additions & 4 deletions packages/extension/media/brand.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,18 @@
}

:root {
/* color */
--color-accent: #fff676;
--color-on-accent: #000000;
/* color — the brand yellow, split into three honest roles. brand_accent.ts
* overrides fill/edge/ink at :root per the live theme; these are the DARK
* defaults (the dev harness + no-JS render on the dark surface). The rule:
* yellow is a FILL, never an ink. On light surfaces the lemon can't define
* its own edge (1.1:1 vs white), so the edge comes from a dark hairline; on
* dark it separates itself (14.8:1), so the edge is transparent. */
--brand-yellow: #fff676;
--color-accent-fill: var(--brand-yellow); /* the swatch — true lemon, both themes */
--color-on-accent: #000000; /* dark ink on the swatch — 18.7:1, never yellow text */
--color-accent-edge: transparent; /* dark default; light → dark hairline (theme fg) */
--color-accent-ink: var(--brand-yellow); /* thin lines that can't be fills; light → neutral fg */
--color-accent: var(--color-accent-ink); /* back-compat alias — strokes get legible ink, never gold */
--color-ok: var(--vscode-testing-iconPassed);
--color-fail: var(--vscode-errorForeground);
--color-run: var(--vscode-progressBar-background);
Expand Down Expand Up @@ -44,7 +53,6 @@
--border-radius: 4px;
--border-radius-round: 1000px;
--border-color: var(--vscode-widget-border, var(--vscode-panel-border));
--border-color-hero: color-mix(in srgb, var(--color-accent) 45%, var(--vscode-panel-border));

/* background */
--bg-box: var(--vscode-editorWidget-background, transparent);
Expand Down
10 changes: 6 additions & 4 deletions packages/extension/media/ui/atoms/button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ defineStyle(
border: var(--border-width) solid var(--border-color);
border-radius: var(--border-radius); padding: var(--space-xs) var(--space-sm);
cursor: pointer; display: inline-flex; align-items: center; gap: var(--space-xs); }
.btn:hover:not(:disabled) { border-color: var(--color-accent);
background: color-mix(in srgb, var(--color-accent) 8%, transparent); }
.btn:active:not(:disabled) { background: color-mix(in srgb, var(--color-accent) 16%, transparent); }
.btn:focus-visible { outline: 1px solid var(--vscode-focusBorder, var(--color-accent)); outline-offset: 1px; }
/* Hover/active use the ink role (lemon on dark, neutral fg on light) — a
hover border can't be a fill, and the raw lemon would vanish on light. */
.btn:hover:not(:disabled) { border-color: var(--color-accent-ink);
background: color-mix(in srgb, var(--color-accent-ink) 8%, transparent); }
.btn:active:not(:disabled) { background: color-mix(in srgb, var(--color-accent-ink) 16%, transparent); }
.btn:focus-visible { outline: 1px solid var(--vscode-focusBorder, var(--color-accent-ink)); outline-offset: 1px; }
.btn:disabled { opacity: 0.4; cursor: default; }
@media (prefers-reduced-motion: no-preference) {
.btn { transition: border-color 0.15s ease-out, background 0.15s ease-out; }
Expand Down
Loading
Loading