002 - Core System
Das Core-System bildet das Fundament der cc-toolbox. Es löst ein zentrales Problem: Wie verwalte ich den State eines generativen Kunstwerks so, dass er persistierbar, synchronisierbar und über UI steuerbar ist?
Die Antwort: Ein zentrales ParameterObject, das als Single Source of Truth dient. Alle Komponenten lesen und schreiben darauf. Der IOManager koordiniert die Kommunikation, der TweakpaneManager bindet die UI an.
Komponenten
| Klasse | Datei | Funktion |
|---|---|---|
Artwork |
Artwork.ts |
Haupt-Container, initialisiert alles |
SketchRunner |
Sketch.ts |
Führt Sketches aus |
SceneGraph |
SceneGraph.ts |
Verwaltet Drawables/Agents |
ParameterObject |
ParameterObject.ts |
Zentraler State-Store |
IOManager |
IOManager.ts |
Event-Hub & Channels |
TweakpaneManager |
TweakpaneManager.ts |
UI-Module-System |
Format |
Format.ts |
Canvas-Formate (Screen, Print) |
Viewport |
Viewport.ts |
Responsive Skalierung |
Artwork
Der zentrale Container für jedes Kunstwerk.
Lifecycle:
User Sketch Artwork SceneGraph
│ │ │ │
│ SketchRunner │ │ │
│ .run() │ │ │
│──────────────>│ │ │
│ │ new Artwork() │ │
│ │──────────────>│ │
│ │ │ initCanvas() │
│ │ │ initTweakpane()
│ │ configure() │ │
│ │──────────────>│ │
│ │ │ addAgent() │
│ │ │──────────────>│
│ │ │ │
│ │ ┌──────────────────────────┤
│ │ │ Render Loop │
│ │ │ │
│ │ draw() │ │
│ │<──────────────│ │
│ │ draw() │ │
│ │──────────────────────────────>│
│ │ │ │
│ │ └──────────────────────────┤
│ │ │ │Props:
| Property | Typ | Beschreibung |
|---|---|---|
canvas |
Canvas |
Canvas-Element & Größe |
parameter |
ParameterObject |
Alle Parameter |
tweakpane |
TweakpaneItems |
UI-Container |
sceneGraph |
SceneGraph |
Agent-Container |
format |
Format |
Aktives Format |
animation |
AnimationState |
Timing-Info |
SceneGraph
Verwaltet alle zeichenbaren Objekte (Agents/Drawables).
Features:
- Hierarchische Struktur
- Z-Order Management
- Batch-Updates
- Visibility Control
API:
| Methode | Beschreibung |
|---|---|
add(agent) |
Agent hinzufügen |
remove(agent) |
Agent entfernen |
draw(ctx) |
Alle Agents zeichnen |
forEach(fn) |
Über Agents iterieren |
ParameterObject
Das ParameterObject ist das Herzstück der Architektur. Es ist ein einfaches JavaScript-Objekt, das den kompletten Zustand eines Artworks enthält – von Canvas-Größe über Farben bis zu Agent-spezifischen Einstellungen.
Warum so zentral?
Das Problem bei generativer Kunst: Man findet nach stundenlangem Tweaken endlich die perfekte Einstellung – und verliert sie beim nächsten Reload. Das ParameterObject löst das:
- Serialisierbar: Als JSON speicherbar (Snapshots!)
- Synchronisierbar: Über Sockets an Studio/andere Artworks
- UI-bindbar: Tweakpane liest und schreibt direkt darauf
- Versionierbar: Git-freundlich, diff-bar
Struktur:
parameter
├── artwork # Artwork-Settings
│ ├── canvas
│ └── animation
├── format # Format-Einstellungen
├── colorset # Aktive Farben
├── tweakpane # UI-State (prefixed)
│ └── {component}
│ └── {subcomponent}
│ └── {key}: value
└── {agent} # Agent-spezifisch
└── {property}: valueEigenschaften:
- Serialisierbar (JSON)
- Import/Export-fähig
- Event-fähig über IOManager
IOManager
Der IOManager ist der Event-Hub der Anwendung. Er entkoppelt Komponenten voneinander – niemand muss direkt auf andere Komponenten zugreifen.
Das Problem ohne IOManager:
ColorSet ändert Farbe → muss alle Brushes kennen → enge KopplungMit IOManager:
ColorSet → emits "colorset:changed" → IOManager → alle Subscriber bekommen esZwei Kommunikationsmuster:
Channel-basiert (Pull)
- Für Tweakpane-Updates
- State-basiert
onUpdate()Callbacks
Event-basiert (Pub/Sub)
- Für Events wie
colorset:changed - Payload-basiert
subscribe()/emit()
- Für Events wie
Beispiel-Events:
| Event | Payload | Auslöser |
|---|---|---|
colorset:changed |
{ colors, id } |
ColorSet wechselt |
format:changed |
{ width, height } |
Format wechselt |
parameter:updated |
{ path, value } |
Parameter ändert sich |
TweakpaneManager
Tweakpane ist eine fantastische UI-Library für Parameter-Manipulation. Aber bei komplexen Artworks mit vielen Agents wird das Management chaotisch: Wer schreibt wohin? Wessen State ist das?
Der TweakpaneManager löst das durch Module mit isolierten State-Bereichen. Jedes Modul:
- Hat einen eigenen Namespace im ParameterObject
- Kennt nur seinen eigenen State
- Kommuniziert über IOManager-Channels
Das Brush-Pattern ist die Referenz-Implementierung: Ein Brush-Modul verwaltet parameter.tweakpane.{component}.brush.* und transformiert die UI-Werte (mit Prefix brush_) in Business-Logic-Werte (ohne Prefix).
Konzept:
TweakpaneManager
├── createModule(options) → TweakpaneModule
│ ├── id: "brush:shape"
│ ├── statePath: ["brush", "shape"]
│ ├── stateDefaults: {...}
│ └── channelId: "ui:brush:shape"
└── modules: Map<id, Module>TweakpaneModule API:
| Methode | Beschreibung |
|---|---|
addBinding(key, params) |
UI-Control hinzufügen |
onUpdate(handler) |
Update-Handler registrieren |
getState() |
State lesen |
setState(obj) |
State setzen |
Format
Vordefinierte Canvas-Formate.
Kategorien:
| Kategorie | Beispiele |
|---|---|
| Screen | 1080p, 4K, Instagram Square |
| Print A-Reihe | A4, A3, A2 (300dpi) |
| Print US | Letter, Legal |
| Custom | Frei definierbar |
Responsive Verhalten:
FitMode: 'contain'- In Container einpassenFitMode: 'cover'- Container ausfüllenFitMode: 'none'- Originalgröße
Vector
2D/3D Vektoroperationen.
Methoden:
| Kategorie | Methoden |
|---|---|
| Arithmetik | add, subtract, multiply, divide |
| Länge | magnitude, normalize, setMagnitude |
| Winkel | angle, rotate, heading |
| Produkte | dot, cross |
| Interpolation | lerp, slerp |
| Utilities | distance, clone, random |
Coordinate & Size
Hilfsklassen für Positionen und Größen.
// Coordinate - Row/Col
const coord = new Coordinate(row, col);
// Size - Width/Height
const size = new Size(width, height);
size.area; // → width * height
size.aspect; // → width / heightDebug
Logging und Debugging-Utilities.
Modi:
silent- Keine Ausgabeminimal- Nur Fehlernormal- Fehler + Warnungenverbose- Alles
Methoden:
| Methode | Beschreibung |
|---|---|
log(msg) |
Info-Log |
warn(msg) |
Warnung |
error(msg) |
Fehler |
time(label) |
Timer starten |
timeEnd(label) |
Timer stoppen |