# Jak přeměnit téma pro hudební přehrávač na runtime doplněk s WASM a audio-reaktivními efekty
Projekt začal jako pokus o opravu rozbitého tématu pro populární Electron přehrávač, ale skončil vytvořením plnohodnotného runtime doplňku ChromaSync — s dynamickou barevnou adaptací, audio-reaktivní pulzací, Zen Mode a výpočetním jádrem na WebAssembly. Všechno to běží na PulseSync — platformě pro modifikaci rozhraní přes JS/CSS, kde autor narazil na omezení frameworku a potřebu škálovat logiku mimo CSS.
Architektura: od tématu k orchestrátoru
ChromaSync byl původně navržený jako vizuální záplata, ale rychle přerostl v mnohovrstvý systém. Klíčové komponenty:
metadata.json— vstupní bod pro PulseSync;handleEvents.json— deklarativní popis nastavení;script.js— centrální orchestrátor stavu a efektů;style.css— základní styly a animace;- WASM modul — jádro pro náročné výpočty (pulzace, vyhlazování);
- Backend vrstva — volitelné síťové funkce.
Propojení PulseSync → handleEvents → script.js → DOM/CSS/WASM umožňuje dynamicky aplikovat změny bez přenačítání. Například při změně skladby skript extrahuje dominantní barvy obálky, předá je do CSS proměnných a současně spustí audio-reaktivní pulzaci přes WASM jádro. Vše probíhá v reálném čase bez znatelných zpoždění.
Systém nastavení: 70 parametrů pod kontrolou
PulseSync umožňuje uživatelům nastavovat doplňky bez úprav kódu. Každé nastavení je popsáno v JSON struktuře s povinným id, podle kterého se spojuje s runtime logikou. Příklad konfigurace režimu změny pozadí:
{
"id": "backgroundTrackTransitionMode",
"name": "Withmena fona (trek)",
"description": "Effekt switching fonovoy oblozhki when smene treka: fade (plavnaya podmena) or slide (staraya uezzhaet vlevo, novaya vezzhaet right).",
"type": "selector",
"selected": "1",
"options": [
{
"name": "Fade (by umolchaniyu)",
"id": "fade"
},
{
"name": "Slide (left/right)",
"id": "slide-horizontal"
}
],
"defaultParameter": "fade"
}
Když takových parametrů dosáhne 70, vzniká nutnost normalizace stavu. script.js tuto úlohu přebírá: sbírá hodnoty, validuje je, převádí do jednotného state objektu a aplikuje na rozhraní. Bez této vrstvy by systém byl neovladatelný — zejména při vzájemně závislých nastaveních, například kdy zapnutí „Zen Mode“ automaticky vypne částice a sníží intenzitu pulzace.
Evoluce script.js: od 700 řádků k monolitu
Původně byl script.js jednoduchý soubor s 700 řádky. Dnes překročil 8000 řádků — ne kvůli nafouknutí, ale kvůli potřebě koordinovat stále více podsystémů. Tento soubor plní roli orchestrátora:
- Získává a normalizuje nastavení z PulseSync;
- Sleduje stav přehrávače (skladba, průběh, fullscreen);
- Řídí DOM elementy a CSS proměnné;
- Spouští a zastavuje audio-reaktivní efekty;
- Volá WASM funkce pro matematické výpočty;
- Zpracovává události myši a klávesnice pro paralaxu a interaktivitu.
Příklad rané logiky — paralaxa pozadí na základě pohybu myši:
const handleParallax = (event) => {
const offsetX = event.clientX / window.innerWidth - 0.5;
const offsetY = event.clientY / window.innerHeight - 0.5;
const posX = `calc(50% + ${offsetX * 25}px)`;
const posY = `calc(50% + ${offsetY * 25}px)`;
requestAnimationFrame(() => {
bgLayer1.style.backgroundPosition = `${posX} ${posY}`;
bgLayer2.style.backgroundPosition = `${posX} ${posY}`;
});
};
Později přibyla složitější funkce — například dynamické extrahování barevné palety z obálky skladby:
const applyChameleonStyles = (palette, sourceChoice) => {
if (settings.useCustomAccentColor?.value) {
document.documentElement.style.setProperty(
'--accent-color',
settings.customAccentColor?.value || '#8a63b3'
);
return;
}
const swatch = palette?.[sourceChoice] || palette?.Vibrant;
if (!swatch) return;
document.documentElement.style.setProperty('--accent-color', swatch.getHex());
};
WASM: když JavaScript už nestíhá
Přelomový moment nastal, když pulzace přestala být jednoduchou animací a proměnila se ve výpočetně náročný systém s několika režimy, vyhlazováním a spouštěči. JavaScript nezvládal požadovanou výkonnost — obzvláště na slabých zařízeních. Řešení — přesunout jádro do Rust/WASM.
Načítání modulu:
async function loadPulseWasm() {
const res = await fetch('/api/chromasync/rust', { cache: 'no-store' });
const buf = await res.arrayBuffer();
const { instance } = await WebAssembly.instantiate(buf);
return instance.exports;
}
Příklad exportované funkce v Rust:
#[no_mangle]
pub extern "C" fn c2(prev: f32, current: f32, weight: f32) -> f32 {
prev * weight + current * (1.0 - weight)
}
WASM se používá pro:
- Výpočet amplitudy zvukové stopy v reálném čase;
- Plynulé vyhlazování přechodů mezi snímky;
- Optimalizaci frekvence volání animačních frameů;
- Izolaci těžké logiky od hlavního UI vlákna.
Výsledek — stabilních 60 FPS i při aktivních efektech a složitých filtrech jako pixelizace nebo šum.
Co je důležité
- PulseSync — platforma umožňující proměnit témata v plnohodnotné runtime doplňky bez přístupu k zdrojovému kódu přehrávače.
- WASM je klíčový pro audio-reaktivní efekty: zajišťuje výkonnost nedosažitelnou čistým JavaScriptem.
- script.js — nejen skript, ale orchestrátor spojující nastavení, DOM, CSS a výpočetní jádro.
- Dynamická barevná adaptace z obálky skladby se realizuje runtime analýzou obrázku a vkládáním CSS proměnných.
- Architektura projektu umožňuje škálovat: nové efekty se přidávají jako nezávislé moduly bez narušení stávající logiky.
Optimalizace: krása nesmí stát FPS
Každý nový efekt představuje riziko poklesu výkonu. Autor věnuje profilování a optimalizaci zvláštní pozornost:
- Použití
requestAnimationFramemístosetTimeoutpro animace; - Debouncing událostí myši a scrollu;
- Líná inicializace těžkých modulů (např. WASM se načte jen při aktivaci pulzace);
- Vypnutí nepoužívaných efektů na pozadí;
- Cacheování výsledků analýzy obálek skladeb.
Testování ukázalo, že i při zapnutých všech efektech (pulzace, částice, paralaxa, filtry) spotřeba CPU nepřekročí 8–12 % na průměrném notebooku. To zachovává responzivitu rozhraní a plynulost animací.
Budoucnost: kam dál
Autor zvažuje několik směrů rozvoje:
- Integrace se systémovými API pro ovládání hlasitosti a mediálních kláves;
- Podpora uživatelských shaderů přes WebGL;
- Export nastavení do cloudu a synchronizace mezi zařízeními;
- Automatická adaptace efektů podle žánru hudby (např. agresivnější pulzace pro elektroniku, plynulé přechody pro jazz).
Hlavní princip — nepřidávat funkce jen pro funkci. Každý nový prvek musí buď řešit konkrétní problém uživatele, nebo výrazně zlepšit uživatelský zážitek bez úhony výkonu.
— Editorial Team
Zatím žádné komentáře.