Ruhige, kinderfreundliche Ausmal-App als Flutter-Web/PWA.
Der MVP ist bewusst klein gehalten:
- Startseite
- Galerie
- 1 Demo-Motiv
- 20 Farben
- Tap-to-fill auf definierten SVG-Regionen
- Zoom und Pan in der Ausmalansicht
- freie Pinsel-Ebene über den SVG-Flächen
- Undo
- Reset
- lokales Speichern im Browser
Es gibt kein Backend, keine Werbung, kein Tracking und keine Accounts.
Voraussetzung: Flutter Stable mit Web-Support.
flutter pub get
flutter run -d chromeAlternativ für einen lokalen Web-Build:
flutter build webFür GitHub Pages sollte der Web-Build mit passendem Base-Href erzeugt werden.
Beispiel für ein Repository buntzauber:
flutter build web --release --base-href /buntzauber/Danach kann der Inhalt von build/web/ statisch veröffentlicht werden.
Alternativ ist im Repo ein GitHub-Actions-Workflow hinterlegt:
Der Workflow:
- baut Flutter Web auf jedem Push nach
main - setzt den
base-hrefautomatisch passend für Repo-Pages oderusername.github.io - veröffentlicht
build/webdirekt über GitHub Pages
Einmalig in GitHub vorbereiten:
- Repository auf GitHub öffnen
Settings -> PagesSourceaufGitHub Actionsstellen
Danach reicht ein Push auf main.
lib/
main.dart
app.dart
core/
constants/
models/
services/
theme/
utils/
features/
home/
gallery/
coloring/
assets/
data/
images/
web/
Die App nutzt kein Pixel-Flood-Fill.
Stattdessen:
- jedes Motiv ist ein bewusst vorbereitetes SVG
- das SVG trennt Füllflächen und schwarze Linien
- jede ausmalbare Fläche ist eine eigene Region mit ID
- Regionen werden über ihre SVG-ID erkannt
- ein Tap prüft, welcher Pfad getroffen wurde
- danach wird genau diese Region eingefärbt
Die Fortschritte werden mit shared_preferences lokal im Browser gespeichert.
Das erste Demo-Motiv liegt hier:
assets/images/demo_flower_meadow.svgassets/data/coloring_pages.json
Die Galerie bezieht ihre Einträge aus assets/data/coloring_pages.json.
- Neues SVG unter
assets/images/anlegen. - Eintrag in
assets/data/coloring_pages.jsonergänzen. - App neu starten.
Beispiel für den JSON-Eintrag:
{
"id": "katze",
"title": "Katze",
"svgAsset": "assets/images/katze.svg",
"overlayAsset": "assets/images/katze_overlay.png"
}Das empfohlene Format für schöne und robust ausfüllbare Motive ist ein eigenes, kleines Buntzauber-Schema:
- Root-SVG mit
viewBox - eine Gruppe
regions - optional eine Gruppe
outlines - in
regionsliegen nur ausmalbare, geschlossene Flächen - in
outlinesliegen nur die schwarzen Linien
Wichtig:
viewBoxist Pflicht- ausmalbare Flächen dürfen
<path>,<rect>,<circle>,<ellipse>,<polygon>oder<polyline>sein - jede Region braucht eine eindeutige
id regionsist der kanonische Wegoutlinesist optional, aber stark empfohlen- keine
transform-Ketten einplanen - Regionen sollten geschlossen und gut antippbar sein
- Regionen sollten sich möglichst nicht überlappen
- kleine, filigrane Miniflächen vermeiden
Warum diese Trennung wichtig ist:
- die Flächen werden gefüllt
- die Outlines bleiben sauber oben drüber
- dadurch sieht das Motiv auch nach vielen Farbwechseln ordentlich aus
- und wir müssen kein unzuverlässiges Pixel-Flood-Fill auf PNGs bauen
Fallback für Fremd-SVGs:
- wenn keine
data-buntzauber-Marker vorhanden sind, versucht die App einen einfachen Importmodus - dabei werden weiß gefüllte Formen als Ausmalflächen interpretiert
- andere Formen werden als Outline behandelt
- das ist nur ein pragmatischer Fallback, kein Garant für beliebige Export-SVGs
Minimalbeispiel:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 320">
<g id="regions" data-buntzauber="regions">
<rect id="body" x="120" y="140" width="160" height="120" />
<path id="roof" d="M100 150 L200 80 L300 150 Z" />
</g>
<g id="outlines" data-buntzauber="outlines">
<rect x="120" y="140" width="160" height="120" />
<path d="M100 150 L200 80 L300 150 Z" />
</g>
</svg>Hinweise:
- Wenn keine
outlinesdefiniert sind, zeichnet die App ersatzweise die Regionspfade als Linien. - Für kuratierte Motive sollte der Fallback-Modus nicht der Zielweg sein.
Empfohlener Weg:
- Ein Motiv als Referenz oder Lineart erstellen, gern auch mit AI.
- Das Motiv in Inkscape, Illustrator oder einem Vektor-Tool sauber vereinfachen.
- Eine Ebene für
regionsbauen: große, geschlossene Flächen eindeutige IDs - Eine zweite Ebene für
outlinesbauen: schöne schwarze Linien ohne Fülllogik - Als SVG exportieren und in der App testen.
Nicht empfohlen:
- ein beliebiges PNG direkt zu flood-fillen
- ein zufälliges SVG aus dem Netz ungeprüft zu importieren
- nur sichtbare Linien ohne echte Füllflächen zu verwenden
Der praktikable spätere Weg wird sehr wahrscheinlich so aussehen:
- AI oder Illustrator erzeugt ein hübsches Grundmotiv.
- Wir vereinfachen die Formensprache für Kinder.
- Wir bauen daraus ein Buntzauber-SVG mit
regionsundoutlines. - Die App nutzt dann nur noch diese saubere Version.
Das ist deutlich robuster als:
- PNG-Flood-Fill
- Freihand-Malen mit Pinsel
- heuristische Zufallsimporte von Fremd-SVGs
Die App kann jetzt auch importierte Lineart-Motive nutzen, bei denen zwei Assets zusammenspielen:
*_regions.svgDas enthält nur die tappbaren Füllflächen.*_overlay.pngDas enthält nur die schwarzen Linien auf transparentem Hintergrund.
In der App werden dann:
- die SVG-Regionen unten gefüllt
- das transparente Linien-PNG oben drübergelegt
Dadurch können schöne PNG-Ausmalbilder verwendet werden, ohne dass die weißen Bildflächen die Füllfarben überdecken.
Es gibt jetzt einen ersten Offline-Konverter in Dart:
Er macht aktuell Folgendes:
- PNG laden
- dunkle Pixel als Outline/Barriere erkennen
- Outline leicht verbreitern, um AA-Lücken zu schließen
- Flood-Fill auf den hellen Innenflächen
- Rand-Hintergrund verwerfen
- Regionen als Buntzauber-SVG exportieren
Beispiel:
dart run tool/png_to_buntzauber_svg.dart input.png output.svg \
--threshold 210 \
--outline-grow 1 \
--min-region-pixels 200 \
--simplify 1.0 \
--border-regions keepFür den eigentlichen Import in die Galerie:
dart run tool/import_lineart_png.dart assets/images/haus.png \
--id haus_png \
--title "Haus" \
--threshold 215 \
--outline-grow 1 \
--min-region-pixels 200 \
--simplify 1.0 \
--border-regions keep--gap-bridge und --border-snap bleiben standardmäßig aus. Der Standardweg ist jetzt bewusst konservativ: lieber ein stabiler, transparenter Sicherheitsrand rund um das Bild als aggressive Rand-Heuristiken mit Seiteneffekten.
Zusätzlich bleibt standardmäßig ein kleiner Sicherheitsrand von 2px rund um das ganze Bild unfüllbar. Dadurch entsteht kein versehentlicher 1-Pixel-Ring als Region direkt am Canvasrand.
Wenn du mehrere neue Motive gesammelt importieren willst:
- PNGs nach assets/import/README.md in
assets/import/legen - Dann einmal ausführen:
dart run tool/import_lineart_folder.dart --scale-factor 2.0Dabei gilt:
- Dateiname wird zur Galerie-ID
- Dateiname wird automatisch in einen Titel umgewandelt
--scale-factorvergrößert das PNG vor der Erzeugung von Regionen und Overlay- erzeugte Dateien landen in
assets/images/ assets/data/coloring_pages.jsonwird aktualisiert
Zusätzlich gibt es jetzt eine kleine lokale Import-Oberfläche neben der eigentlichen App.
Schnellstart vom Repo-Root aus:
dart run tool/import_ui_server.dartDann im Browser öffnen:
http://127.0.0.1:8787
Kurzablauf:
- PNGs nach
assets/import/legen dart run tool/import_ui_server.dartstartenhttp://127.0.0.1:8787öffnen- Bilder auswählen,
scale-factorsetzen, importieren
Die Import-UI:
- liest alle PNGs aus
assets/import/ - zeigt Vorschaubilder und Mehrfachauswahl
- erlaubt einen gemeinsamen
scale-factor - importiert nur die ausgewählten Bilder
- nutzt intern denselben Import-Workflow wie das CLI-Tool
Gut geeignet für:
- einfache schwarze Lineart auf hellem Hintergrund
- wenige große Flächen
- wenig Textur
- klar geschlossene Formen
Schlecht geeignet für:
- Fotos
- starke Schatten
- weiche Farbverläufe
- offene Linien
- sehr detailreiche AI-Bilder ohne Vorverarbeitung
Der Prototyp ist also ein guter Baustein für den späteren Workflow, aber noch kein Wunderkonverter für beliebige Bilder.
Der aktuelle MVP deckt ab:
- Startseite mit Einstieg in die Galerie
- Galerie mit dem Demo-Motiv
- Ausmalansicht mit 8 Farben
- Tap-to-fill per SVG-Region
- Zoom und Pan für kleine Flächen
- freies Malen als zusätzliche Brush-Layer
- Undo
- Reset
- lokales Wiederherstellen nach Reload
In der aktuellen Arbeitsumgebung war flutter nicht installiert. Deshalb konnte der Build hier nicht lokal ausgeführt werden. Die Projektstruktur und die Dateien sind jedoch so angelegt, dass sie in einer normalen Flutter-Web-Umgebung direkt verwendbar sind.