Zpět na domů

Vytvoření runtime doplňku s WASM pro hudební přehrávač

Podrobný rozbor vytvoření runtime doplňku ChromaSync pro hudební přehrávač: od obnovení tématu po implementaci WASM jádra pro audio-reaktivní efekty. Pokrývá architekturu, systém nastavení, optimalizaci a budoucí směry rozvoje.

Runtime doplněk s WASM: jak jsem přestavěl architekturu pro audio-reaktivní efekty
Advertisement 728x90

# 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í.

Google AdInline article slot

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:

Google AdInline article slot
  • 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.

Google AdInline article slot

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í requestAnimationFrame místo setTimeout pro 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

Advertisement 728x90

Číst dál