Add typecheck + CI checks, light theme with self-hosted Inter, fix real-model test

- Typecheck: typescript 7 devDependency, `bun run typecheck`; CI gains a
  `check` stage (install, typecheck, fast tests) gating image builds (D-038).
- Light theme: every colour is a token; prefers-color-scheme: light
  overrides them. Inter Variable self-hosted from @fontsource-variable/inter,
  kept out of Bun's CSS inlining and precached (scripts/fonts.ts, D-037).
  Backend select no longer overflows on narrow phones.
- tests/live-real-model.test.ts: time budget scales with clip length and
  en_alien gets a measured WER bar; it had failed since July (D-039).
- Delete the temporary isolate_wer2.ts; fix icon "not checked in" comments
  and the README's model-weights location.
- Agent docs: branch naming, typecheck, CI, Bun CSS gotcha, permissions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas WintherandClaude Opus 5.5 committed 2026-10-29 20:52:13 +01:00
1 parent 0ece4b3a2a
commit 4942461f79
21 files changed
+477 -113

No files matched your search

+159 -37
View File
@@ -1,13 +1,132 @@
/* Inter Variable, self-hosted (OFL-1.1, @fontsource-variable/inter). Served
from /fonts/ rather than bundled — see scripts/fonts.ts. */
/* inter-cyrillic-ext-wght-normal */
@font-face {
font-family: 'Inter Variable';
font-style: normal;
font-display: swap;
font-weight: 100 900;
src: url(fonts/inter-cyrillic-ext-wght-normal.woff2) format("woff2");
unicode-range: U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F;
}
/* inter-cyrillic-wght-normal */
@font-face {
font-family: 'Inter Variable';
font-style: normal;
font-display: swap;
font-weight: 100 900;
src: url(fonts/inter-cyrillic-wght-normal.woff2) format("woff2");
unicode-range: U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116;
}
/* inter-greek-ext-wght-normal */
@font-face {
font-family: 'Inter Variable';
font-style: normal;
font-display: swap;
font-weight: 100 900;
src: url(fonts/inter-greek-ext-wght-normal.woff2) format("woff2");
unicode-range: U+1F00-1FFF;
}
/* inter-greek-wght-normal */
@font-face {
font-family: 'Inter Variable';
font-style: normal;
font-display: swap;
font-weight: 100 900;
src: url(fonts/inter-greek-wght-normal.woff2) format("woff2");
unicode-range: U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF;
}
/* inter-vietnamese-wght-normal */
@font-face {
font-family: 'Inter Variable';
font-style: normal;
font-display: swap;
font-weight: 100 900;
src: url(fonts/inter-vietnamese-wght-normal.woff2) format("woff2");
unicode-range: U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB;
}
/* inter-latin-ext-wght-normal */
@font-face {
font-family: 'Inter Variable';
font-style: normal;
font-display: swap;
font-weight: 100 900;
src: url(fonts/inter-latin-ext-wght-normal.woff2) format("woff2");
unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
/* inter-latin-wght-normal */
@font-face {
font-family: 'Inter Variable';
font-style: normal;
font-display: swap;
font-weight: 100 900;
src: url(fonts/inter-latin-wght-normal.woff2) format("woff2");
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
/* Theme tokens. Dark is the default; light follows the OS setting
(prefers-color-scheme) — there is no in-app toggle. */
:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
font-family: "Inter Variable", Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
color-scheme: light dark;
color: #e8e8e8;
background-color: #16181d;
color: var(--fg);
background-color: var(--bg);
accent-color: var(--accent);
--bg: #16181d;
--fg: #e8e8e8;
--muted: #9aa3b2;
--panel: #1f232b;
--border: #343a46;
--surface-raised: #262b34; /* inputs, selects, inline code */
--surface-selected: #232a38; /* selected / drag-active rows */
--accent: #7aa2f7;
--muted: #9aa3b2;
--on-accent: #16181d;
--success: #9ad6ae;
--success-bg: #1d2b23;
--success-border: #3d6b4f;
--danger: #f2b8b5;
--danger-muted: #d99a97;
--danger-bg: #2a1c1e;
--danger-border: #8b3a3a;
--on-danger: #2a1c1e;
--live: #e0605e;
--shadow: rgba(0, 0, 0, 0.5);
}
@media (prefers-color-scheme: light) {
:root {
--bg: #f5f6f8;
--fg: #1a1d23;
--muted: #5b6372;
--panel: #ffffff;
--border: #d3d8e0;
--surface-raised: #eef0f4;
--surface-selected: #e8eefc;
--accent: #2f5bd3;
--on-accent: #ffffff;
--success: #1d6a3c;
--success-bg: #e6f4eb;
--success-border: #9ccdae;
--danger: #a12e2b;
--danger-muted: #a3403c;
--danger-bg: #fcecea;
--danger-border: #e2a4a1;
--on-danger: #ffffff;
--live: #cf3a37;
--shadow: rgba(20, 24, 33, 0.14);
}
}
::selection {
background: color-mix(in srgb, var(--accent) 35%, transparent);
}
body {
@@ -103,7 +222,7 @@ body {
border: 1px solid var(--border);
border-radius: 14px;
padding: 1rem 1.25rem;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
box-shadow: 0 4px 16px var(--shadow);
z-index: 10;
}
@@ -131,7 +250,7 @@ body {
.auth-tab-selected,
.auth-tab-selected:hover:enabled {
border-color: var(--accent);
background: #232a38;
background: var(--surface-selected);
color: inherit;
}
@@ -150,8 +269,8 @@ body {
}
.auth-panel input {
background: #262b34;
color: #e8e8e8;
background: var(--surface-raised);
color: var(--fg);
border: 1px solid var(--border);
border-radius: 8px;
padding: 0.35rem 0.5rem;
@@ -172,12 +291,12 @@ body {
.auth-error {
margin: 0;
font-size: 0.85rem;
color: #f2b8b5;
color: var(--danger);
}
.auth-submit {
background: var(--accent);
color: #16181d;
color: var(--on-accent);
border: none;
border-radius: 8px;
padding: 0.4rem 0.8rem;
@@ -221,7 +340,7 @@ body {
/* Server engine active — no model download needed on this device (D-020). */
.server-engine-hint {
color: #9ad6ae;
color: var(--success);
}
.device-select,
@@ -231,11 +350,14 @@ body {
gap: 0.5rem;
font-size: 0.85rem;
color: var(--muted);
max-width: 100%;
}
.model-picker select,
.transcription-options select {
background: #262b34;
min-width: 0; /* shrink inside narrow (mobile) panels instead of overflowing */
max-width: 100%;
background: var(--surface-raised);
color: inherit;
border: 1px solid var(--border);
border-radius: 8px;
@@ -285,7 +407,7 @@ body {
.model-option-selected,
.model-group:not(:disabled) .model-option-selected:hover {
border-color: var(--accent);
background: #232a38;
background: var(--surface-selected);
}
.model-group:disabled .model-option {
@@ -314,9 +436,9 @@ body {
}
.model-badge {
border: 1px solid #3d6b4f;
background: #1d2b23;
color: #9ad6ae;
border: 1px solid var(--success-border);
background: var(--success-bg);
color: var(--success);
border-radius: 999px;
padding: 0.1rem 0.55rem;
font-size: 0.75rem;
@@ -337,8 +459,8 @@ body {
}
.model-download-button:hover:enabled {
border-color: #3d6b4f;
color: #9ad6ae;
border-color: var(--success-border);
color: var(--success);
}
.model-download-button:disabled {
@@ -354,7 +476,7 @@ body {
}
.offline-status-ready {
color: #9ad6ae;
color: var(--success);
}
.update-toast {
@@ -369,13 +491,13 @@ body {
border: 1px solid var(--accent);
border-radius: 8px;
padding: 0.6rem 1rem;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
box-shadow: 0 4px 16px var(--shadow);
z-index: 10;
}
.update-toast button {
background: var(--accent);
color: #16181d;
color: var(--on-accent);
border: none;
border-radius: 6px;
padding: 0.3rem 0.8rem;
@@ -449,7 +571,7 @@ body {
.dropzone-active {
border-color: var(--accent);
background: #232a38;
background: var(--surface-selected);
}
.dropzone-disabled {
@@ -500,7 +622,7 @@ body {
.live-button-active,
.live-button-active:hover:enabled {
border-color: #e0605e;
border-color: var(--live);
}
.live-dot {
@@ -508,7 +630,7 @@ body {
width: 0.6rem;
height: 0.6rem;
border-radius: 999px;
background: #e0605e;
background: var(--live);
animation: pulse 1.2s ease-in-out infinite;
}
@@ -545,17 +667,17 @@ body {
}
.cancel-button:hover {
border-color: #8b3a3a;
color: #f2b8b5;
border-color: var(--danger-border);
color: var(--danger);
}
.error {
margin: 0;
padding: 0.75rem 1rem;
border-radius: 10px;
border: 1px solid #8b3a3a;
background: #2a1c1e;
color: #f2b8b5;
border: 1px solid var(--danger-border);
background: var(--danger-bg);
color: var(--danger);
}
.error-message {
@@ -565,14 +687,14 @@ body {
.error-suggestion {
margin: 0.4rem 0 0;
font-size: 0.85rem;
color: #d99a97;
color: var(--danger-muted);
}
.error-retry-button {
margin-top: 0.6rem;
border: 1px solid #f2b8b5;
border: 1px solid var(--danger);
background: transparent;
color: #f2b8b5;
color: var(--danger);
border-radius: 8px;
padding: 0.3rem 0.9rem;
font-size: 0.85rem;
@@ -581,8 +703,8 @@ body {
}
.error-retry-button:hover {
background: #f2b8b5;
color: #2a1c1e;
background: var(--danger);
color: var(--on-danger);
}
/* --- ModelLoadProgress --- */
@@ -772,7 +894,7 @@ body {
code {
font-family: ui-monospace, monospace;
background: #262b34;
background: var(--surface-raised);
padding: 0.1em 0.35em;
border-radius: 5px;
}
@@ -868,8 +990,8 @@ code {
}
.storage-delete:hover:enabled {
border-color: #8b3a3a;
color: #f2b8b5;
border-color: var(--danger-border);
color: var(--danger);
}
.storage-delete:disabled {