008 - Agents
Agents sind wiederverwendbare Zeichen-Komponenten für den SceneGraph.
Das Konzept
Ein Agent ist ein eigenständiges "Ding, das zeichnet". Er hat eigene Parameter, eigenen State, eigene Tweakpane-UI. Du fügst ihn dem SceneGraph hinzu, und er kümmert sich um den Rest.
Warum Agents statt Funktionen? Eine Funktion drawParticles(ctx, particles) ist zustandslos – du musst die Partikel-Liste selbst verwalten. Ein ParticleManager Agent verwaltet seine Partikel intern, hat Tweakpane-Sliders für Count/Speed/Size, und du rufst nur .draw(props) auf.
Warum SceneGraph? Weil die Reihenfolge zählt. Was zuerst gezeichnet wird, liegt hinten. Ein Agent für den Hintergrund muss vor den Partikeln kommen. Der SceneGraph macht das explizit und erlaubt Umordnen zur Laufzeit.
Das Pattern: Jeder Agent hat eine statische ensureParameterSet() Methode, die Defaults ins ParameterObject schreibt. Das muss VOR dem Tweakpane-Setup passieren – sonst crasht der Exhibition-Mode (der hat keine Tweakpane).
Übersicht
┌─────────────────┐
│ SceneGraph │
└─────────────────┘
│
┌───────────────────────────┼───────────────────────────┐
│ │ │ │ │ │ │
▼ ▼ ▼ │ ▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────┴───┐ ┌────────────┐ ┌────────────┐
│ Background │ │Background- │ │ Brush │ │ Particle- │ │ Particle- │
│ │ │ Shape │ │ │ │ Manager │ │ Wind │
└────────────┘ └────────────┘ └────────┘ └────────────┘ └────────────┘
┌───────────────────────────┼───────────────────────────┐
│ │ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────┐ ┌────────────┐ ┌────────────┐
│ Entity_ │ │ Grid_ │ │ Image- │ │ ImageLayer │ │ Characters │
│ Manager │ │ Manager │ │ Layer │ │ Dithering │ │ │
└────────────┘ └────────────┘ └────────┘ └────────────┘ └────────────┘
┌─────────────────────┐
│ DitherShapeGenerator│
└─────────────────────┘Agents-Liste
| Agent | Datei | Funktion |
|---|---|---|
Background |
Background.ts |
Einfarbiger Hintergrund |
BackgroundShape |
BackgroundShape.ts |
Shape im Zentrum |
Brush |
Brush.ts |
Universal-Zeichenwerkzeug |
ParticleManager |
Particles.ts |
Partikel-System |
ParticleWind |
ParticleWind.ts |
Wind-Partikel mit Noise |
Entity_Manager |
Entities.ts |
Bouncing/Wrapping Entities |
Grid_Manager |
Grid_Manager.ts |
Grid-System |
ImageLayer |
ImageLayer.ts |
Bild-Darstellung |
ImageLayerDithering |
ImageLayerDithering.ts |
Bild mit Dithering-Effekt |
Characters |
Characters.ts |
Text/Zeichen-Rendering |
DitherShapeGenerator |
DitherShapeGenerator.ts |
Shapes aus Dither-Daten |
Background
Einfacher farbiger Hintergrund.
Parameter:
| Parameter | Typ | Beschreibung |
|---|---|---|
color |
string |
Hintergrundfarbe |
opacity |
number |
Transparenz |
BackgroundShape
Ein Shape zentriert im Hintergrund.
Parameter:
| Parameter | Typ | Beschreibung |
|---|---|---|
brush |
Brush_ParameterSet |
Shape-Definition |
scale |
number |
Skalierung |
rotation |
number |
Rotation (Grad) |
Brush
Das universelle Zeichenwerkzeug.
Parameter:
| Parameter | Typ | Default | Beschreibung |
|---|---|---|---|
shape |
string |
'Circle' | Shape-Name |
position |
{x, y} |
(0.5, 0.5) | Position (normalisiert) |
size |
number |
100 | Größe |
rotation |
number |
0 | Rotation |
fill |
boolean |
true | Füllung? |
fillColor |
string |
'#FFFFFFFF' | Füllfarbe |
border |
number |
0 | Rahmenbreite |
borderColor |
string |
'#000000FF' | Rahmenfarbe |
opacity |
number |
1 | Transparenz |
Physics-Optionen:
| Option | Typ | Beschreibung |
|---|---|---|
physics.mode |
'none' | 'rigid' | 'soft' |
Physics-Modus |
physics.rigid |
RigidBodyConfig |
Rigid Body Settings |
physics.soft |
SoftBodyConfig |
Soft Body Settings |
ParticleManager
Verwaltet Partikel-Systeme.
Parameter:
| Parameter | Typ | Beschreibung |
|---|---|---|
count |
number |
Anzahl Partikel |
source |
ParticleSource |
Spawn-Quelle |
physics |
PhysicsConfig |
Physics-Einstellungen |
Particle Sources:
| Source | Beschreibung |
|---|---|
ImageParticleSource |
Partikel aus Bild-Pixeln |
BrushParticleSource |
Partikel in Brush-Form |
ParticleWind
Wind-Simulation mit Noise.
Parameter:
| Parameter | Typ | Beschreibung |
|---|---|---|
count |
number |
Partikel-Anzahl |
windStrength |
number |
Windstärke |
noiseScale |
number |
Noise-Skalierung |
gravity |
number |
Schwerkraft |
fadeIn |
boolean |
Einblenden? |
fadeOut |
boolean |
Ausblenden? |
Entity_Manager
Bouncing/Wrapping Objekte.
Parameter:
| Parameter | Typ | Beschreibung |
|---|---|---|
count |
number |
Anzahl Entities |
brush |
Brush_ParameterSet |
Entity-Aussehen |
velocity |
{min, max} |
Geschwindigkeitsbereich |
boundaryMode |
'bounce' | 'wrap' |
Grenzverhalten |
Entity Features:
- Position, Velocity, Acceleration
- Bouncing an Canvas-Grenzen
- Wrapping (Pac-Man Style)
- Collision Detection (optional)
Entity Stats Broadcasting
Der Entity_Manager schreibt automatisch Statistiken ins ParameterObject, die von anderen Artworks (z.B. ParameterObserver) empfangen werden können:
// Diese Werte werden automatisch in parameter.entity.stats geschrieben:
{
centerX: 0.52, // Normalisiertes Zentrum aller Entities (0-1)
centerY: 0.48,
avgSpeed: 0.023, // Durchschnittsgeschwindigkeit (normalisiert)
spreadX: 0.31, // Streuung der Entities
spreadY: 0.28,
// Positionen der ersten 10 Entities (normalisiert 0-1)
e0_x: 0.12, e0_y: 0.45,
e1_x: 0.67, e1_y: 0.23,
// ... bis e9
}Anwendung mit ParameterObserver:
// Im Observer-Artwork:
const observer = new ParameterObserver({
serverUrl: 'http://localhost:4000',
targetArtwork: 'item-cc-entities',
});
observer.onUpdate((params, artworkId) => {
const stats = params.entity?.stats;
if (stats) {
console.log(`Entities center: (${stats.centerX}, ${stats.centerY})`);
console.log(`Average speed: ${stats.avgSpeed}`);
}
});Mit Smart Filter im ParameterMandala werden genau diese dynamischen Entity-Stats visualisiert, während statische Parameter (Canvas-Size, Animation-Settings) herausgefiltert werden.
Grid_Manager
Dual-View Grid System.
Parameter:
| Parameter | Typ | Beschreibung |
|---|---|---|
cols |
number |
Spalten |
rows |
number |
Zeilen |
cellPadding |
number |
Zellen-Abstand |
showLines |
boolean |
Linien zeigen? |
showPoints |
boolean |
Punkte zeigen? |
Views:
- PointGrid: Fokus auf Kreuzungspunkte und Linien
- CellGrid: Fokus auf Zellen als Mini-Canvases
ImageLayer
Bild-Darstellung.
Parameter:
| Parameter | Typ | Beschreibung |
|---|---|---|
src |
string |
Bild-URL |
fit |
'contain' | 'cover' | 'fill' |
Einpassung |
position |
{x, y} |
Position |
opacity |
number |
Transparenz |
ImageLayerDithering
Bild mit Dithering-Effekt.
Parameter:
| Parameter | Typ | Beschreibung |
|---|---|---|
src |
string |
Bild-URL |
ditherMode |
DitherMode |
Dithering-Algorithmus |
cellSize |
number |
Zellengröße |
shape |
DitherShape |
Shape pro Zelle |
Dither Modes:
| Mode | Beschreibung |
|---|---|
threshold |
Einfacher Schwellwert |
floydSteinberg |
Floyd-Steinberg |
atkinson |
Atkinson |
ordered |
Ordered Dithering |
halftone |
Halbton-Muster |
Dither Shapes:
| Shape | Beschreibung |
|---|---|
circle |
Kreise |
square |
Quadrate |
line |
Linien |
cross |
Kreuze |
custom |
Eigene Shapes |
Characters
Text und Einzelzeichen.
Parameter:
| Parameter | Typ | Beschreibung |
|---|---|---|
text |
string |
Anzuzeigender Text |
font |
string |
Schriftart |
fontSize |
number |
Schriftgröße |
color |
string |
Textfarbe |
position |
{x, y} |
Position |
DitherShapeGenerator
Generiert Shapes aus Dither-Daten für Plotter.
Methoden:
| Methode | Beschreibung |
|---|---|
generate(imageData, opts) |
Shapes generieren |
getShapes() |
Shape-Array abrufen |
Agent-Interface
Alle Agents implementieren:
interface Agent {
draw(props: ArtworkProps): void;
update?(deltaTime: number): void;
setParameter?(key: string, value: any): void;
}Tweakpane Integration
Jeder Agent hat ensureParameterSet() für Defaults:
// In configure()
Background.ensureParameterSet(parameter, colorset);
ColorSet.ensureParameterSet(parameter, ['palette1', 'palette2']);Wichtig: ensureParameterSet() muss VOR dem Tweakpane-Check aufgerufen werden (sonst crasht Exhibition Mode).