Monorepo for Aesthetic.Computer
aesthetic.computer
1# Aesthetic Computer Piece Structure
2
3*Understanding how to create and structure AC pieces*
4
5## Overview
6
7Aesthetic Computer pieces are JavaScript modules that define interactive experiences. Each piece exports specific functions that hook into the AC lifecycle, providing entry points for initialization, rendering, input handling, and cleanup.
8
9## Piece Lifecycle
10
11### Core Functions
12
13Every piece can export these optional functions:
14
15#### `boot({ ... })`
16**Purpose**: Initialize the piece when it starts
17**When Called**: Once when the piece loads
18**Common Uses**: Setup variables, load resources, configure settings
19
20```javascript
21export function boot({ wipe, screen, resolution }) {
22 // Initialize piece state
23 resolution(800, 600);
24 console.log(`Piece started with screen: ${screen.width}x${screen.height}`);
25}
26```
27
28#### `paint({ ... })`
29**Purpose**: Render the visual output
30**When Called**: Every frame at the display refresh rate (typically 60fps)
31**Common Uses**: Draw graphics, update animations, render UI
32
33```javascript
34export function paint({ wipe, ink, box, circle }) {
35 wipe("black"); // Clear screen
36 ink("white"); // Set color
37 box(50, 50, 100, 100); // Draw rectangle
38 circle(200, 200, 50); // Draw circle
39}
40```
41
42#### `act({ event, ... })`
43**Purpose**: Handle user input and system events
44**When Called**: When input events occur (clicks, key presses, etc.)
45**Common Uses**: Respond to user interaction, state changes
46
47```javascript
48export function act({ event, pointer, keyboard }) {
49 if (event.is("pointer:down")) {
50 console.log(`Clicked at: ${pointer.x}, ${pointer.y}`);
51 }
52
53 if (event.is("keyboard:down:space")) {
54 console.log("Space key pressed");
55 }
56}
57```
58
59#### `sim({ ... })`
60**Purpose**: Update simulation logic
61**When Called**: At a fixed rate (typically 120fps), independent of rendering
62**Common Uses**: Physics calculations, game logic, state updates
63
64```javascript
65let position = 0;
66export function sim({ }) {
67 // Update position independent of framerate
68 position += 0.5;
69 if (position > 800) position = 0;
70}
71```
72
73#### `beat({ ... })`
74**Purpose**: Synchronize with musical timing
75**When Called**: On metronome beats based on BPM setting
76**Common Uses**: Musical synchronization, rhythmic animations
77
78```javascript
79export function beat({ bpm }) {
80 console.log(`Beat at ${bpm} BPM`);
81 // Trigger rhythmic events
82}
83```
84
85#### `leave({ ... })`
86**Purpose**: Clean up before the piece unloads
87**When Called**: Right before switching to another piece
88**Common Uses**: Save state, clean up resources, send final data
89
90```javascript
91export function leave({ store }) {
92 store["myPiece:lastPosition"] = position;
93 console.log("Piece is leaving");
94}
95```
96
97### Optional Functions
98
99#### `meta({ ... })`
100**Purpose**: Define piece metadata
101**When Called**: Once during piece initialization
102**Common Uses**: Set title, description, configuration
103
104```javascript
105export function meta({ store }) {
106 return {
107 title: "My Amazing Piece",
108 description: "An interactive art experience",
109 author: "Artist Name"
110 };
111}
112```
113
114#### `preview({ ... })`
115**Purpose**: Create custom thumbnail
116**When Called**: When generating piece previews
117**Common Uses**: Draw representative thumbnail image
118
119```javascript
120export function preview({ wipe, ink, write, slug }) {
121 wipe(64);
122 ink(255);
123 write(slug, { center: "xy", size: 1 });
124}
125```
126
127## API Access
128
129Each lifecycle function receives an API object containing all available functions and data:
130
131### Common API Properties
132- **Graphics**: `wipe`, `ink`, `box`, `circle`, `line`, `plot`, `write`
133- **Input**: `pointer`, `keyboard`, `event`
134- **Screen**: `screen` (width, height), `resolution`
135- **Time**: `frame`, `time`, `beat`
136- **Storage**: `store` (persistent data)
137- **Network**: `send`, `receive`, `session`
138- **Audio**: `tone`, `noise`, `sound`
139- **Utilities**: `random`, `map`, `constrain`
140
141### Destructuring Pattern
142```javascript
143export function paint({ wipe, ink, box, screen, pointer }) {
144 // Only destructure what you need
145 wipe("black");
146 ink("cyan");
147 box(pointer.x, pointer.y, 50, 50);
148}
149```
150
151## Piece Types
152
153### Interactive Pieces
154Focus on user input and response:
155```javascript
156let drawing = [];
157
158export function paint({ wipe, ink, line }) {
159 wipe("black");
160 ink("white");
161
162 // Draw all lines in drawing array
163 for (let i = 0; i < drawing.length - 1; i++) {
164 line(drawing[i].x, drawing[i].y,
165 drawing[i+1].x, drawing[i+1].y);
166 }
167}
168
169export function act({ event, pointer }) {
170 if (event.is("pointer:down") || event.is("pointer:drag")) {
171 drawing.push({ x: pointer.x, y: pointer.y });
172 }
173}
174```
175
176### Generative Pieces
177Focus on procedural generation:
178```javascript
179export function paint({ wipe, ink, circle, screen, random }) {
180 wipe("navy");
181 ink("cyan");
182
183 // Generate random circles
184 for (let i = 0; i < 50; i++) {
185 circle(
186 random() * screen.width,
187 random() * screen.height,
188 random() * 20 + 5
189 );
190 }
191}
192```
193
194### Animation Pieces
195Focus on time-based changes:
196```javascript
197let rotation = 0;
198
199export function sim() {
200 rotation += 0.02; // Update rotation in sim for smooth animation
201}
202
203export function paint({ wipe, ink, box, screen, sin, cos }) {
204 wipe("black");
205 ink("red");
206
207 const centerX = screen.width / 2;
208 const centerY = screen.height / 2;
209 const radius = 100;
210
211 const x = centerX + sin(rotation) * radius;
212 const y = centerY + cos(rotation) * radius;
213
214 box(x, y, 20, 20, "center");
215}
216```
217
218## Configuration & Exports
219
220### System Configuration
221```javascript
222// Export configuration for special systems
223export const system = "nopaint"; // Use nopaint system
224export const palette = "custom"; // Custom color palette
225```
226
227### Piece Settings
228```javascript
229// Piece-specific settings
230export const wrap = true; // Enable coordinate wrapping
231export const autolock = false; // Disable auto-locking
232```
233
234## Best Practices
235
236### Performance
237- Keep `paint` function efficient (called 60+ times per second)
238- Use `sim` for heavy calculations
239- Minimize object creation in hot paths
240- Cache expensive calculations
241
242### State Management
243- Use module-level variables for piece state
244- Use `store` for persistent data across sessions
245- Initialize state in `boot`, clean up in `leave`
246
247### User Experience
248- Provide visual feedback for interactions
249- Handle edge cases gracefully
250- Consider accessibility (keyboard navigation, etc.)
251
252### Code Organization
253```javascript
254// State at module level
255let gameState = { score: 0, level: 1 };
256let particles = [];
257
258// Helper functions
259function createParticle(x, y) {
260 return { x, y, vx: random(-2, 2), vy: random(-2, 2) };
261}
262
263// Lifecycle functions
264export function boot({ screen }) {
265 // Initialize particles
266 for (let i = 0; i < 10; i++) {
267 particles.push(createParticle(
268 random() * screen.width,
269 random() * screen.height
270 ));
271 }
272}
273
274export function sim() {
275 // Update particle positions
276 particles.forEach(p => {
277 p.x += p.vx;
278 p.y += p.vy;
279 });
280}
281
282export function paint({ wipe, ink, circle }) {
283 wipe("black");
284 ink("white");
285
286 // Render particles
287 particles.forEach(p => {
288 circle(p.x, p.y, 3);
289 });
290}
291```
292
293## Template Examples
294
295See the `/templates` folder for complete piece templates demonstrating different patterns and use cases.
296
297---
298
299*For more details on the API functions available in each lifecycle function, see the [JavaScript API Reference](../api/javascript-api.md).*