Communitygithub.com

ninjasweb/painter-skill

Malt Szenen in Code und verwandle sie in Videos – mit echter Ölmalerei-Optik aus Pinselstrichen, Spektralfarbmischung und einem ‚Living Painting‘-Effekt.

Was ist painter-skill?

Dieses Skill ermöglicht es dir, mit Code Bilder im Ölmalerei-Stil zu erstellen und diese in animierte Videos umzuwandeln. Jeder Bildpunkt ist ein echter, von dir platzierter Pinselstrich – keine Filter über einem Rendering. Die Engine verwendet WebGPU/WGSL für instanzierte Striche in einem Headless-Chrome, exportiert mit WebCodecs und Mediabunny nach MP4 und nutzt ffmpeg zur Qualitätssicherung. Es werden zwei Phasen unterstützt: eine ‚Paint-on-Reveal‘-Phase, in der das Bild Strich für Strich entsteht, und eine ‚Living Painting‘-Phase mit Wind, wandernden Wolken, glitzerndem Wasser und Parallax-Kamera. Das Skill eignet sich für Entwickler und Künstler, die animierte Landschaften, Speedpainting-Videos, verträumte Hintergründe oder Studien von Meistergemälden erstellen möchten. Die Berechnung erfolgt komplett lokal auf deiner Hardware – keine Cloud-API-Schlüssel nötig. Der Workflow lehnt sich an echte Maltechniken an: erst Komposition und Werteplan, dann Schicht für Schicht von hinten nach vorne malen, zwischendurch prüfen und anpassen. Die Referenzdateien enthalten Lektionen aus vier Mal-Demonstrationen und Vermessungen von 13 gemeinfreien Meisterlandschaften.

Funktioniert mit✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ninjasweb/painter-skill/tree/HEAD

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Malerisches Video

Du malst mit Code, wie ein Maler mit dem Pinsel malt: Entscheide zuerst das Bild (Komposition, Werte, Palette), lege dann echte Striche von hinten nach vorne, schau dir das Ergebnis an und passe es an. Die Engine verwandelt diese Striche in Einzelbilder; nichts ist ein Filter über einem Rendering – jede Markierung ist ein von dir gesetzter Pinselstrich.

Die Methode wurde aus vier Mal-Demonstrationen (Prozess, Kiefer, malerische Bäume, Sonnenuntergangswolken) und aus der Vermessung von 13 gemeinfreien Meisterlandschaften gelernt. Die destillierten Lektionen sind in references/; der funktionierende Code ist in engine/ und examples/.

Einrichtung (einmal pro Projekt)

cp -R /pfad/zu/malerisch-video/engine ./painter-engine
cd painter-engine
npm ci
node bin/paint.mjs still ../pfad/zu/szene.js --t 8          # → PNG neben der Szene (stills/<szene>/)

Ersetze /pfad/zu/malerisch-video mit dem Ordner, der diese SKILL.md enthält (z.B. ~/.claude/skills/malerisch-video). Benötigt Node ≥ 22.12, Google Chrome mit WebGPU (oder CHROME_PATH), ffmpeg und ffprobe. Referenzstudien benötigen zusätzlich Python mit tools/requirements.txt. Kein Build-Schritt oder Rendering-API-Schlüssel; das Rendering läuft auf lokaler Hardware. Beginne eine neue Szene, indem du die nächstgelegene Datei in examples/ kopierst (sunset-river.js Himmel/Wolken/Wasser · lone-pine.js vertikal, einzelnes Motiv · lake-path.js Bäume/Tiefe/Weg · sunset-study.js dramatischer Himmel mit dunklen Wolkenmassen und Gegenlicht (eine Studie des Aufbaus einer Demonstration) · mountain-hamlet.js Berge, Hütte, Felsen, Wanderfigur, Rauch · brush-chart.js Pinsel und Mischungen).

