Monorepo for Aesthetic.Computer
aesthetic.computer
1% !TEX program = xelatex
2% Cards format — auto-generated from api.tex by cards-convert.mjs
3\documentclass[11pt]{article}
4
5\usepackage{fontspec}
6\usepackage{unicode-math}
7\setmainfont{Latin Modern Roman}
8\setsansfont{Latin Modern Sans}
9\setmonofont{Latin Modern Mono}[Scale=0.88]
10
11
12\usepackage{graphicx}
13\graphicspath{{figures/}}
14\usepackage{booktabs}
15\usepackage{tabularx}
16\usepackage{ragged2e}
17\usepackage{microtype}
18\usepackage{natbib}
19\usepackage{listings}
20
21\lstdefinelanguage{processing}{
22 morekeywords=[1]{void,int,float,boolean,color,String,class,new,if,else,for,while,return,public,private,extends,import},
23 morekeywords=[2]{setup,draw,mousePressed,mouseDragged,keyPressed,size,background,stroke,noStroke,fill,noFill,line,rect,ellipse,point,triangle,beginShape,endShape,vertex,translate,rotate,scale,pushMatrix,popMatrix,frameRate,width,height,mouseX,mouseY,pmouseX,pmouseY,key,keyCode,mouseButton,frameCount},
24 sensitive=true,
25 morecomment=[l]{//},
26 morecomment=[s]{/*}{*/},
27 morestring=[b]",
28}
29\lstdefinelanguage{p5js}{
30 morekeywords=[1]{function,let,const,var,if,else,for,while,return,new,class,export},
31 morekeywords=[2]{setup,draw,mousePressed,mouseDragged,keyPressed,createCanvas,background,stroke,noStroke,fill,noFill,line,rect,ellipse,point,triangle,beginShape,endShape,vertex,translate,rotate,scale,push,pop,frameRate,width,height,mouseX,mouseY,pmouseX,pmouseY,key,keyCode,mouseButton,frameCount,createGraphics,random,noise,map,constrain,dist,lerp},
32 sensitive=true,
33 morecomment=[l]{//},
34 morestring=[b]",
35 morestring=[b]',
36 morestring=[b]`,
37}
38\lstdefinelanguage{acjs}{
39 morekeywords=[1]{function,export,const,let,var,return,if,else,new,async,await,import,from,for},
40 morekeywords=[2]{wipe,ink,line,box,circle,write,screen,params,colon,jump,send,store,net,sound,speaker,pen,event,boot,paint,act,sim,leave,paste,plot,poly,flood,form,cursor,handle,num,geo,ui},
41 sensitive=true,
42 morecomment=[l]{//},
43 morestring=[b]",
44 morestring=[b]',
45 morestring=[b]`,
46}
47\lstdefinestyle{processingstyle}{
48 language=processing,
49 keywordstyle=[1]\color{pjkw}\bfseries,
50 keywordstyle=[2]\color{pjfn}\bfseries,
51 commentstyle=\color{pjcmt}\itshape,
52 stringstyle=\color{jsstr},
53}
54\lstdefinestyle{p5style}{
55 language=p5js,
56 keywordstyle=[1]\color{jskw}\bfseries,
57 keywordstyle=[2]\color{pjfn}\bfseries,
58 commentstyle=\color{jscmt}\itshape,
59 stringstyle=\color{jsstr},
60}
61\lstdefinestyle{acjsstyle}{
62 language=acjs,
63 keywordstyle=[1]\color{jskw}\bfseries,
64 keywordstyle=[2]\color{jsfn}\bfseries,
65 commentstyle=\color{jscmt}\itshape,
66 stringstyle=\color{jsstr},
67}
68\lstset{
69 basicstyle=\ttfamily\small,
70 breaklines=true,
71 frame=single,
72 rulecolor=\color{acgray!30},
73 backgroundcolor=\color{acgray!5},
74 xleftmargin=0.5em,
75 xrightmargin=0.5em,
76 aboveskip=0.5em,
77 belowskip=0.5em,
78 numbers=none,
79 tabsize=2,
80}
81
82\makeatletter
83\def\input@path{{../}}
84\makeatother
85\usepackage{ac-paper-cards}
86
87% Extra commands from base paper
88\definecolor{jskw}{RGB}{119,51,170}
89\definecolor{jsfn}{RGB}{0,136,170}
90\definecolor{jsstr}{RGB}{170,120,0}
91\definecolor{jsnum}{RGB}{204,0,102}
92\definecolor{jscmt}{RGB}{102,102,102}
93\definecolor{pjkw}{RGB}{204,102,0}
94\definecolor{pjfn}{RGB}{0,102,153}
95\definecolor{pjcmt}{RGB}{102,102,102}
96
97\hypersetup{
98 pdftitle={From setup() to boot(): Processing at the Core of the Piece API},
99}
100
101\renewcommand{\acpdfbase}{piece-api-26-arxiv}
102\begin{document}
103
104% ============================================================
105% TITLE CARD
106% ============================================================
107\thispagestyle{empty}
108\vspace*{\fill}
109\begin{center}
110\href{https://papers.aesthetic.computer}{\includegraphics[height=9em]{pals}}\par\vspace{0.1em}
111{\acbold\fontsize{18pt}{22pt}\selectfont\color{acdark} From \texttt{setup()} to \texttt{boot()}}\par
112\vspace{0.1em}
113{\fontsize{9pt}{11pt}\selectfont\color{acpink} Processing at the Core of the Piece API}\par
114\vspace{0.4em}
115{\normalsize\color{cyan!70!blue}\href{https://prompt.ac/@jeffrey}{\textbf{@jeffrey}}}\par
116{\small\color{acgray} Aesthetic.Computer}\par
117{\small\color{acgray} ORCID: \href{https://orcid.org/0009-0007-4460-4913}{0009-0007-4460-4913}}\par
118\vspace{0.4em}
119\rule{0.5\textwidth}{0.5pt}\par
120\vspace{0.15em}
121\colorbox{yellow!60}{\small\color{red!80!black}\textbf{\textit{working draft --- not for citation}}}\par
122\vspace{0.1em}
123{\footnotesize\color{acgray} March 2026 · \href{https://github.com/whistlegraph/aesthetic-computer/commit/8f14b5989}{8f14b5989}}\par
124\vspace{0.1em}
125{\footnotesize\color{acgray}\href{https://papers.aesthetic.computer/piece-api-26-arxiv-da.pdf}{Dansk} · \href{https://papers.aesthetic.computer/piece-api-26-arxiv-es.pdf}{Español} · \href{https://papers.aesthetic.computer/piece-api-26-arxiv-zh.pdf}{{\accjk 中文}} · \href{https://papers.aesthetic.computer/piece-api-26-arxiv-ja.pdf}{{\accjk 日本語}}}\par
126\end{center}
127\vspace*{\fill}
128
129% ============================================================
130% INDEX CARD
131% ============================================================
132\cardindex
133
134% ============================================================
135% BODY
136% ============================================================
137\section{Introduction}
138
139The history of creative coding APIs is a history of deciding what the programmer should say first. In Design By Numbers~\citep{maeda2001dbn}, the first statement was a coordinate and a grayscale value: \texttt{Paper 50}. In Processing~\citep{reas2003processing}, it was \texttt{size(200, 200)} inside \texttt{setup()}. In p5.js~\citep{mccarthy2015p5js}, it was \texttt{createCanvas(400, 400)}. In \ac{}, the programmer says nothing about the canvas at all---the runtime provides \texttt{screen.width} and \texttt{screen.height} as given facts, and the first meaningful statement is typically \texttt{wipe()}, clearing the screen to begin painting.
140
141These are not arbitrary differences. Each reflects a decision about what the platform assumes versus what the programmer must specify, and these decisions accumulate into fundamentally different relationships between author and machine. This paper traces the API lineage from Processing through p5.js to AC, examining each transition as a set of design moves: what was kept, what was changed, and what the change implies.
142
143The contribution is threefold: (1) a detailed technical comparison of the lifecycle models, drawing APIs, input systems, and state management strategies of Processing, p5.js, and AC; (2) an analysis of the design rationale behind AC's departures from the Processing model; and (3) an argument that the AC piece API embodies a shift from the sketchbook metaphor to what we call the \emph{instrument metaphor}---a model where the relationship between programmer and program is ongoing, performative, and practice-based rather than exploratory and disposable.
144
145% ============ 2. THE PROCESSING MODEL ============
146
147\section{The Processing Model (2001)}
148\label{sec:processing}
149
150Processing~\citep{reas2007processing} was designed as a ``software sketchbook'' for visual artists. Its API centers on two lifecycle functions and a library of global drawing primitives.
151
152\subsection{Lifecycle: \texttt{setup()} and \texttt{draw()}}
153
154\begin{lstlisting}[style=processingstyle,caption={Minimal Processing sketch.}]
155void setup() {
156 size(400, 400);
157 background(0);
158}
159
160void draw() {
161 stroke(255);
162 ellipse(mouseX, mouseY, 20, 20);
163}
164\end{lstlisting}
165
166\texttt{setup()} runs once; \texttt{draw()} runs every frame at a default 60fps. This two-function model is Processing's most influential design decision. It reduces the cognitive overhead of animation from managing a render loop to filling in two blanks: ``what happens once?'' and ``what happens every frame?''
167
168The model is deliberately minimal. There is no explicit \texttt{input()} function---mouse and keyboard state are available as global variables (\texttt{mouseX}, \texttt{mouseY}, \texttt{key}, \texttt{keyCode}) that update automatically. Event callbacks (\texttt{mousePressed()}, \texttt{keyPressed()}) exist but are optional supplements, not required entry points.
169
170\subsection{Drawing primitives}
171
172Processing's drawing API uses a \emph{stateful pipeline} model inherited from PostScript and OpenGL: state-setting calls (\texttt{stroke()}, \texttt{fill()}, \texttt{strokeWeight()}) modify a persistent graphics context, and shape calls (\texttt{ellipse()}, \texttt{rect()}, \texttt{line()}) render using that context. The context persists across frames unless explicitly reset.
173
174\begin{lstlisting}[style=processingstyle,caption={Stateful drawing context.}]
175void draw() {
176 fill(255, 0, 0); // Set fill: red
177 stroke(0); // Set stroke: black
178 strokeWeight(3); // Set weight: 3px
179 ellipse(100, 100, 50, 50); // Uses above
180 rect(200, 100, 50, 50); // Also uses above
181 // State persists into next frame
182}
183\end{lstlisting}
184
185This state persistence is both powerful (less code for uniform styles) and error-prone (forgotten state leaks across frames). Processing addresses this with \texttt{pushStyle()}/\texttt{popStyle()} and \texttt{pushMatrix()}/\texttt{popMatrix()}, but these are expert-level tools.
186
187\subsection{Global scope}
188
189All Processing programs share a single global namespace. Variables declared outside \texttt{setup()} and \texttt{draw()} are accessible everywhere. The drawing functions (\texttt{line()}, \texttt{ellipse()}, \texttt{background()}) are global. Input variables (\texttt{mouseX}, \texttt{mouseY}) are global. This eliminates the need to understand scope, imports, or dependency injection---critical for beginners---but makes programs impossible to compose or isolate.
190
191% ============ 3. THE P5.JS TRANSITION ============
192
193\section{The p5.js Transition (2014)}
194\label{sec:p5js}
195
196p5.js~\citep{mccarthy2015p5js} is a JavaScript reimplementation of Processing. Its primary contribution is bringing the Processing model to the browser, but the port required several adaptations.
197
198\subsection{Lifecycle preservation}
199
200\begin{lstlisting}[style=p5style,caption={Minimal p5.js sketch.}]
201function setup() {
202 createCanvas(400, 400);
203}
204
205function draw() {
206 background(220);
207 ellipse(mouseX, mouseY, 50, 50);
208}
209\end{lstlisting}
210
211The \texttt{setup()}/\texttt{draw()} model is preserved exactly. The cognitive model is identical: two functions, global drawing primitives, automatic animation loop. This continuity is deliberate---p5.js aims to be Processing for the web, not a new language.
212
213\subsection{Canvas creation}
214
215The most visible change is \texttt{createCanvas()} replacing \texttt{size()}. This is not cosmetic: in Processing, \texttt{size()} configures the application window; in p5.js, \texttt{createCanvas()} creates an HTML \texttt{<canvas>} element within the DOM. The sketch must negotiate with the existing page rather than owning the entire display.
216
217\subsection{Instance mode}
218
219p5.js introduces an important escape hatch from the global namespace: \emph{instance mode}.
220
221\begin{lstlisting}[style=p5style,caption={p5.js instance mode.}]
222const sketch = (p) => {
223 p.setup = () => {
224 p.createCanvas(400, 400);
225 };
226 p.draw = () => {
227 p.background(220);
228 p.ellipse(p.mouseX, p.mouseY, 50, 50);
229 };
230};
231new p5(sketch);
232\end{lstlisting}
233
234Instance mode wraps all API functions behind a namespace (\texttt{p.}), allowing multiple sketches on one page and avoiding global pollution. However, most p5.js code is written in global mode, and instance mode is typically encountered only when embedding sketches in larger applications. The prefix notation (\texttt{p.ellipse} vs.\ \texttt{ellipse}) increases verbosity and reduces the ``just write'' quality that makes Processing inviting.
235
236\subsection{What changed, what didn't}
237
238p5.js preserved: the two-function lifecycle, global drawing primitives, stateful graphics context, frame-based animation, and the ``sketch'' identity. It adapted: canvas creation to the DOM, renderer selection (2D/WebGL), event handling to browser events, and added instance mode for composition. It did not address: the conflation of simulation and rendering, the lack of structured input handling, or the single-file isolation problem.
239
240% ============ 4. THE AC PIECE API ============
241
242\section{The AC Piece API (2021--)}
243\label{sec:ac}
244
245\ac{}'s piece API~\citep{scudder2026ac} is built on Processing's core ideas---immediate-mode graphics, single-file programs, lifecycle functions---and extends them around five concerns instead of two.
246
247\subsection{Five lifecycle functions}
248
249\begin{lstlisting}[style=acjsstyle,caption={Minimal AC piece.}]
250function boot({ screen, params }) {
251 // Runs once on load
252}
253
254function paint({ wipe, ink, line, screen }) {
255 wipe("navy");
256 ink("pink").circle(
257 screen.width / 2,
258 screen.height / 2,
259 50
260 );
261}
262
263function act({ event: e }) {
264 if (e.is("keyboard:down:space")) {
265 // Handle spacebar
266 }
267}
268
269function sim() {
270 // Update state at 120fps
271}
272
273export { boot, paint, act, sim };
274\end{lstlisting}
275
276The five functions are:
277
278\begin{itemize}
279 \item \texttt{boot(\$api)} --- runs once when the piece loads. Extends Processing's \texttt{setup()}, with the screen provided by the runtime rather than configured by the programmer.
280 \item \texttt{paint(\$api)} --- runs every frame that needs rendering. Carries forward \texttt{draw()}'s immediate-mode model, but is purely visual: no logic, no state mutation (by convention).
281 \item \texttt{act(\$api)} --- called once per input event. Consolidates Processing's event callbacks (\texttt{mousePressed()}, \texttt{keyPressed()}) into a single, unified entry point.
282 \item \texttt{sim(\$api)} --- runs at a fixed 120Hz, potentially multiple times per rendered frame. Has no equivalent in Processing; closest analogue is the fixed-timestep game loop~\citep{nystrom2014game}.
283 \item \texttt{leave(\$api)} --- cleanup on exit. No equivalent in Processing, where sketches simply terminate.
284\end{itemize}
285
286Each function is optional. A piece that exports only \texttt{paint} is a valid, functioning program.
287
288\subsection{API injection via destructuring}
289
290The most structurally significant extension of the Processing model is that \textbf{no API functions exist in the global scope}. Every function the piece uses is received as a parameter:
291
292\begin{lstlisting}[style=acjsstyle,caption={API destructuring in AC.}]
293function paint({ wipe, ink, line, box,
294 circle, screen, num }) {
295 wipe(0, 0, 30);
296 ink(255, 100, 180);
297 const cx = num.lerp(0, screen.width, 0.5);
298 circle(cx, screen.height / 2, 40);
299}
300\end{lstlisting}
301
302This design has several consequences:
303
304\begin{enumerate}
305 \item \textbf{No global pollution.} Module-level variables are piece state; API functions are parameters. There is no ambient namespace to collide with.
306 \item \textbf{Self-documenting imports.} The destructuring pattern at the top of each function declares exactly which API surfaces the function uses, serving as an inline dependency manifest.
307 \item \textbf{Composability.} Multiple pieces can coexist in the same JavaScript context without API collisions, enabling the platform's piece-switching and embedding mechanisms.
308 \item \textbf{Discoverability.} Autocompletion in editors works on the destructured parameter object, providing a natural way to explore the API.
309\end{enumerate}
310
311This is the p5.js instance mode pattern taken to its conclusion: instead of prefixing every call with \texttt{p.}, the programmer destructures exactly the functions they need, once, at the function signature.
312
313\subsection{Separation of simulation and rendering}
314\label{sec:simsep}
315
316Processing's \texttt{draw()} conflates two concerns: updating state and rendering pixels. This works for simple sketches but creates problems as complexity grows: physics simulations tied to frame rate, input latency coupled to rendering cost, and difficulty separating ``what happened'' from ``what it looks like.''
317
318AC separates these explicitly:
319
320\begin{itemize}
321 \item \texttt{sim()} runs at a fixed 120Hz, independent of display refresh rate. On a 60Hz display, \texttt{sim()} runs twice per \texttt{paint()} call. On a 144Hz display, the ratio adjusts accordingly.
322 \item \texttt{paint()} runs at the display's refresh rate (capped at approximately 165fps), and is responsible only for rendering the current state.
323 \item \texttt{act()} runs once per input event, immediately when the event arrives.
324\end{itemize}
325
326This three-way split mirrors the architecture of modern game engines~\citep{nystrom2014game}: a fixed update tick for deterministic logic, a variable render tick for smooth display, and an event queue for input. The difference is that AC exposes this architecture as a first-class API rather than hiding it behind a framework.
327
328\subsection{Unified event handling}
329
330Processing distributes input handling across global variables and optional callbacks:
331
332\begin{lstlisting}[style=processingstyle]
333// Processing: scattered input model
334void draw() {
335 if (mousePressed) { /* poll state */ }
336}
337void mousePressed() { /* callback */ }
338void keyPressed() { /* callback */ }
339void mouseDragged() { /* callback */ }
340\end{lstlisting}
341
342AC consolidates all input into \texttt{act()} with a string-based event matching system:
343
344\begin{lstlisting}[style=acjsstyle]
345function act({ event: e, pen }) {
346 if (e.is("touch")) { }
347 if (e.is("draw")) { }
348 if (e.is("lift")) { }
349 if (e.is("keyboard:down:a")) { }
350 if (e.is("keyboard:down:space")){ }
351 if (e.is("gamepad:a")) { }
352 if (e.is("reframed")) { }
353}
354\end{lstlisting}
355
356The \texttt{event.is()} pattern provides a uniform interface across input modalities (touch, mouse, keyboard, gamepad, MIDI, hand tracking) through a single function. Event strings are hierarchical (\texttt{keyboard:down:a}) and can match at any level of specificity. This replaces the combinatorial explosion of Processing callbacks with a single, filterable stream.
357
358\subsection{Drawing primitives: stateless by default}
359
360Processing and p5.js use a stateful graphics context where \texttt{fill()}, \texttt{stroke()}, and transformation calls persist until explicitly changed. AC inverts this: the \texttt{ink()} function sets color for the \emph{immediately following} draw call and returns the API object for chaining:
361
362\begin{lstlisting}[style=acjsstyle]
363function paint({ wipe, ink, line, circle }) {
364 wipe("black");
365 ink("red").circle(50, 50, 20);
366 ink("blue").line(0, 0, 100, 100);
367 // No state leaks between calls
368}
369\end{lstlisting}
370
371The \texttt{ink()} return-and-chain pattern makes color-shape pairs visually atomic: each drawing operation is a self-contained expression rather than a sequence of context mutations. This eliminates the class of bugs where forgotten \texttt{fill()} or \texttt{stroke()} calls from a previous frame (or a previous function) bleed into unrelated drawing.
372
373The \texttt{wipe()} function replaces Processing's \texttt{background()}, using a shorter, more active verb. This naming is deliberate: ``wipe'' suggests a physical action (erasing a surface) rather than a property setting.
374
375\subsection{No canvas configuration}
376
377In Processing, the first line of \texttt{setup()} is typically \texttt{size(w, h)}. In p5.js, it is \texttt{createCanvas(w, h)}. In AC, there is no equivalent call. The runtime provides the canvas at the device's native resolution, and pieces receive \texttt{screen.width} and \texttt{screen.height} as read-only properties.
378
379This reflects a mobile-first design philosophy: on phones and tablets, the ``correct'' canvas size is the device screen. Allowing the programmer to specify dimensions creates a mismatch between the fixed canvas and the variable viewport. AC eliminates this mismatch by making the canvas responsive by default.
380
381% ============ 5. API SURFACE COMPARISON ============
382
383\section{API Surface Comparison}
384\label{sec:comparison}
385
386Table~\ref{tab:lifecycle} compares the lifecycle models. Table~\ref{tab:drawing} compares drawing primitives.
387
388\begin{table}[h]
389\small
390\centering
391\begin{tabular}{lp{0.28\linewidth}p{0.28\linewidth}p{0.28\linewidth}}
392\toprule
393 & \textbf{Processing} & \textbf{p5.js} & \textbf{AC} \\
394\midrule
395Init & \texttt{setup()} & \texttt{setup()} & \texttt{boot(\$)} \\
396Render & \texttt{draw()} & \texttt{draw()} & \texttt{paint(\$)} \\
397Logic & (in draw) & (in draw) & \texttt{sim(\$)} \\
398Input & callbacks & callbacks & \texttt{act(\$)} \\
399Cleanup & --- & \texttt{remove()} & \texttt{leave(\$)} \\
400\midrule
401Render rate & 60fps & 60fps & display Hz \\
402Logic rate & 60fps & 60fps & 120fps fixed \\
403Scope & global & global/inst. & injected \\
404\bottomrule
405\end{tabular}
406\caption{Lifecycle comparison. \texttt{\$} denotes destructured API injection.}
407\label{tab:lifecycle}
408\end{table}
409
410\begin{table}[h]
411\small
412\centering
413\begin{tabular}{lp{0.28\linewidth}p{0.28\linewidth}}
414\toprule
415\textbf{Processing/p5} & \textbf{AC} & \textbf{Notes} \\
416\midrule
417\texttt{background()} & \texttt{wipe()} & Verb, not property \\
418\texttt{fill() + stroke()} & \texttt{ink()} & Unified, chainable \\
419\texttt{ellipse()} & \texttt{circle()} & Named for shape \\
420\texttt{rect()} & \texttt{box()} & Shorter name \\
421\texttt{line()} & \texttt{line()} & Unchanged \\
422\texttt{point()} & \texttt{plot()} & Graph metaphor \\
423\texttt{text()} & \texttt{write()} & Active verb \\
424--- & \texttt{flood()} & Fill region \\
425--- & \texttt{paste()} & Buffer compositing \\
426--- & \texttt{form()} & 3D rendering \\
427\bottomrule
428\end{tabular}
429\caption{Drawing primitive comparison.}
430\label{tab:drawing}
431\end{table}
432
433\subsection{Naming philosophy}
434
435Processing's API names are descriptive nouns and adjectives: \texttt{background}, \texttt{ellipse}, \texttt{rect}, \texttt{stroke}, \texttt{fill}. They describe \emph{what} is being set or drawn. AC's names are active verbs: \texttt{wipe}, \texttt{ink}, \texttt{plot}, \texttt{write}, \texttt{flood}, \texttt{paste}. They describe \emph{what the programmer is doing}---physical actions performed on a surface.
436
437This shift from descriptive to imperative naming aligns with the instrument metaphor: an instrument's interface is understood through verbs (press, blow, strike, pluck), not nouns. The AC API reads as a sequence of actions: ``wipe the screen, ink it pink, draw a circle, write some text.''
438
439\subsection{Color model}
440
441Processing uses separate \texttt{fill()} and \texttt{stroke()} calls, each accepting RGB, HSB, or hex values. The fill/stroke distinction maps to vector graphics (SVG, PostScript) where shapes have interior color and boundary color.
442
443AC uses a single \texttt{ink()} call that sets color for all subsequent operations. There is no fill/stroke distinction: a \texttt{circle()} is filled or stroked based on its parameters, not on ambient context. The \texttt{ink()} function accepts:
444
445\begin{itemize}
446 \item RGB values: \texttt{ink(255, 100, 50)}
447 \item Named colors: \texttt{ink("pink")}, \texttt{ink("navy")}
448 \item Grayscale: \texttt{ink(128)}
449 \item Alpha: \texttt{ink(255, 0, 0, 128)}
450\end{itemize}
451
452Named colors are a significant usability choice for beginners. Where Processing requires \texttt{fill(255, 192, 203)} for pink, AC accepts \texttt{ink("pink")}. The named color vocabulary is intentionally small and evocative, closer to a paint box than a color picker.
453
454% ============ 6. STATE MANAGEMENT ============
455
456\section{State Management}
457\label{sec:state}
458
459\subsection{Processing: global variables}
460
461\begin{lstlisting}[style=processingstyle]
462int x = 100;
463int y = 100;
464
465void draw() {
466 background(0);
467 x += 1;
468 ellipse(x, y, 20, 20);
469}
470\end{lstlisting}
471
472State in Processing lives in global variables. This is simple but has well-known problems: all state is mutable from anywhere, there is no encapsulation, and program state is indistinguishable from API state.
473
474\subsection{AC: module-level closures}
475
476\begin{lstlisting}[style=acjsstyle]
477let x = 100;
478let y = 100;
479
480function sim() {
481 x += 1;
482}
483
484function paint({ wipe, ink, circle }) {
485 wipe(0);
486 ink(255).circle(x, y, 20);
487}
488
489export { sim, paint };
490\end{lstlisting}
491
492AC pieces are ES modules. Variables declared at module scope are private to the piece---invisible to the runtime, other pieces, and the global scope. The \texttt{export} statement makes only the lifecycle functions visible. This is not a convention enforced by documentation; it is a guarantee of the JavaScript module system.
493
494The separation of state mutation (\texttt{sim}) from state rendering (\texttt{paint}) encourages a discipline where \texttt{paint} is a pure function of module state---it reads variables and draws, but does not modify them. This is not enforced, but the API structure makes it the natural pattern.
495
496% ============ 7. THE GENEALOGY ============
497
498\section{The Genealogy}
499\label{sec:genealogy}
500
501\subsection{Design By Numbers (1999)}
502
503Maeda's Design By Numbers~\citep{maeda2001dbn} introduced the core insight: a programming environment for visual output, with the simplest possible API. DBN had no animation loop---programs ran once, top to bottom. The primitive set was minimal: \texttt{Paper} (background), \texttt{Pen} (stroke weight), \texttt{Line}, \texttt{Set} (pixel), and control flow. The entire language could be learned in an afternoon.
504
505AC inherits DBN's minimalism in naming (short, active verbs) and its conviction that the API should be exhaustively learnable.
506
507\subsection{Processing (2001)}
508
509Processing~\citep{reas2003processing} added what DBN lacked: animation (\texttt{draw()} loop), interaction (\texttt{mouseX/Y}), and a richer primitive set. It also added what DBN deliberately avoided: state (the graphics context), a standard library (math, typography, image loading), and a compilation step (Java). Processing's greatest innovation was not any single function but the \texttt{setup()}/\texttt{draw()} pair: the simplest possible expression of interactive animation.
510
511AC inherits the lifecycle function model but splits \texttt{draw()} into three concerns (\texttt{paint}, \texttt{sim}, \texttt{act}).
512
513\subsection{p5.js (2014)}
514
515p5.js~\citep{mccarthy2015p5js} brought Processing to the browser, making sketches instantly shareable via URL. This was a prerequisite for AC: the browser as creative platform. p5.js also introduced instance mode, foreshadowing AC's API injection pattern.
516
517AC inherits the browser-native assumption and the shareability principle (every piece is a URL), but replaces the library-in-a-page model with a full runtime: pieces do not include a \texttt{<script>} tag; they are loaded by the platform.
518
519\subsection{openFrameworks (2005)}
520
521openFrameworks~\citep{openframeworks2005} used a similar lifecycle (\texttt{setup()}, \texttt{update()}, \texttt{draw()}) but in C++, separating update logic from rendering. AC's \texttt{sim()}/\texttt{paint()} split is closer to this model than to Processing's unified \texttt{draw()}.
522
523\subsection{The instrument turn}
524
525The genealogy can be summarized as a series of separations:
526
527\begin{enumerate}
528 \item \textbf{DBN}: one-shot execution (no animation loop).
529 \item \textbf{Processing}: init + render (\texttt{setup} + \texttt{draw}).
530 \item \textbf{openFrameworks}: init + update + render.
531 \item \textbf{AC}: init + input + update + render + cleanup (\texttt{boot} + \texttt{act} + \texttt{sim} + \texttt{paint} + \texttt{leave}).
532\end{enumerate}
533
534Each step separates concerns that were previously conflated. AC's five-function model is the fullest decomposition of the interactive program lifecycle into named, single-responsibility entry points. The result resembles the perception-action cycle of embodied cognition~\citep{varela1991embodied}: perceive (\texttt{act}), think (\texttt{sim}), act (\texttt{paint}), and the additional bookends of birth (\texttt{boot}) and death (\texttt{leave}).
535
536% ============ 8. WORKED EXAMPLE ============
537
538\section{Worked Example: A Bouncing Ball}
539\label{sec:example}
540
541To make the comparison concrete, we implement a bouncing ball in all three systems.
542
543\subsection{Processing}
544
545\begin{lstlisting}[style=processingstyle]
546float x = 200, y = 200;
547float vx = 3, vy = 2;
548
549void setup() {
550 size(400, 400);
551}
552
553void draw() {
554 background(0);
555 x += vx; y += vy;
556 if (x < 0 || x > width) vx *= -1;
557 if (y < 0 || y > height) vy *= -1;
558 fill(255, 100, 180);
559 noStroke();
560 ellipse(x, y, 30, 30);
561}
562\end{lstlisting}
563
564Logic and rendering are interleaved in \texttt{draw()}. State mutation (\texttt{x += vx}), boundary checking, and drawing all share one function.
565
566\subsection{p5.js}
567
568\begin{lstlisting}[style=p5style]
569let x = 200, y = 200;
570let vx = 3, vy = 2;
571
572function setup() {
573 createCanvas(400, 400);
574}
575
576function draw() {
577 background(0);
578 x += vx; y += vy;
579 if (x < 0 || x > width) vx *= -1;
580 if (y < 0 || y > height) vy *= -1;
581 fill(255, 100, 180);
582 noStroke();
583 ellipse(x, y, 30, 30);
584}
585\end{lstlisting}
586
587Structurally identical to Processing. The only changes are syntactic: \texttt{let} vs.\ \texttt{float}, \texttt{createCanvas} vs.\ \texttt{size}.
588
589\subsection{AC}
590
591\begin{lstlisting}[style=acjsstyle]
592let x, y, vx = 3, vy = 2;
593
594function boot({ screen }) {
595 x = screen.width / 2;
596 y = screen.height / 2;
597}
598
599function sim({ screen }) {
600 x += vx; y += vy;
601 if (x < 0 || x > screen.width) vx *= -1;
602 if (y < 0 || y > screen.height) vy *= -1;
603}
604
605function paint({ wipe, ink, circle }) {
606 wipe(0);
607 ink(255, 100, 180).circle(x, y, 15);
608}
609
610export { boot, sim, paint };
611\end{lstlisting}
612
613The concerns are separated: \texttt{boot} initializes state relative to the actual screen, \texttt{sim} updates physics at 120Hz (ensuring consistent behavior across display refresh rates), and \texttt{paint} renders without modifying state. The \texttt{ink().circle()} chain replaces three lines (\texttt{fill}, \texttt{noStroke}, \texttt{ellipse}).
614
615% ============ 9. DESIGN RATIONALE ============
616
617\section{Design Rationale}
618\label{sec:rationale}
619
620\subsection{Why five functions?}
621
622The five-function model is not motivated by software engineering rigor (``separation of concerns'' as dogma) but by the instrument metaphor. A musical instrument has distinct phases: you pick it up (boot), you listen and respond (act), you think about what comes next (sim), you play (paint), and eventually you put it down (leave). These are not interchangeable moments---you do not tune the instrument while performing, and you do not perform while putting it away. The lifecycle functions formalize these distinctions.
623
624\subsection{Why inject the API?}
625
626Global APIs are convenient for beginners but create an implicit dependency on the platform. A Processing sketch cannot be understood without knowing that \texttt{ellipse()} is a Processing function, not a user function. AC's destructuring pattern makes the dependency explicit: if \texttt{circle} appears in the function body, it appears in the function signature. This is the same design principle behind ES module imports, applied at the function level.
627
628The practical benefit is hot-reloading: because pieces do not capture global references, the runtime can replace the API object between reloads without invalidating the piece's closures.
629
630\subsection{Why 120Hz simulation?}
631
632Processing's \texttt{draw()} runs at the display rate (typically 60fps). This means physics simulations, animation timing, and input processing all run at the same rate as pixel output. On a 144Hz display, a Processing sketch runs 2.4$\times$ faster; on a 30Hz display, it runs at half speed.
633
634AC decouples simulation from display by running \texttt{sim()} at a fixed 120Hz. This ensures deterministic behavior: a bouncing ball moves at the same speed regardless of display refresh rate. The 120Hz rate was chosen as a multiple of common display rates (60, 120) and a reasonable upper bound for input responsiveness.
635
636\subsection{Why no canvas size?}
637
638Requiring \texttt{size()} or \texttt{createCanvas()} assumes the programmer knows (and cares about) the output resolution. On desktop, this is reasonable. On mobile---AC's primary target---it is a source of friction: the ``right'' size depends on the device, orientation, and pixel density, none of which the programmer should need to manage. AC provides the screen as a given, like a canvas that is already stretched and primed.
639
640% ============ 10. ADDITIONAL LIFECYCLE ============
641
642\section{Extended Lifecycle}
643\label{sec:extended}
644
645Beyond the core five functions, AC pieces may export additional lifecycle hooks:
646
647\begin{itemize}
648 \item \texttt{beat(\$api)} --- called once per metronome tick. The BPM is set via \texttt{sound.bpm}. This has no equivalent in Processing; it reflects AC's orientation toward musical applications.
649 \item \texttt{preview(\$api)} --- renders a static thumbnail image for the piece. Used in piece listings and social sharing.
650 \item \texttt{icon(\$api)} --- renders a favicon for the browser tab.
651 \item \texttt{meta()} --- returns \texttt{\{title, desc\}} metadata for Open Graph tags.
652 \item \texttt{receive(event)} --- handles messages from other pieces or the system, enabling inter-piece communication.
653\end{itemize}
654
655The \texttt{beat()} function is particularly notable. It elevates rhythmic timing from a feature the programmer must implement (via \texttt{millis()} in Processing) to a first-class lifecycle event. This is an API-level statement that music and rhythm are core use cases, not afterthoughts.
656
657% ============ 11. CONCLUSION ============
658
659\section{Conclusion}
660\label{sec:conclusion}
661
662Processing's core insight---that a programming environment for creative work should provide a lifecycle, not just a language---lives at the center of every AC piece. The path from \texttt{setup()}/\texttt{draw()} to \texttt{boot()}/\texttt{paint()}/\texttt{act()}/\texttt{sim()}/\texttt{leave()} is not a departure from Processing but an argument about what Processing's model is capable of when extended further.
663
664Processing proved that \texttt{setup()} + \texttt{draw()} was enough to make animation accessible. The AC piece API argues that the same immediate-mode, lifecycle-driven approach---when decomposed into five functions instead of two---can support not just sketching but \emph{practicing}: returning to the same piece, refining it, performing with it, building fluency over time.
665
666The sketchbook metaphor (write, run, discard) and the instrument metaphor (boot, play, practice, return) are not opposed. They are points on the same continuum. Processing showed that the continuum exists. AC argues it extends further than we thought---that \texttt{setup()} + \texttt{draw()} was the beginning of an idea whose full shape requires \texttt{boot} + \texttt{act} + \texttt{sim} + \texttt{paint} + \texttt{leave}.
667
668The API is the instrument. Processing is its core. How the API decomposes the act of programming determines what gets made.
669
670\bibliographystyle{plainnat}
671\bibliography{references}
672
673\end{document}