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
34 changes: 28 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,34 @@ GitHub. The full reasoning and the measurements behind each change are in [ROADM
- The self-test selects every theme from the picker, walks every category, and measures the
colour Chromium actually draws for each visible text against its background: about 2,600
texts per theme, none below the threshold.
- **Three CaYaDev colours moved so the default theme passes the same test.**
- The small hint text was 3.4–4.4:1 on cards and is now at least 4.5:1.
- Code comments in the shader editor were 3.3:1.
- White text on the solid red danger button was 3.9:1.
- The end of the red gradient on filled buttons is slightly deeper, so white text reads in the
middle of the gradient too.
- **CaYaDev looks the same, with these visible changes.**
- Four colours moved so the default theme passes the same test:
- the small hint text was 3.4–4.4:1 on cards and is now at least 4.5:1;
- code comments in the shader editor were 3.3:1;
- white text on the solid red danger button was 3.9:1;
- the end of the red gradient on filled buttons is slightly deeper, so white text reads in
the middle of the gradient too.
- Near-identical shades became one per role. Error text had six reds across the panel and
Studio, and now uses one. The status greens and ambers each come down to one fill shade and
one text shade.
- The Performance View had its own neutral greys. It now uses the panel's surfaces.
- The lyric editor and the MCP setup snippets use the code editor's background and text colour.
- Studio's solid danger button is the panel's red.
- The projection-mapping guide line is the panel's info blue instead of cyan. A selected tempo
marker on the timeline is drawn in the strong text colour.
- **Clip Deck cells stay readable in any slot colour.**
- A cell's background is tinted with the slot colour. On a white slot, the small info line fell
to 3.3:1 on hover. The tint is now 10%, and 12% on hover, with a stronger border showing the
hover.
- Countdown numbers use the readable amber. They were 3.5:1 in Light.
- A slot with no source was faded with opacity, so its name fell to 3.3:1. It now has a dashed
border, no tint and secondary text.
- The empty-cell "+" was drawn in the line colour, at 1.5:1. It is now secondary text.
- The Auto VJ conflict note uses the amber meant for text, which is paler in CaYaDev.
- A test checks every text in a cell, in every state, on white, black, grey and the six primary
and secondary colours. The self-test now measures clip cells too and reads `color-mix()`
backgrounds. Before, it skipped them and measured the text against the card underneath.
Only cells that show a scene preview are left out, because their text sits on a picture.
- **Two labels were unreadable in every theme.** The empty side of the A/B crossfader and the
"built-in" tag in Studio's list were dimmed with opacity to 2.9:1 and 3.7:1. They now use the
secondary text colour. The decorative "·" separators in status lines are hidden from screen
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ layers and **40 GPU effects**, an **OBS overlay**, **Spout / Syphon**, **project
[![Downloads](https://img.shields.io/github/downloads/CaYatur/SoundVisualizer/total?label=downloads)](https://github.com/CaYatur/SoundVisualizer/releases)
[![License: MIT](https://img.shields.io/badge/License-MIT-e11d2a.svg)](LICENSE)
[![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-111997.svg)](#download)
[![Tests](https://img.shields.io/badge/tests-3222%20passing-2ea043.svg)](#tests)
[![Tests](https://img.shields.io/badge/tests-3223%20passing-2ea043.svg)](#tests)
[![Electron](https://img.shields.io/badge/Electron-43-47848F.svg)](https://www.electronjs.org/)

<a href="https://github.com/CaYatur/SoundVisualizer/releases/latest"><img src="https://img.shields.io/badge/Download-Windows-0a84ff?style=for-the-badge" alt="Download for Windows" /></a>
Expand Down Expand Up @@ -1744,7 +1744,7 @@ npm test
npm start -- --smoke
```

**3222 unit tests, all passing.** They are written to check answers, not to exercise lines:
**3223 unit tests, all passing.** They are written to check answers, not to exercise lines:

- **Formulas** are checked against values derived by hand from their definitions — Viviani's curve
staying on its sphere, the torus tube radius, Chladni's m↔n antisymmetry, every attractor staying
Expand Down
4 changes: 2 additions & 2 deletions README.tr.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ destesi**, ve **MCP üzerinden yapay zekâ kontrolü**.
[![İndirme](https://img.shields.io/github/downloads/CaYatur/SoundVisualizer/total?label=indirme)](https://github.com/CaYatur/SoundVisualizer/releases)
[![Lisans: MIT](https://img.shields.io/badge/Lisans-MIT-e11d2a.svg)](LICENSE)
[![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-111997.svg)](#hızlı-başlangıç)
[![Test](https://img.shields.io/badge/test-3222%20geçiyor-2ea043.svg)](#testler)
[![Test](https://img.shields.io/badge/test-3223%20geçiyor-2ea043.svg)](#testler)
[![Electron](https://img.shields.io/badge/Electron-43-47848F.svg)](https://www.electronjs.org/)

<a href="https://github.com/CaYatur/SoundVisualizer/releases/latest"><img src="https://img.shields.io/badge/%C4%B0ndir-Windows-0a84ff?style=for-the-badge" alt="Windows için indir" /></a>
Expand Down Expand Up @@ -1747,7 +1747,7 @@ npm test
npm start -- --smoke
```

**3222 birim testi, hepsi geçiyor.** Satır çalıştırmak için değil, cevap denetlemek için yazıldılar:
**3223 birim testi, hepsi geçiyor.** Satır çalıştırmak için değil, cevap denetlemek için yazıldılar:

- **Formüller**, tanımlarından elle türetilmiş değerlerle sınanıyor — Viviani eğrisinin küre üzerinde
kalması, simidin boru yarıçapı, Chladni'nin m↔n antisimetrisi, her çekicinin sınırlı kalması ve görüş
Expand Down
20 changes: 18 additions & 2 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ npm test
npm start -- --smoke
```

- **3222 unit tests, all passing** on `main`. 703 of those shipped in v3.1.0;
- **3223 unit tests, all passing** on `main`. 703 of those shipped in v3.1.0;
105 came with v3.1.1; 163 came with v3.1.2; 157 came with v3.1.3 — 1128 at
that tag — 469 more with v3.1.4, most of them from the MilkDrop work — 1597 at
that tag — 1402 more with v3.1.5 — 2999 at that tag — and 27
Expand Down Expand Up @@ -3591,7 +3591,23 @@ The panel had one look. It now has seven themes and Device default, chosen under
- `--accent2` is both heading text and the end of the button gradient. It cannot be both: a red that reads at 4.5:1 on a dark card cannot carry white text at 4.5:1. So the gradient end became its own token, `--accent-grad`.
- **Measured before and after in CaYaDev.**
- Panel screenshots of every category in both languages, taken before any CSS change, were compared pixel by pixel.
- With the four intentional changes set back to their old values, the remaining differences were live content (BPM, the app list, meters), the new picker, and one consolidated green on the lighting status.
- With the four contrast fixes set back to their old values, the remaining differences in those screenshots were live content (BPM, the app list, meters), the new picker, and one consolidated green on the lighting status.
- The screenshots did not cover every surface. Reading the old CSS afterwards found more visible CaYaDev changes:
- near-identical status shades merged: six error reds became `--danger-text`, and greens and ambers became one fill and one text shade each;
- the Performance View moved from its own neutral greys to the panel's surfaces;
- the lyric editor and MCP snippets moved to the code editor's colours;
- Studio's solid danger button became the panel's red;
- the mapping guide line became info blue;
- the selected tempo marker became the strong text colour.

The CHANGELOG lists them.
- **Clip cells, checked afterwards.** The Performance View, the Auto VJ conflict note, the lyric editor and the MCP setup were opened in all seven themes and measured. The clip cells were not covered by the self-test, which skipped them because the background is the user's slot colour.
- Measured with them included, a white slot dropped the small info line to 3.3:1 on hover in CaYaDev.
- In Light, the countdown was 3.5:1.
- A slot with no source was faded with opacity, which brought its name to 3.3:1.
- The tint is now 10% (12% on hover), the countdowns use `--warn-text`, and the sourceless slot is dimmed with colour instead of opacity.
- A test measures every text in a cell, in every state, against nine extreme slot colours, and forbids opacity on the cell.
- The self-test also read `color-mix()` backgrounds (`color(srgb …)`) as nothing and measured the text against the card underneath. It now parses them and measures clip cells. Only cells with a scene preview are skipped.
- **Tests that fail on misuse.**
- Every theme defines exactly the token set.
- `:root` equals the CaYaDev table.
Expand Down
18 changes: 11 additions & 7 deletions src/admin/admin.css
Original file line number Diff line number Diff line change
Expand Up @@ -1354,8 +1354,11 @@ input[type=color].tl-swatch.big { width: 34px; height: 24px; }
.cd-plus { font-size: 18px; line-height: 1; color: var(--muted2); transition: color .12s, transform .12s; }
.cd-cell.empty:hover { border-color: var(--line2); background: rgb(var(--fg-rgb) / .02); }
.cd-cell.empty:hover .cd-plus { color: var(--text); transform: scale(1.15); }
.cd-cell.filled { border: 1px solid color-mix(in srgb, var(--slot) 45%, var(--line)); background: color-mix(in srgb, var(--slot) 14%, var(--card)); color: var(--text); }
.cd-cell.filled:hover { background: color-mix(in srgb, var(--slot) 22%, var(--card)); }
/* Zemin, kullanıcının yuva rengiyle boyanıyor: beyaz ya da siyah bir yuvada
da ikincil yazı 4.5:1'in altına düşmesin diye karışım en çok %12 (#770).
Üzerine gelmeyi kenar da gösteriyor. */
.cd-cell.filled { border: 1px solid color-mix(in srgb, var(--slot) 45%, var(--line)); background: color-mix(in srgb, var(--slot) 10%, var(--card)); color: var(--text); }
.cd-cell.filled:hover { background: color-mix(in srgb, var(--slot) 12%, var(--card)); border-color: color-mix(in srgb, var(--slot) 75%, var(--line)); }
.cd-color { position: absolute; left: 0; top: 0; bottom: 0; width: 4px; }
.cd-name { font-weight: 600; font-size: 11.5px; }
.cd-meta { font-size: 10px; color: var(--muted); min-height: 12px; }
Expand All @@ -1374,7 +1377,7 @@ input[type=color].tl-swatch.big { width: 34px; height: 24px; }
.cd-cell.sel { outline: 2px solid var(--accent); outline-offset: 1px; }
@media (prefers-reduced-motion: reduce) { .cd-cell.armed { animation: none; } }
.cd-name, .cd-meta { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cd-count { position: absolute; right: 5px; top: 3px; font-size: 10px; font-weight: 700; color: var(--warn);
.cd-count { position: absolute; right: 5px; top: 3px; font-size: 10px; font-weight: 700; color: var(--warn-text);
font-variant-numeric: tabular-nums; }
.cd-editor { border-top: 1px solid var(--line); padding-top: 8px; margin-top: 8px; }
.cd-editor-head { display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 700; color: var(--text); margin-bottom: 6px; }
Expand Down Expand Up @@ -1432,7 +1435,7 @@ input[type=color].tl-swatch.big { width: 34px; height: 24px; }
.perf-cell.active { border-color: var(--cue-live); background: color-mix(in srgb, var(--cue-live) 22%, var(--bg2)); color: var(--text-strong); }
.perf-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.perf-count {
position: absolute; right: 8px; bottom: 4px; font-size: 13px; color: var(--cue-armed);
position: absolute; right: 8px; bottom: 4px; font-size: 13px; color: var(--warn-text);
font-variant-numeric: tabular-nums;
}
.perf-hint { color: var(--muted2); font-size: 12px; text-align: center; }
Expand All @@ -1449,9 +1452,10 @@ input[type=color].tl-swatch.big { width: 34px; height: 24px; }
/* Çakışma uyarısı — engellemiyoruz ama görünür olmalı. */
.settings-io-note.warn { color: var(--warn-text); border-left: 2px solid var(--warn); padding-left: 8px; }

/* Kaynağı seçilmemiş yuva: dolu görünüyor ama ateşlenemez. Kesikli kenar
ve soluk metin bunu ateşlemeden önce belli eder. */
.cd-cell.filled.noref { border-style: dashed; opacity: .65; }
/* Kaynağı seçilmemiş yuva: dolu görünüyor ama ateşlenemez. Kesikli kenar,
boyasız zemin ve ikincil yazı bunu ateşlemeden önce belli eder. Opaklık
adı 3.3:1'e düşürüyordu; adın okunması gerekiyor ki düzeltilsin (#770). */
.cd-cell.filled.noref { border-style: dashed; background: var(--card); color: var(--muted); }


/* OpenRGB aygıt listesi. Sürülemeyen aygıtlar sönük çizilir: renk kabul
Expand Down
25 changes: 18 additions & 7 deletions src/shared/ui-contrast-audit.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,26 @@
Eşik: 4.5:1; büyük yazı (24 px ya da 18.66 px kalın) 3:1. AAA temada 7 ve
4.5. */
(function () {
/* color-mix() sonucu `color(srgb 0.1 0.2 0.3 / 0.5)` olarak hesaplanır
(0–1 arası). Çözülemeyen zemin sessizce atlanıyor ve yazı alttaki
karta göre ölçülüyordu: kullanıcı renkli klip hücreleri böyle geçti. */
const parse = (s) => {
const m = /rgba?\(\s*([\d.]+)[,\s]+([\d.]+)[,\s]+([\d.]+)(?:\s*[,/]\s*([\d.]+%?))?\s*\)/.exec(String(s || ''));
const str = String(s || '');
const alpha = (v) => {
let a = v === undefined ? 1 : v.endsWith('%') ? parseFloat(v) / 100 : parseFloat(v);
return Number.isFinite(a) ? a : 1;
};
const c = /color\(srgb\s+([-\d.e]+)\s+([-\d.e]+)\s+([-\d.e]+)(?:\s*\/\s*([\d.]+%?))?\s*\)/.exec(str);
if (c) return [+c[1] * 255, +c[2] * 255, +c[3] * 255, alpha(c[4])];
const m = /rgba?\(\s*([\d.]+)[,\s]+([\d.]+)[,\s]+([\d.]+)(?:\s*[,/]\s*([\d.]+%?))?\s*\)/.exec(str);
if (!m) return null;
let a = m[4] === undefined ? 1 : m[4].endsWith('%') ? parseFloat(m[4]) / 100 : parseFloat(m[4]);
if (!Number.isFinite(a)) a = 1;
return [+m[1], +m[2], +m[3], a];
return [+m[1], +m[2], +m[3], alpha(m[4])];
};

// Geçişin renk durakları (hesaplanan değer rgb()/rgba() biçiminde gelir)
// Geçişin renk durakları (hesaplanan değer rgb()/rgba()/color() biçiminde gelir)
function gradientStops(img) {
if (!img || img === 'none' || img.indexOf('gradient') < 0 || img.indexOf('url(') >= 0) return null;
const re = /rgba?\([^)]*\)/g;
const re = /(?:rgba?|color)\([^)]*\)/g;
const stops = [];
let m;
while ((m = re.exec(img))) {
Expand Down Expand Up @@ -91,7 +99,10 @@
const SKIP = [
'.preview-stage', '.studio-preview', '.md-thumb-box', '.logo-lib-thumb', '.img-thumb',
'.scene-thumb', '.layer-preview', '.md-cell .md-fav', '.preset', '.up-swatch',
'.tpl-swatch', '.tl-swatch', '.cd-cell', '.perf-cell', '[aria-hidden="true"]',
/* Klip hücreleri ölçülür (zemin kullanıcının rengiyle boyalı ama oran
her renkte yetecek kadar düşük); yalnız sahne önizlemesi taşıyanlar
görüntü üstünde sayılır. */
'.tpl-swatch', '.tl-swatch', '.cd-cell:has(> .cd-thumb)', '.perf-cell:has(> .perf-thumb)', '[aria-hidden="true"]',
'.ui-theme-preview',
].join(',');

Expand Down
Loading
Loading