Monorepo for Aesthetic.Computer aesthetic.computer
at main 774 lines 38 kB view raw
1% !TEX program = xelatex 2\documentclass[10pt,letterpaper,twocolumn]{article} 3 4% === GEOMETRY === 5\usepackage[top=0.75in, bottom=0.75in, left=0.75in, right=0.75in]{geometry} 6 7% === FONTS === 8\usepackage{fontspec} 9\usepackage{unicode-math} 10\setmainfont{Latin Modern Roman} 11\setsansfont{Latin Modern Sans} 12\setmonofont{Latin Modern Mono}[Scale=0.85] 13\newfontfamily\acbold{ywft-processing-bold}[ 14 Path=../../system/public/type/webfonts/, 15 Extension=.ttf 16] 17\newfontfamily\aclight{ywft-processing-light}[ 18 Path=../../system/public/type/webfonts/, 19 Extension=.ttf 20] 21 22% === PACKAGES === 23\usepackage{xcolor} 24\usepackage{titlesec} 25\usepackage{enumitem} 26\usepackage{booktabs} 27\usepackage{tabularx} 28\usepackage{fancyhdr} 29\usepackage{hyperref} 30\usepackage{graphicx} 31\usepackage{ragged2e} 32\usepackage{microtype} 33\usepackage{listings} 34\usepackage{natbib} 35\usepackage[colorspec=0.92]{draftwatermark} 36 37% === COLORS === 38\definecolor{acpink}{RGB}{180,72,135} 39\definecolor{acpurple}{RGB}{120,80,180} 40\definecolor{acdark}{RGB}{64,56,74} 41\definecolor{acgray}{RGB}{119,119,119} 42\definecolor{draftcolor}{RGB}{180,72,135} 43 44% === DRAFT WATERMARK === 45\DraftwatermarkOptions{ 46 text=WORKING DRAFT, 47 fontsize=3cm, 48 color=draftcolor!18, 49 angle=45, 50 pos={0.5\paperwidth, 0.5\paperheight} 51} 52 53% === JS SYNTAX COLORS === 54\definecolor{jskw}{RGB}{119,51,170} 55\definecolor{jsfn}{RGB}{0,136,170} 56\definecolor{jsstr}{RGB}{170,120,0} 57\definecolor{jsnum}{RGB}{204,0,102} 58\definecolor{jscmt}{RGB}{102,102,102} 59 60% === PROCESSING SYNTAX COLORS === 61\definecolor{pjkw}{RGB}{204,102,0} 62\definecolor{pjfn}{RGB}{0,102,153} 63\definecolor{pjcmt}{RGB}{102,102,102} 64 65% === HYPERREF === 66\hypersetup{ 67 colorlinks=true, 68 linkcolor=acpurple, 69 urlcolor=acpurple, 70 citecolor=acpurple, 71 pdfauthor={@jeffrey}, 72 pdftitle={From setup() to boot(): Processing at the Core of the Piece API}, 73} 74 75% === SECTION FORMATTING === 76\titleformat{\section} 77 {\normalfont\bfseries\normalsize\uppercase} 78 {\thesection.} 79 {0.5em} 80 {} 81\titlespacing{\section}{0pt}{1.2em}{0.3em} 82 83\titleformat{\subsection} 84 {\normalfont\bfseries\small} 85 {\thesubsection} 86 {0.5em} 87 {} 88\titlespacing{\subsection}{0pt}{0.8em}{0.2em} 89 90\titleformat{\subsubsection} 91 {\normalfont\itshape\small} 92 {\thesubsubsection} 93 {0.5em} 94 {} 95\titlespacing{\subsubsection}{0pt}{0.6em}{0.1em} 96 97% === HEADER/FOOTER === 98\pagestyle{fancy} 99\fancyhf{} 100\renewcommand{\headrulewidth}{0pt} 101\fancyhead[C]{\footnotesize\color{draftcolor}\textit{Working Draft --- not for citation}} 102\fancyfoot[C]{\footnotesize\thepage} 103 104% === LIST SETTINGS === 105\setlist[itemize]{nosep, leftmargin=1.2em, itemsep=0.1em} 106\setlist[enumerate]{nosep, leftmargin=1.2em} 107 108% === COLUMN SEPARATION === 109\setlength{\columnsep}{1.8em} 110 111% === PARAGRAPH SETTINGS === 112\setlength{\parindent}{1em} 113\setlength{\parskip}{0.3em} 114 115% Hyphenation for narrow two-column layout 116\tolerance=800 117\emergencystretch=1em 118\hyphenpenalty=50 119 120% === LISTINGS === 121\lstdefinelanguage{processing}{ 122 morekeywords=[1]{void,int,float,boolean,color,String,class,new,if,else,for,while,return,public,private,extends,import}, 123 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}, 124 sensitive=true, 125 morecomment=[l]{//}, 126 morecomment=[s]{/*}{*/}, 127 morestring=[b]", 128} 129 130\lstdefinelanguage{p5js}{ 131 morekeywords=[1]{function,let,const,var,if,else,for,while,return,new,class,export}, 132 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}, 133 sensitive=true, 134 morecomment=[l]{//}, 135 morestring=[b]", 136 morestring=[b]', 137 morestring=[b]`, 138} 139 140\lstdefinelanguage{acjs}{ 141 morekeywords=[1]{function,export,const,let,var,return,if,else,new,async,await,import,from,for}, 142 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}, 143 sensitive=true, 144 morecomment=[l]{//}, 145 morestring=[b]", 146 morestring=[b]', 147 morestring=[b]`, 148} 149 150\lstdefinestyle{processingstyle}{ 151 language=processing, 152 keywordstyle=[1]\color{pjkw}\bfseries, 153 keywordstyle=[2]\color{pjfn}\bfseries, 154 commentstyle=\color{pjcmt}\itshape, 155 stringstyle=\color{jsstr}, 156} 157 158\lstdefinestyle{p5style}{ 159 language=p5js, 160 keywordstyle=[1]\color{jskw}\bfseries, 161 keywordstyle=[2]\color{pjfn}\bfseries, 162 commentstyle=\color{jscmt}\itshape, 163 stringstyle=\color{jsstr}, 164} 165 166\lstdefinestyle{acjsstyle}{ 167 language=acjs, 168 keywordstyle=[1]\color{jskw}\bfseries, 169 keywordstyle=[2]\color{jsfn}\bfseries, 170 commentstyle=\color{jscmt}\itshape, 171 stringstyle=\color{jsstr}, 172} 173 174\lstset{ 175 basicstyle=\ttfamily\small, 176 breaklines=true, 177 frame=single, 178 rulecolor=\color{acgray!30}, 179 backgroundcolor=\color{acgray!5}, 180 xleftmargin=0.5em, 181 xrightmargin=0.5em, 182 aboveskip=0.5em, 183 belowskip=0.5em, 184 numbers=none, 185 tabsize=2, 186} 187 188\newcommand{\acdot}{{\color{acpink}.}} 189\newcommand{\ac}{\textsc{Aesthetic.Computer}} 190% Random caps for Aesthetic.Computer branding 191\newcount\acrandtmp 192\newcommand{\acrandletter}[2]{% 193 \acrandtmp=\uniformdeviate 2\relax 194 \ifnum\acrandtmp=0\relax#1\else#2\fi% 195} 196\newcommand{\acrandname}{% 197 \acrandletter{a}{A}\acrandletter{e}{E}\acrandletter{s}{S}\acrandletter{t}{T}% 198 \acrandletter{h}{H}\acrandletter{e}{E}\acrandletter{t}{T}\acrandletter{i}{I}% 199 \acrandletter{c}{C}{\color{acpink}.}\acrandletter{c}{C}\acrandletter{o}{O}% 200 \acrandletter{m}{M}\acrandletter{p}{P}\acrandletter{u}{U}\acrandletter{t}{T}% 201 \acrandletter{e}{E}\acrandletter{r}{R}% 202} 203 204\begin{document} 205 206% ============ TITLE BLOCK ============ 207 208\twocolumn[{% 209\begin{center} 210{\acbold\fontsize{22pt}{26pt}\selectfont\color{acdark} From \texttt{setup()} to \texttt{boot()}}\par 211\vspace{0.2em} 212{\aclight\fontsize{11pt}{13pt}\selectfont\color{acpink} Processing at the Core of the Piece API}\par 213\vspace{0.6em} 214{\normalsize\href{https://prompt.ac/@jeffrey}{@jeffrey}}\par 215{\small\color{acgray} Aesthetic.Computer}\par 216{\small\color{acgray} ORCID: \href{https://orcid.org/0009-0007-4460-4913}{0009-0007-4460-4913}}\par 217\vspace{0.3em} 218{\small\color{acpurple} \url{https://aesthetic.computer}}\par 219\vspace{0.6em} 220\rule{\textwidth}{1.5pt} 221\vspace{0.5em} 222\end{center} 223 224\begin{center} 225{\small\color{draftcolor}\textbf{[ working draft --- not for citation ]}} 226\end{center} 227\vspace{0.3em} 228 229\begin{quote} 230\small\noindent\textbf{Abstract.} 231Every creative coding platform defines a core API---a small set of functions through which programs see the world and draw on it. Processing's \texttt{setup()}/\texttt{draw()} with global drawing primitives (\texttt{background()}, \texttt{stroke()}, \texttt{ellipse()}) established a pattern in 2001 that has shaped two decades of creative coding tools. p5.js brought this model to the browser in 2014, preserving the API surface while adapting to JavaScript and the DOM. \ac{} (AC), begun in 2021, carries Processing's thinking at its core while extending the model in several structural ways: it expands the two-function lifecycle to five (\texttt{boot}, \texttt{paint}, \texttt{act}, \texttt{sim}, \texttt{leave}), eliminates global state in favor of destructured API injection, separates simulation from rendering at different tick rates, and makes every program URL-addressable with no build step. This paper traces how Processing's ideas live inside the AC piece API, comparing the lifecycle models, drawing primitives, input handling, and state management strategies across Design By Numbers, Processing, p5.js, and AC. We argue that the AC API design---with Processing's immediate-mode graphics model at its foundation---extends the \emph{sketchbook} metaphor (write, run, discard) into an \emph{instrument} metaphor (boot, play, practice, return). 232\end{quote} 233\vspace{0.5em} 234}] 235 236% ============ 1. INTRODUCTION ============ 237 238\section{Introduction} 239 240The 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. 241 242These 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. 243 244The 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. 245 246% ============ 2. THE PROCESSING MODEL ============ 247 248\section{The Processing Model (2001)} 249\label{sec:processing} 250 251Processing~\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. 252 253\subsection{Lifecycle: \texttt{setup()} and \texttt{draw()}} 254 255\begin{lstlisting}[style=processingstyle,caption={Minimal Processing sketch.}] 256void setup() { 257 size(400, 400); 258 background(0); 259} 260 261void draw() { 262 stroke(255); 263 ellipse(mouseX, mouseY, 20, 20); 264} 265\end{lstlisting} 266 267\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?'' 268 269The 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. 270 271\subsection{Drawing primitives} 272 273Processing'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. 274 275\begin{lstlisting}[style=processingstyle,caption={Stateful drawing context.}] 276void draw() { 277 fill(255, 0, 0); // Set fill: red 278 stroke(0); // Set stroke: black 279 strokeWeight(3); // Set weight: 3px 280 ellipse(100, 100, 50, 50); // Uses above 281 rect(200, 100, 50, 50); // Also uses above 282 // State persists into next frame 283} 284\end{lstlisting} 285 286This 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. 287 288\subsection{Global scope} 289 290All 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. 291 292% ============ 3. THE P5.JS TRANSITION ============ 293 294\section{The p5.js Transition (2014)} 295\label{sec:p5js} 296 297p5.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. 298 299\subsection{Lifecycle preservation} 300 301\begin{lstlisting}[style=p5style,caption={Minimal p5.js sketch.}] 302function setup() { 303 createCanvas(400, 400); 304} 305 306function draw() { 307 background(220); 308 ellipse(mouseX, mouseY, 50, 50); 309} 310\end{lstlisting} 311 312The \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. 313 314\subsection{Canvas creation} 315 316The 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. 317 318\subsection{Instance mode} 319 320p5.js introduces an important escape hatch from the global namespace: \emph{instance mode}. 321 322\begin{lstlisting}[style=p5style,caption={p5.js instance mode.}] 323const sketch = (p) => { 324 p.setup = () => { 325 p.createCanvas(400, 400); 326 }; 327 p.draw = () => { 328 p.background(220); 329 p.ellipse(p.mouseX, p.mouseY, 50, 50); 330 }; 331}; 332new p5(sketch); 333\end{lstlisting} 334 335Instance 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. 336 337\subsection{What changed, what didn't} 338 339p5.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. 340 341% ============ 4. THE AC PIECE API ============ 342 343\section{The AC Piece API (2021--)} 344\label{sec:ac} 345 346\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. 347 348\subsection{Five lifecycle functions} 349 350\begin{lstlisting}[style=acjsstyle,caption={Minimal AC piece.}] 351function boot({ screen, params }) { 352 // Runs once on load 353} 354 355function paint({ wipe, ink, line, screen }) { 356 wipe("navy"); 357 ink("pink").circle( 358 screen.width / 2, 359 screen.height / 2, 360 50 361 ); 362} 363 364function act({ event: e }) { 365 if (e.is("keyboard:down:space")) { 366 // Handle spacebar 367 } 368} 369 370function sim() { 371 // Update state at 120fps 372} 373 374export { boot, paint, act, sim }; 375\end{lstlisting} 376 377The five functions are: 378 379\begin{itemize} 380 \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. 381 \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). 382 \item \texttt{act(\$api)} --- called once per input event. Consolidates Processing's event callbacks (\texttt{mousePressed()}, \texttt{keyPressed()}) into a single, unified entry point. 383 \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}. 384 \item \texttt{leave(\$api)} --- cleanup on exit. No equivalent in Processing, where sketches simply terminate. 385\end{itemize} 386 387Each function is optional. A piece that exports only \texttt{paint} is a valid, functioning program. 388 389\subsection{API injection via destructuring} 390 391The 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: 392 393\begin{lstlisting}[style=acjsstyle,caption={API destructuring in AC.}] 394function paint({ wipe, ink, line, box, 395 circle, screen, num }) { 396 wipe(0, 0, 30); 397 ink(255, 100, 180); 398 const cx = num.lerp(0, screen.width, 0.5); 399 circle(cx, screen.height / 2, 40); 400} 401\end{lstlisting} 402 403This design has several consequences: 404 405\begin{enumerate} 406 \item \textbf{No global pollution.} Module-level variables are piece state; API functions are parameters. There is no ambient namespace to collide with. 407 \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. 408 \item \textbf{Composability.} Multiple pieces can coexist in the same JavaScript context without API collisions, enabling the platform's piece-switching and embedding mechanisms. 409 \item \textbf{Discoverability.} Autocompletion in editors works on the destructured parameter object, providing a natural way to explore the API. 410\end{enumerate} 411 412This 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. 413 414\subsection{Separation of simulation and rendering} 415\label{sec:simsep} 416 417Processing'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.'' 418 419AC separates these explicitly: 420 421\begin{itemize} 422 \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. 423 \item \texttt{paint()} runs at the display's refresh rate (capped at approximately 165fps), and is responsible only for rendering the current state. 424 \item \texttt{act()} runs once per input event, immediately when the event arrives. 425\end{itemize} 426 427This 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. 428 429\subsection{Unified event handling} 430 431Processing distributes input handling across global variables and optional callbacks: 432 433\begin{lstlisting}[style=processingstyle] 434// Processing: scattered input model 435void draw() { 436 if (mousePressed) { /* poll state */ } 437} 438void mousePressed() { /* callback */ } 439void keyPressed() { /* callback */ } 440void mouseDragged() { /* callback */ } 441\end{lstlisting} 442 443AC consolidates all input into \texttt{act()} with a string-based event matching system: 444 445\begin{lstlisting}[style=acjsstyle] 446function act({ event: e, pen }) { 447 if (e.is("touch")) { } 448 if (e.is("draw")) { } 449 if (e.is("lift")) { } 450 if (e.is("keyboard:down:a")) { } 451 if (e.is("keyboard:down:space")){ } 452 if (e.is("gamepad:a")) { } 453 if (e.is("reframed")) { } 454} 455\end{lstlisting} 456 457The \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. 458 459\subsection{Drawing primitives: stateless by default} 460 461Processing 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: 462 463\begin{lstlisting}[style=acjsstyle] 464function paint({ wipe, ink, line, circle }) { 465 wipe("black"); 466 ink("red").circle(50, 50, 20); 467 ink("blue").line(0, 0, 100, 100); 468 // No state leaks between calls 469} 470\end{lstlisting} 471 472The \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. 473 474The \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. 475 476\subsection{No canvas configuration} 477 478In 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. 479 480This 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. 481 482% ============ 5. API SURFACE COMPARISON ============ 483 484\section{API Surface Comparison} 485\label{sec:comparison} 486 487Table~\ref{tab:lifecycle} compares the lifecycle models. Table~\ref{tab:drawing} compares drawing primitives. 488 489\begin{table}[h] 490\small 491\centering 492\begin{tabularx}{\columnwidth}{lXXX} 493\toprule 494 & \textbf{Processing} & \textbf{p5.js} & \textbf{AC} \\ 495\midrule 496Init & \texttt{setup()} & \texttt{setup()} & \texttt{boot(\$)} \\ 497Render & \texttt{draw()} & \texttt{draw()} & \texttt{paint(\$)} \\ 498Logic & (in draw) & (in draw) & \texttt{sim(\$)} \\ 499Input & callbacks & callbacks & \texttt{act(\$)} \\ 500Cleanup & --- & \texttt{remove()} & \texttt{leave(\$)} \\ 501\midrule 502Render rate & 60fps & 60fps & display Hz \\ 503Logic rate & 60fps & 60fps & 120fps fixed \\ 504Scope & global & global/inst. & injected \\ 505\bottomrule 506\end{tabularx} 507\caption{Lifecycle comparison. \texttt{\$} denotes destructured API injection.} 508\label{tab:lifecycle} 509\end{table} 510 511\begin{table}[h] 512\small 513\centering 514\begin{tabularx}{\columnwidth}{lXX} 515\toprule 516\textbf{Processing/p5} & \textbf{AC} & \textbf{Notes} \\ 517\midrule 518\texttt{background()} & \texttt{wipe()} & Verb, not property \\ 519\texttt{fill() + stroke()} & \texttt{ink()} & Unified, chainable \\ 520\texttt{ellipse()} & \texttt{circle()} & Named for shape \\ 521\texttt{rect()} & \texttt{box()} & Shorter name \\ 522\texttt{line()} & \texttt{line()} & Unchanged \\ 523\texttt{point()} & \texttt{plot()} & Graph metaphor \\ 524\texttt{text()} & \texttt{write()} & Active verb \\ 525--- & \texttt{flood()} & Fill region \\ 526--- & \texttt{paste()} & Buffer compositing \\ 527--- & \texttt{form()} & 3D rendering \\ 528\bottomrule 529\end{tabularx} 530\caption{Drawing primitive comparison.} 531\label{tab:drawing} 532\end{table} 533 534\subsection{Naming philosophy} 535 536Processing'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. 537 538This 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.'' 539 540\subsection{Color model} 541 542Processing 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. 543 544AC 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: 545 546\begin{itemize} 547 \item RGB values: \texttt{ink(255, 100, 50)} 548 \item Named colors: \texttt{ink("pink")}, \texttt{ink("navy")} 549 \item Grayscale: \texttt{ink(128)} 550 \item Alpha: \texttt{ink(255, 0, 0, 128)} 551\end{itemize} 552 553Named 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. 554 555% ============ 6. STATE MANAGEMENT ============ 556 557\section{State Management} 558\label{sec:state} 559 560\subsection{Processing: global variables} 561 562\begin{lstlisting}[style=processingstyle] 563int x = 100; 564int y = 100; 565 566void draw() { 567 background(0); 568 x += 1; 569 ellipse(x, y, 20, 20); 570} 571\end{lstlisting} 572 573State 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. 574 575\subsection{AC: module-level closures} 576 577\begin{lstlisting}[style=acjsstyle] 578let x = 100; 579let y = 100; 580 581function sim() { 582 x += 1; 583} 584 585function paint({ wipe, ink, circle }) { 586 wipe(0); 587 ink(255).circle(x, y, 20); 588} 589 590export { sim, paint }; 591\end{lstlisting} 592 593AC 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. 594 595The 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. 596 597% ============ 7. THE GENEALOGY ============ 598 599\section{The Genealogy} 600\label{sec:genealogy} 601 602\subsection{Design By Numbers (1999)} 603 604Maeda'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. 605 606AC inherits DBN's minimalism in naming (short, active verbs) and its conviction that the API should be exhaustively learnable. 607 608\subsection{Processing (2001)} 609 610Processing~\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. 611 612AC inherits the lifecycle function model but splits \texttt{draw()} into three concerns (\texttt{paint}, \texttt{sim}, \texttt{act}). 613 614\subsection{p5.js (2014)} 615 616p5.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. 617 618AC 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. 619 620\subsection{openFrameworks (2005)} 621 622openFrameworks~\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()}. 623 624\subsection{The instrument turn} 625 626The genealogy can be summarized as a series of separations: 627 628\begin{enumerate} 629 \item \textbf{DBN}: one-shot execution (no animation loop). 630 \item \textbf{Processing}: init + render (\texttt{setup} + \texttt{draw}). 631 \item \textbf{openFrameworks}: init + update + render. 632 \item \textbf{AC}: init + input + update + render + cleanup (\texttt{boot} + \texttt{act} + \texttt{sim} + \texttt{paint} + \texttt{leave}). 633\end{enumerate} 634 635Each 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}). 636 637% ============ 8. WORKED EXAMPLE ============ 638 639\section{Worked Example: A Bouncing Ball} 640\label{sec:example} 641 642To make the comparison concrete, we implement a bouncing ball in all three systems. 643 644\subsection{Processing} 645 646\begin{lstlisting}[style=processingstyle] 647float x = 200, y = 200; 648float vx = 3, vy = 2; 649 650void setup() { 651 size(400, 400); 652} 653 654void draw() { 655 background(0); 656 x += vx; y += vy; 657 if (x < 0 || x > width) vx *= -1; 658 if (y < 0 || y > height) vy *= -1; 659 fill(255, 100, 180); 660 noStroke(); 661 ellipse(x, y, 30, 30); 662} 663\end{lstlisting} 664 665Logic and rendering are interleaved in \texttt{draw()}. State mutation (\texttt{x += vx}), boundary checking, and drawing all share one function. 666 667\subsection{p5.js} 668 669\begin{lstlisting}[style=p5style] 670let x = 200, y = 200; 671let vx = 3, vy = 2; 672 673function setup() { 674 createCanvas(400, 400); 675} 676 677function draw() { 678 background(0); 679 x += vx; y += vy; 680 if (x < 0 || x > width) vx *= -1; 681 if (y < 0 || y > height) vy *= -1; 682 fill(255, 100, 180); 683 noStroke(); 684 ellipse(x, y, 30, 30); 685} 686\end{lstlisting} 687 688Structurally identical to Processing. The only changes are syntactic: \texttt{let} vs.\ \texttt{float}, \texttt{createCanvas} vs.\ \texttt{size}. 689 690\subsection{AC} 691 692\begin{lstlisting}[style=acjsstyle] 693let x, y, vx = 3, vy = 2; 694 695function boot({ screen }) { 696 x = screen.width / 2; 697 y = screen.height / 2; 698} 699 700function sim({ screen }) { 701 x += vx; y += vy; 702 if (x < 0 || x > screen.width) vx *= -1; 703 if (y < 0 || y > screen.height) vy *= -1; 704} 705 706function paint({ wipe, ink, circle }) { 707 wipe(0); 708 ink(255, 100, 180).circle(x, y, 15); 709} 710 711export { boot, sim, paint }; 712\end{lstlisting} 713 714The 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}). 715 716% ============ 9. DESIGN RATIONALE ============ 717 718\section{Design Rationale} 719\label{sec:rationale} 720 721\subsection{Why five functions?} 722 723The 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. 724 725\subsection{Why inject the API?} 726 727Global 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. 728 729The 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. 730 731\subsection{Why 120Hz simulation?} 732 733Processing'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. 734 735AC 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. 736 737\subsection{Why no canvas size?} 738 739Requiring \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. 740 741% ============ 10. ADDITIONAL LIFECYCLE ============ 742 743\section{Extended Lifecycle} 744\label{sec:extended} 745 746Beyond the core five functions, AC pieces may export additional lifecycle hooks: 747 748\begin{itemize} 749 \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. 750 \item \texttt{preview(\$api)} --- renders a static thumbnail image for the piece. Used in piece listings and social sharing. 751 \item \texttt{icon(\$api)} --- renders a favicon for the browser tab. 752 \item \texttt{meta()} --- returns \texttt{\{title, desc\}} metadata for Open Graph tags. 753 \item \texttt{receive(event)} --- handles messages from other pieces or the system, enabling inter-piece communication. 754\end{itemize} 755 756The \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. 757 758% ============ 11. CONCLUSION ============ 759 760\section{Conclusion} 761\label{sec:conclusion} 762 763Processing'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. 764 765Processing 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. 766 767The 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}. 768 769The API is the instrument. Processing is its core. How the API decomposes the act of programming determines what gets made. 770 771\bibliographystyle{plainnat} 772\bibliography{references} 773 774\end{document}