trakodag
Edytor obrazu sterowany kodem. Każda warstwa to osobny program w JavaScripcie, który operuje na pikselach wynikowego obrazu poprzedniej warstwy. Pełny dostęp do każdego piksela, pętle, zmienne, funkcje matematyczne, dodatkowe obrazy jako tablice pikseli.
Cała apka to jeden plik index.html — bez zależności, bez build-stepu.
Uruchomienie
Otwórz index.html w przeglądarce:
xdg-open index.html # Linux
open index.html # macOS
firefox index.html # albo dowolna inna przeglądarka
Model warstw
Warstwy tworzą pipeline:
original → layer 1 → layer 2 → … → final
Każda warstwa otrzymuje wynik poprzedniej jako prev (dla pierwszej prev = original)
i pisze do output. Wynik trafia jako prev do następnej warstwy. Suwak
strength każdej warstwy to mieszanie z wejściem: lerp(prev, output, strength)
— przy 0.00 warstwa jest niewidoczna, przy 1.00 w pełni nadpisuje.
Wyłączenie ikony oka pomija warstwę całkowicie.
Interfejs
- Load image — załaduj obraz źródłowy (PNG, JPG, …)
- + Add image — dorzuć dodatkowy obraz dostępny w kodzie jako
images[i] - Run / auto-run — odpalenie pipeline'u (auto-run debouncuje wpisywanie ~250 ms);
skrót
Ctrl/Cmd + Enter - scale — rozdzielczość robocza podglądu (
1x,0.5x,0.25x,0.125x). Per-piksel JS jest wolny, więc edytuj na np.0.25x, eksport zawsze leci w1x. - theme —
blue / orangelubpurple / sea; wybór pamiętany wlocalStorage - Export PNG — render w pełnej rozdzielczości i pobranie pliku
- Save project / Load project —
.jsonz samymi warstwami i kodem (bez obrazu) - ? / ⓘ Vars — ściąga API i pełny zestaw przykładów
Najechanie kursorem na canvas pokazuje oryginał.
Edytor
- Kolorowanie składni: komentarze, stringi, liczby, słowa kluczowe, nazwy API, funkcje, operatory.
Tabwstawia 2 spacje.- Nazwy warstw: dwuklik → edycja inline.
Code API
Zmienne dostępne w kodzie warstwy:
| Nazwa | Co to |
|---|---|
width, height |
wymiary obrazu w aktualnej rozdzielczości roboczej |
original |
obiekt źródłowego obrazu: { pixels, width, height, getPixel(x,y) } |
prev |
wynik poprzedniej warstwy (dla pierwszej = original), ten sam kształt |
images[i] |
dodatkowe obrazy dorzucone przyciskiem + Add image |
output |
Uint8ClampedArray RGBA długości width*height*4 — to do tego piszesz |
Helpery:
| Nazwa | Działanie |
|---|---|
getPixel(x, y) |
skrót do prev.getPixel(x, y) → {r, g, b, a} |
setPixel(x, y, r, g, b, a) |
zapis piksela; a domyślnie 255 |
setPixel(x, y, p) |
zapis z obiektu {r, g, b, a} |
forEach((x, y, p) => { … }) |
iteracja po wszystkich pikselach prev; mutuj p lub zwróć nowy |
clamp(v, lo=0, hi=255) |
obcięcie do zakresu |
lerp(a, b, t) |
interpolacja liniowa |
log(...) |
wypisanie do panelu konsoli pod edytorem |
Random:
| Nazwa | Wynik |
|---|---|
random1() |
float [0, 1) |
random256() |
int [0, 255] |
randomBoolean() |
true / false (50/50) |
randomRange(lo, hi) |
float [lo, hi) |
randomInt(lo, hi) |
int [lo, hi] (inclusive) |
random() |
alias Math.random() |
Matematyka — wszystko z Math jest dostępne pod skróconymi nazwami:
sin, cos, tan, asin, acos, atan, atan2, abs, sqrt, pow,
exp, floor, ceil, round, min, max, hypot, sign, plus stałe
PI, TAU, E. Pełen obiekt też jest pod Math.
Przykłady
Brightness +5:
forEach((x, y, p) => {
p.r = clamp(p.r + 5);
p.g = clamp(p.g + 5);
p.b = clamp(p.b + 5);
});
Maksymalny niebieski w kolumnie x = 50:
forEach((x, y, p) => {
if (x === 50) { p.r = 0; p.g = 0; p.b = 255; }
});
Co 500-ny piksel: pomnóż zielony kanał razy 2:
forEach((x, y, p) => {
const i = y * width + x;
if (i % 500 === 0) p.g = clamp(p.g * 2);
});
Wklejenie obrazu images[0] w punkcie (50, 100):
const img = images[0];
const offsetX = 50, offsetY = 100;
for (let y = 0; y < img.height; y++) {
for (let x = 0; x < img.width; x++) {
const dx = x + offsetX, dy = y + offsetY;
if (dx < 0 || dx >= width || dy < 0 || dy >= height) continue;
const q = img.getPixel(x, y);
setPixel(dx, dy, q.r, q.g, q.b, q.a);
}
}
Sinusoidalne przesunięcie poziome:
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const dx = floor(sin(y * 0.05) * 20);
const p = prev.getPixel((x + dx + width) % width, y);
setPixel(x, y, p.r, p.g, p.b, p.a);
}
}
Więcej przykładów w panelu ? — basics / coordinates / random / geometry / second image.
Format pliku projektu
Save project zapisuje JSON ze stanem warstw (sam kod, bez obrazu):
{
"format": "trakodag.web",
"version": 1,
"savedAt": "2026-04-16T20:00:00.000Z",
"layers": [
{
"name": "base",
"code": "forEach((x,y,p) => { p.r = clamp(p.r + 5); ... });",
"visible": true,
"opacity": 1.0
}
]
}
Obraz wczytujesz osobno przyciskiem Load image — projekt jest przenośny między różnymi obrazami.
Wydajność
Per-piksel JS na obrazach kilkudziesięciu MP będzie zauważalnie wolny. Schemat pracy:
- Wczytaj obraz, zostaw
scalena0.25x(lub0.125xdla bardzo dużych) - Pisz i debuguj kod na małym podglądzie
- Przed eksportem opcjonalnie podbij
scależeby zobaczyć finalny render - Export PNG zawsze leci w
1x— nie musisz nic zmieniać