Arbeitsablauf – überspringe die Betrachtungsschritte nicht

  1. Briefing. Motiv, Stimmung, Tageszeit, Format (16:9, 9:16, 1:1 – jede --size), Dauer und wie die Zeit aufgeteilt wird: Paint-on-Reveal, Living Painting oder beides (Standard: ~60 % Enthüllung, ~40 % lebendig).
  2. Studiere eine Referenz, wenn vorhanden (tools/study.py, siehe references/composition.md). Sie berichtet über Wertemassen, Schlüssel, Chroma, Palette und Brennpunkt – kopiere die Struktur, niemals das Bild.
  3. Komponiere vor der Farbe. Schreibe die Komposition als Kommentar oben in die Szene: Horizonthöhe (niemals die Mitte), Brennpunkt (auf einem Drittel, wo der stärkste Wertkontrast und das höchste Chroma liegen), der Hinführer, was es einrahmt, und ein Werteplan – ein Wert (0–1) für jede große Form, in drei ungleichen Massen. references/composition.md.
  4. Palette aus Pigmenten, platziert auf dem Werteplan. tone(mix({ ultramarine: 1, transYellowOxide: 1 }), 0.42). Halte das Chroma überall niedrig außer beim Brennpunkt-Akzent (Meister: mittleres OKLab-Chroma 0,02–0,06, Bereich mit hohem Chroma unter ~8 %).
  5. Male von hinten nach vorne mit den Motiv-Malern (paintSky, paintCumulus, paintHills, paintMountains, paintWater, paintTreeline, paintPine, paintFir, paintTree, paintGrass, paintRocks, paintHouse, paintGlow, paintMoon, walker, boat, smoke…) und rohem layer.scatter/stroke/path für alles andere. Eine p.phase('name') pro Stufe, Ebenen erstellt fern → nah. references/api.md.
  6. Schau hin, kritisiere, passe an – mindestens zwei Runden. Rendere ein Standbild, öffne das PNG und beurteile es wie ein Gemälde: kneife die Augen zusammen (Lesen sich die drei Wertemassen?), ist der Brennpunkt wie geplant, ist etwas gleichmäßig verteilt / gleich groß / gleich gesättigt, sieht irgendeine Markierung mechanisch aus? Behebe die Ursache im Code. Führe study.py auf deinem eigenen Standbild aus und vergleiche mit dem Plan. Diese Schleife ist die Fähigkeit; erste Renderings sind nie richtig.
  7. Zeit. p.timelapse() für die Enthüllung, danach Bewegung: sway, drift, shimmer, p.wind, p.camera (Parallaxe nach Ebenentiefe), p.dynamic für Dinge, die sich bewegen. references/animation.md.
  8. Kontaktbogen, dann rendern. still --n 12 --sheet → überprüfe jede Stufe des Zeitstrahls; dann render → qa. references/pipeline.md.
  9. Berichte ehrlich: was automatisch geprüft wurde, was du angesehen hast, was du nicht getan hast.

Szenen-Skelett

import { Painting, mix, tone, mixOk, skyColor, paintSky, ridge, paintHills, paintGrass, key, ease } from 'painter';
export const meta = { duration: 16, fps: 30 };

export default function ({ aspect, seed }) {            // aspect = Breite / Höhe des Renderings
  const p = new Painting({ aspect, seed, ground: '#c9b89a' });   // getönter Malgrund, niemals weiß
  p.duration = 16;
  const A = aspect;                                     // Szeneneinheiten: x 0…A, y 0 (oben) … 1 (unten)

  const skyTop = tone(mix({ ultramarine: 2, titaniumWhite: 2 }), 0.72), skyLow = tone(mix({ cadmiumOrange: 1, titaniumWhite: 3 }), 0.88);
  const hillCol = tone(mix({ ultramarine: 1, burntUmber: 1 }), 0.3);
  const hill = ridge({ y: 0.68, amp: 0.05, freq: 2, seed });

  p.phase('himmel');
  paintSky(p.layer('himmel', { depth: 0 }), { color: skyColor({ top: 0, bottom: 0.7, stops: [[0, skyTop], [1, skyLow]] }), bottom: 0.72 });
  p.phase('land');
  paintHills(p.layer('hügel', { depth: 0.6 }), { top: hill, color: (x, y, k) => hillCol, size: 0.03 });
  paintGrass(p.layer('gras', { depth: 1 }), { bounds: [0, 0.8, A, 1.05], dark: hillCol, light: tone(hillCol, 0.5), blade: 0.05 });

  p.timelapse({ start: 0.3, end: 10 });                 // Bild fertig bei 10 s
  p.camera = (t) => ({ zoom: key(t, [[10, 1], [16, 1.07]], ease.inOut) });
  p.wind = (t) => ({ strength: key(t, [[0, 0], [10, 0.15], [12, 1]]) });
  return p;
}

Regeln, die es gemalt aussehen lassen (die Kurzfassung)

  1. Der Wert leistet die Arbeit, die Farbe bekommt die Anerkennung. Plane drei ungleiche Wertemassen; kneife die Augen bei jedem Standbild zusammen.
  2. Getönter Malgrund, niemals weiß. Wähle die Imprimatura, um das Bild zu harmonisieren (warme Siena unter Grüntönen, helles Creme unter einem Sonnenuntergang).
  3. Entfernung zuerst, dann nach vorne. Fern = heller, kühler, grauer, weicher, dünnere Farbe, kleinere Markierungen. Nah = dunkelste Dunkelheiten, höchster Kontrast und Chroma, dickste Farbe, größte Markierungen. Verwende atmosphere(color, d, air).
  4. Dunkelheiten zuerst und dünn, Lichter zuletzt und dick. thick 0,1–0,3 für Schatten und Entfernung, 0,8–1 für Glanzlichter; Glanzlichter sind klein und wenige.
  5. Hell gegen Dunkel, Dunkel gegen Hell. Brich jede Masse mit Markierungen, die eine kleine Wertstufe (±0,05) von dem entfernt sind, was darunter liegt; p.valueAt(x, y) / p.sample(x, y) sagen dir, was dort ist.
  6. Striche folgen der Form: um eine Wolkenkugel herum, entlang eines Abhangs, flach auf Wasser, einen Grashalm hinauf, einen Stamm hinunter.
  7. Mische Grüntöne und erde sie (earth(mix({ ultramarine: 1, cadmiumYellow: 1 }), 0.3)); spare reines Chroma für einen Akzent auf.
  8. Variiere alles: Größen, Abstände, Höhen, Intervalle. Gleich = mechanisch. Ungerade Gruppen, überlappende Formen, eine Dominante.
  9. Verlorene und gefundene Kanten: weich, wo sich Formen abwenden oder zurückweichen (soft 0,5+), scharf am Brennpunkt.
  10. Reine Funktion der Zeit. Eine Szene ist deterministisch aus seed; ein Einzelbild hängt nur von t ab. Verwende niemals Math.random() oder die Wanduhrzeit – verwende layer.rand / rng(seed).

