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
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,20 @@ updater sees v3.1.5 as the latest release and does not offer it to the beta as a
- **The selected scene's info line** was 3.9:1 in Light and 4.1–4.4:1
in Midnight and CaYaDev. On the selected row's accent tint it now uses the secondary text
colour, and the contrast rules cover body and secondary text on selected rows.
- **The self-test scans a populated panel [777].**
- The self-test's settings had no saved scenes, no clip cells with a preview and no slot without
a source. So the untranslated-text scan and the contrast audit never drew those screens. The
selected scene's 3.9:1 label above was found by hand.
- The self-test now adds representative content to the panel in memory:
- three saved scenes (white, black and gradient backgrounds) and a selected one that changes
nothing;
- clip slots that reference them;
- a white image, white and black colour slots, and a slot with no source.
- It also opens every fold, and puts the panel back afterwards.
- It counts what it actually scanned and fails if the selected row, four preview cells or the
sourceless slot were not drawn. On the first run they were not: an earlier step leaves the
deck at 2×2.
- Each theme now measures about 3,040 texts, with none below the threshold.
- **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-3229%20passing-2ea043.svg)](#tests)
[![Tests](https://img.shields.io/badge/tests-3230%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 @@ -1746,7 +1746,7 @@ npm test
npm start -- --smoke
```

**3229 unit tests, all passing.** They are written to check answers, not to exercise lines:
**3230 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-3229%20geçiyor-2ea043.svg)](#testler)
[![Test](https://img.shields.io/badge/test-3230%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 @@ -1749,7 +1749,7 @@ npm test
npm start -- --smoke
```

**3229 birim testi, hepsi geçiyor.** Satır çalıştırmak için değil, cevap denetlemek için yazıldılar:
**3230 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
2 changes: 1 addition & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ npm test
npm start -- --smoke
```

- **3229 unit tests, all passing** on `main`. 703 of those shipped in v3.1.0;
- **3230 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
87 changes: 85 additions & 2 deletions src/main/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -7070,6 +7070,55 @@ async function runSmoke() {
if (opened !== 'açıldı') errors.push('i18n scan could not open timeline/clipdeck: ' + opened);
await wait(900);

/* DOLU PANEL (#777). Öz testin ayarlarında kayıtlı sahne, önizlemeli
klip hücresi ya da kaynağı seçilmemiş yuva yok; çeviri ve karşıtlık
taramaları o ekranları hiç görmüyordu (seçili sahnenin alt yazısı
Aydınlık'ta 3,9:1 kalmıştı, #775). Panelin kendi nesnesine temsilî
içerik eklenir, seçili sahne görüntüyü değiştirmeyen bir kopyadır;
tema adımından sonra eski hâline döner. Disk zaten korunuyor. */
const populated = await awc3.executeJavaScript(`(function(){
var P = window.SVPanel; if (!P) return { error: 'panel yok' };
var c = P.cfg();
// Önceki adımlar başka bir desteyi etkin bırakabiliyor: görünen deste
var decks = (c.clipdeck && c.clipdeck.decks) || [];
var deck = decks.filter(function (d) { return d && d.id === c.clipdeck.activeDeck; })[0] || decks[0];
if (!deck) return { error: 'deste yok' };
window.__smokePopulateDeck = deck.id;
window.__smokePopulateBackup = JSON.stringify({ scenes: c.scenes || [], slots: deck.slots || [], rows: deck.rows, cols: deck.cols, active: c._activeSceneId || null });
// Önceki deste adımı ızgarayı 2x2 bırakıyor; yuvalar ızgaranın içinde kalmalı
deck.rows = Math.max(+deck.rows || 0, 3);
deck.cols = Math.max(+deck.cols || 0, 4);
var same = JSON.parse(JSON.stringify(c)); delete same.scenes;
var bgScene = function (id, name, bg) {
var d = JSON.parse(JSON.stringify(same));
d.background = Object.assign({}, d.background, bg);
return { id: id, name: name, data: d };
};
c.scenes = (c.scenes || []).concat([
{ id: 'smoke-same', name: 'Smoke current', data: same },
bgScene('smoke-white', 'Smoke white', { type: 'solid', solidColor: '#ffffff' }),
bgScene('smoke-black', 'Smoke black', { type: 'solid', solidColor: '#000000' }),
bgScene('smoke-grad', 'Smoke gradient', { type: 'gradient', gradient: { colors: ['#ffffff', '#ffe066', '#00ffff'] } }),
]);
var img = 'data:image/svg+xml,' + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8"><rect width="8" height="8" fill="white"/></svg>');
deck.slots = [
{ row: 0, col: 0, name: 'White scene', type: 'scene', ref: 'smoke-white' },
{ row: 0, col: 1, name: 'Black scene', type: 'scene', ref: 'smoke-black' },
{ row: 0, col: 2, name: 'Gradient scene', type: 'scene', ref: 'smoke-grad' },
{ row: 0, col: 3, name: 'White image', type: 'image', ref: img },
{ row: 1, col: 0, name: 'White slot', type: 'palette', ref: 'x', color: '#ffffff' },
{ row: 1, col: 1, name: 'Black slot', type: 'palette', ref: 'x', color: '#000000' },
{ row: 1, col: 2, name: 'No source', type: 'video', ref: '' },
];
P.applyScene('smoke-same');
P.rerender();
return { scenes: c.scenes.length, slots: deck.slots.length };
})()`);
console.log('[SMOKE] dolu panel: ' + JSON.stringify(populated));
if (!populated || populated.error) errors.push('populated panel: ' + ((populated && populated.error) || 'no result'));
await wait(700);
const openFolds = "(function(){var h=document.querySelectorAll('#sections .fold-head:not(.open)');for(var i=0;i<h.length;i++)h[i].click();return h.length;})()";

const cats = await awc3.executeJavaScript(
"Array.from(document.querySelectorAll('.nav-item .nav-label')).map(function(n){return n.textContent;})"
);
Expand All @@ -7079,6 +7128,8 @@ async function runSmoke() {
for (let i = 0; i < cats.length; i++) {
await awc3.executeJavaScript("(function(){var b=document.querySelectorAll('.nav-item')[" + i + "]; if(b) b.click();})()");
await wait(340);
// Katlanır bölümler kapalıyken içerikleri DOM'da yok
if (await awc3.executeJavaScript(openFolds)) await wait(300);
const found = await awc3.executeJavaScript(`(function(){
var skip = 'source-name,audio-state,scene-name,up-name,map-signal,url-field,client-addr,gen-pair,np-live'.split(',');
var out = [];
Expand Down Expand Up @@ -7165,16 +7216,28 @@ async function runSmoke() {
const original = U.choice();
const cats = Array.from(document.querySelectorAll('[data-cat]')).map((b) => b.dataset.cat);
const out = [];
// Dolu panelin ekranları gerçekten tarandı mı (#777)
const seen = { active: false, thumbs: 0, noref: 0, folds: 0 };
for (const t of UT.THEMES) {
click('[data-cat="settings"]'); await sleep(450);
if (!click('.ui-theme-opt[data-theme="' + t.id + '"]')) { out.push({ theme: t.id, error: 'not in the picker' }); continue; }
await sleep(250);
/* Her ayar değişikliği seçili sahne vurgusunu kaldırıyor (bilerek):
dolu panelin seçili satırı her temada yeniden seçilir. */
if (window.__smokePopulateBackup && window.SVPanel) { window.SVPanel.applyScene('smoke-same'); await sleep(250); }
let checked = 0, min = Infinity;
const fails = [];
for (const c of cats) {
click('[data-cat="' + c + '"]'); await sleep(400);
// Katlanır bölümlerin içeriği kapalıyken DOM'da yok
const folds = document.querySelectorAll('#sections .fold-head:not(.open)');
folds.forEach((h) => h.click());
if (folds.length) { seen.folds += folds.length; await sleep(250); }
if (document.querySelector('#sceneList .scene-item.active')) seen.active = true;
seen.thumbs = Math.max(seen.thumbs, document.querySelectorAll('.cd-cell > .cd-thumb').length);
seen.noref = Math.max(seen.noref, document.querySelectorAll('.cd-cell.noref').length);
const s = document.getElementById('sections');
const steps = Math.min(8, Math.ceil(s.scrollHeight / Math.max(1, s.clientHeight)));
const steps = Math.min(14, Math.ceil(s.scrollHeight / Math.max(1, s.clientHeight)));
for (let k = 0; k < steps; k++) {
s.scrollTop = k * s.clientHeight; await sleep(100);
const r = A.audit(document, window, { pageBg: getComputedStyle(document.body).backgroundColor, aaa: !!U.current().aaa });
Expand All @@ -7188,7 +7251,7 @@ async function runSmoke() {
click('[data-cat="settings"]'); await sleep(350);
click('.ui-theme-opt[data-theme="' + original + '"]');
await sleep(200);
return { themes: out, restored: U.choice() === original };
return { themes: out, restored: U.choice() === original, seen };
})()`);
if (!report || report.error) {
errors.push('ui themes: ' + ((report && report.error) || 'no report'));
Expand All @@ -7202,10 +7265,30 @@ async function runSmoke() {
if (r.failCount) errors.push('ui theme ' + r.theme + ': ' + r.failCount + ' text element(s) below the contrast threshold');
});
if (!report.restored) errors.push('ui themes: the user\'s theme was not restored');
console.log('[SMOKE] dolu panel tarandı: ' + JSON.stringify(report.seen));
const sn = report.seen || {};
if (!sn.active || sn.thumbs < 4 || sn.noref < 1) {
errors.push('ui themes: the populated panel was not scanned (' + JSON.stringify(sn) + ')');
}
}
} catch (e) {
errors.push('ui themes: ' + (e && e.message ? e.message : e));
}
// Dolu panel eski hâline (sahneler, yuvalar, seçili sahne)
try {
await awc4.executeJavaScript(`(function(){
var raw = window.__smokePopulateBackup; if (!raw || !window.SVPanel) return false;
var b = JSON.parse(raw), c = window.SVPanel.cfg();
c.scenes = b.scenes;
var d = ((c.clipdeck && c.clipdeck.decks) || []).filter(function (x) { return x && x.id === window.__smokePopulateDeck; })[0];
if (d) { d.slots = b.slots; d.rows = b.rows; d.cols = b.cols; }
delete window.__smokePopulateDeck;
c._activeSceneId = b.active;
delete window.__smokePopulateBackup;
window.SVPanel.apply();
return true;
})()`);
} catch (e) { /* panel kapanıyor */ }
}

/* --- Panel ekran görüntüleri (--smoke-shots) ---
Expand Down
25 changes: 25 additions & 0 deletions tests/ui-themes.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,31 @@ test('öz test her temayı panelin seçicisinden tarıyor ve kullanıcının tem
assert.match(step, /restored/);
});

/* Dolu panel (#777): öz testin ayarlarında kayıtlı sahne ve önizlemeli
hücre yoktu; tarama o ekranları hiç görmüyordu. İçerik ekleniyor, gerçekten
tarandığı sayılıyor ve sonra geri alınıyor. */
test('öz test çeviri ve karşıtlık taramalarını dolu panelde yapıyor', () => {
const m = read('src/main/main.js');
const p = m.indexOf('DOLU PANEL (#777)');
assert.ok(p > 0, 'dolu panel adımı');
const pop = m.slice(p, p + 4000);
['smoke-same', 'smoke-white', 'smoke-black', 'smoke-grad'].forEach((id) => assert.ok(pop.includes(id), id));
assert.match(pop, /type: 'image', ref: img/);
assert.match(pop, /ref: ''/, 'kaynağı seçilmemiş yuva');
assert.match(pop, /P\.applyScene\('smoke-same'\)/, 'seçili sahne satırı');
assert.match(pop, /c\.clipdeck\.activeDeck/, 'görünen desteye yazılıyor');
assert.match(pop, /deck\.cols = Math\.max/, 'yuvalar ızgaranın içinde');
// Çeviri taraması katlanır bölümleri açıyor
assert.match(m, /if \(await awc3\.executeJavaScript\(openFolds\)\)/);
// Karşıtlık taraması kapsamı sayıyor ve eksikse düşüyor
const t = m.indexOf('Arayüz temaları: ekrandaki yazıların karşıtlığı (#770)');
const step = m.slice(t, t + 7000);
assert.match(step, /\.fold-head:not\(\.open\)/);
assert.match(step, /window\.SVPanel\.applyScene\('smoke-same'\)/);
assert.match(step, /!sn\.active \|\| sn\.thumbs < 4 \|\| sn\.noref < 1/);
assert.match(step, /__smokePopulateBackup/, 'içerik geri alınıyor');
});

test('süs ayraçları ekran okuyucudan ve ölçümden gizli', () => {
const dir = path.join(root, 'src', 'admin');
fs.readdirSync(dir).filter((f) => f.endsWith('.js')).forEach((f) => {
Expand Down
Loading