Wo Dinge schiefgehen (beim Bauen hiervon gelernt)

  • Weiß verschluckt Mischungen. Der Spektralmischer gewichtet Pigmente nach Leuchtdichte; eine 1:9-Farbe:Weiß-Mischung ist fast weiß. Mische den Farbton mit wenig oder keinem Weiß und platziere ihn dann mit tone(c, value). Schneide grelle Ergebnisse mit chroma(c, 0.5–0.8)`.
  • Wolken als Bälle mit Stöcken → viele kleine Lappen auf einer flachen Basis (cumulusShape Lappen 40–60), Licht nur auf der der Sonne zugewandten Seite, runde weiche Tupfer, mäßiges thick.
  • Kiefer als Palme → Nadeln sind abgerundete Büschel (Ausbrüche von kurzen Fächerstrichen), die auf den Ästen sitzen, mit Himmelslöchern dazwischen, dunkel darunter, Lichter oben; Äste hängen tief und reichen hoch hinauf.
  • Bäume mit Regenschirm-Speichen-Ästen / schwarzen Stämmen → Äste müssen innerhalb der Krone enden; Stammdunkelheiten haben einen Wert von ~0,22, nicht schwarz, und erhalten atmosphere mit der Entfernung.
  • Ein ganzer Bereich in gesättigter Farbe (oranger Boden, türkiser Himmel) → erde ihn; verstreue die reine Farbe als ein paar kleine Markierungen.
  • Weg liest sich als Fluss → warmes hellgrau, Striche in Bewegungsrichtung, kühles Violett nur in seinen Schatten.
  • Wasser aus kurzen Strichen sieht digital aus → Wasser besteht aus langen, waagerechten Zügen, die ineinander übergehen, mit nur wenigen Kräuselmarkierungen in der Nähe des Betrachters (was paintWater tut); füge keine Reihen von Strichen von Hand hinzu.
  • See liest sich als gläserner Spiegel → paintWater({ chop: 1 }) für Wellenrücken und Gischt; behalte chop: 0 für Seen und Flüsse bei.
  • Lampen-/Fensterlicht ist ein flacher Fleck → paintGlow über einer dunklen Umgebung, dann der kleine heiße Kern; ein langer weicher Strich ist kein Leuchten.
  • Strahlen als weiße Spieße → wenige, breite, sehr weiche, niedrige Deckkraft-Strahlenbündel (paintRays Standardeinstellungen).
  • Leinwandbindung wird zu einem Gitter auf blasser dünner Farbe → behalte look.weave ≤ 0,2 bei.
  • Berge als schuppige Wand oder Zebrastreifen → baue die Skyline mit peaks(), halte die Reichweite fern (dünne Farbe, size ≈ 0,02, schmaler Wertebereich) und lasse paintMountains sie in ein paar große beleuchtete und Schattenebenen aufteilen.
  • Ein flaches Band ist keine Wolkenbank / Hügel / Baumgrenze → variiere die Oberkante, die inneren Werte und lasse Lücken.
  • Szene schlägt mit einem vagen Browserfehler fehl → die CLI prüft zuerst auf Syntax; ein Laufzeitfehler gibt die Szenenzeile aus. Eine lokale Variable, die eine Farbe überschattet (leaf, sky, hill), ist die übliche Ursache für c.map is not a function.
  • Lesen eines veralteten Standbilds: überprüfe immer zuerst die Befehlsausgabe auf einen Fehler, bevor du das PNG öffnest.
  • WebGPU und WebCodecs existieren nur auf einem sicheren Ursprung – die CLI bedient http://127.0.0.1; öffne Szenen niemals über file://.

Referenzdateien

  • references/painting-lessons.md – was jede Demonstration lehrt und wie sie sich auf Engine-Aufrufe abbildet.
  • references/composition.md – Komponieren einer Szene, der Werteplan, Zahlen von den Meistern, study.py.
  • references/api.md – Painting / Ebene / Pinsel / Farbe / Motivmaler-Referenz, Schreiben eines neuen Motivmalers.
  • references/animation.md – Enthüllungstempo, lebendige Bewegung, Kamera und Parallaxe, dynamische Ebenen, Sieden, Audio.
  • references/pipeline.md – CLI, Rendereinstellungen, Leistung, Qualitätssicherung, Fehlerbehebung, Liefergegenstände.

Verwandte Skills