Something went wrong. Try again.
Monorepo for Aesthetic.Computer aesthetic.computer
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784% !TEX program = xelatex\documentclass[10pt,letterpaper,twocolumn]{article}
% === GEOMETRY ===\usepackage[top=0.75in, bottom=0.75in, left=0.75in, right=0.75in]{geometry}
% === FONTS ===\usepackage{fontspec}\usepackage{unicode-math}\setmainfont{Latin Modern Roman}[ Extension=.otf, UprightFont=lmroman10-regular, BoldFont=lmroman10-bold, ItalicFont=lmroman10-italic, BoldItalicFont=lmroman10-bolditalic,]\setsansfont{Latin Modern Sans}[ Extension=.otf, UprightFont=lmsans10-regular, BoldFont=lmsans10-bold, ItalicFont=lmsans10-oblique, BoldItalicFont=lmsans10-boldoblique,]\setmonofont{Latin Modern Mono}[ Extension=.otf, UprightFont=lmmono10-regular, ItalicFont=lmmono10-italic, Scale=0.85,]\newfontfamily\acbold{ywft-processing-bold}[ Path=../../system/public/type/webfonts/, Extension=.ttf]\newfontfamily\aclight{ywft-processing-light}[ Path=../../system/public/type/webfonts/, Extension=.ttf]
% === PACKAGES ===\usepackage{xcolor}\usepackage{titlesec}\usepackage{enumitem}\usepackage{booktabs}\usepackage{tabularx}\usepackage{fancyhdr}\usepackage{hyperref}\usepackage{xurl}\usepackage{graphicx}\usepackage{ragged2e}\usepackage{microtype}\usepackage{listings}\usepackage{natbib}\usepackage[colorspec=0.92]{draftwatermark}
% === COLORS ===\definecolor{acpink}{RGB}{180,72,135}\definecolor{acpurple}{RGB}{120,80,180}\definecolor{acdark}{RGB}{64,56,74}\definecolor{acgray}{RGB}{119,119,119}\definecolor{draftcolor}{RGB}{180,72,135}
% === DRAFT WATERMARK ===\DraftwatermarkOptions{ text=WORKING DRAFT, fontsize=3cm, color=draftcolor!18, angle=45, pos={0.5\paperwidth, 0.5\paperheight}}
% === JS SYNTAX COLORS ===\definecolor{jskw}{RGB}{119,51,170}\definecolor{jsfn}{RGB}{0,136,170}\definecolor{jsstr}{RGB}{170,120,0}\definecolor{jsnum}{RGB}{204,0,102}\definecolor{jscmt}{RGB}{102,102,102}
% === PROCESSING SYNTAX COLORS ===\definecolor{pjkw}{RGB}{204,102,0}\definecolor{pjfn}{RGB}{0,102,153}\definecolor{pjcmt}{RGB}{102,102,102}
% === HYPERREF ===\hypersetup{ colorlinks=true, linkcolor=acpurple, urlcolor=acpurple, citecolor=acpurple, pdfauthor={@jeffrey}, pdftitle={Fra setup() til boot(): Processing i kernen af Piece-API'en},}
% === SECTION FORMATTING ===\titleformat{\section} {\normalfont\bfseries\normalsize\uppercase} {\thesection.} {0.5em} {}\titlespacing{\section}{0pt}{1.2em}{0.3em}
\titleformat{\subsection} {\normalfont\bfseries\small} {\thesubsection} {0.5em} {}\titlespacing{\subsection}{0pt}{0.8em}{0.2em}
\titleformat{\subsubsection} {\normalfont\itshape\small} {\thesubsubsection} {0.5em} {}\titlespacing{\subsubsection}{0pt}{0.6em}{0.1em}
% === HEADER/FOOTER ===\pagestyle{fancy}\fancyhf{}\renewcommand{\headrulewidth}{0pt}\fancyhead[C]{\footnotesize\color{draftcolor}\textit{Arbejdsudkast --- ikke til citation}}\fancyfoot[C]{\footnotesize\thepage}
% === LIST SETTINGS ===\setlist[itemize]{nosep, leftmargin=1.2em, itemsep=0.1em}\setlist[enumerate]{nosep, leftmargin=1.2em}
% === COLUMN SEPARATION ===\setlength{\columnsep}{1.8em}
% === PARAGRAPH SETTINGS ===\setlength{\parindent}{1em}\setlength{\parskip}{0.3em}
% Hyphenation for narrow two-column layout\tolerance=800\emergencystretch=1em\hyphenpenalty=50
% === LISTINGS ===\lstdefinelanguage{processing}{ morekeywords=[1]{void,int,float,boolean,color,String,class,new,if,else,for,while,return,public,private,extends,import}, 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}, sensitive=true, morecomment=[l]{//}, morecomment=[s]{/*}{*/}, morestring=[b]",}
\lstdefinelanguage{p5js}{ morekeywords=[1]{function,let,const,var,if,else,for,while,return,new,class,export}, 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}, sensitive=true, morecomment=[l]{//}, morestring=[b]", morestring=[b]', morestring=[b]`,}
\lstdefinelanguage{acjs}{ morekeywords=[1]{function,export,const,let,var,return,if,else,new,async,await,import,from,for}, 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}, sensitive=true, morecomment=[l]{//}, morestring=[b]", morestring=[b]', morestring=[b]`,}
\lstdefinestyle{processingstyle}{ language=processing, keywordstyle=[1]\color{pjkw}\bfseries, keywordstyle=[2]\color{pjfn}\bfseries, commentstyle=\color{pjcmt}\itshape, stringstyle=\color{jsstr},}
\lstdefinestyle{p5style}{ language=p5js, keywordstyle=[1]\color{jskw}\bfseries, keywordstyle=[2]\color{pjfn}\bfseries, commentstyle=\color{jscmt}\itshape, stringstyle=\color{jsstr},}
\lstdefinestyle{acjsstyle}{ language=acjs, keywordstyle=[1]\color{jskw}\bfseries, keywordstyle=[2]\color{jsfn}\bfseries, commentstyle=\color{jscmt}\itshape, stringstyle=\color{jsstr},}
\lstset{ basicstyle=\ttfamily\small, breaklines=true, frame=single, rulecolor=\color{acgray!30}, backgroundcolor=\color{acgray!5}, xleftmargin=0.5em, xrightmargin=0.5em, aboveskip=0.5em, belowskip=0.5em, numbers=none, tabsize=2,}
\newcommand{\acdot}{{\color{acpink}.}}\newcommand{\ac}{\textsc{Aesthetic.Computer}}
\begin{document}
% ============ TITLE BLOCK ============
\twocolumn[{%\begin{center}{\acbold\fontsize{22pt}{26pt}\selectfont\color{acdark} Fra \texttt{setup()} til \texttt{boot()}}\par\includegraphics[width=0.5\textwidth]{figures/cover}\par\vspace{0.35em}\vspace{0.2em}{\aclight\fontsize{11pt}{13pt}\selectfont\color{acpink} Processing i kernen af Piece-API'en}\par\vspace{0.6em}{\normalsize\href{https://prompt.ac/@jeffrey}{@jeffrey}}\par{\small\color{acgray} Aesthetic.Computer}\par{\small\color{acgray} ORCID: \href{https://orcid.org/0009-0007-4460-4913}{0009-0007-4460-4913}}\par\vspace{0.3em}{\small\color{acpurple} \url{https://aesthetic.computer}}\par\vspace{0.6em}\rule{\textwidth}{1.5pt}\vspace{0.5em}\end{center}
\begin{center}{\small\color{draftcolor}\textbf{[ arbejdsudkast --- ikke til citation ]}}\end{center}\vspace{0.3em}
\begin{quote}\small\noindent\textbf{Abstrakt.}Enhver kreativ kodningsplatform definerer en kerne-API---et lille sæt funktioner, hvorigennem programmer ser verden og tegner på den. Processings \texttt{setup()}/\texttt{draw()} med globale tegneprimitiver (\texttt{background()}, \texttt{stroke()}, \texttt{ellipse()}) etablerede et mønster i 2001, der har formet to årtiers kreative kodningsværktøjer. p5.js bragte denne model til browseren i 2014, bevarede API-overfladen mens den tilpassede sig JavaScript og DOM'en. \ac{} (AC), påbegyndt i 2021, bærer Processings tænkning i sin kerne, mens den udvider modellen på flere strukturelle måder: den udvider to-funktions livscyklussen til fem (\texttt{boot}, \texttt{paint}, \texttt{act}, \texttt{sim}, \texttt{leave}), eliminerer global tilstand til fordel for destruktureret API-injektion, adskiller simulation fra rendering ved forskellige tick-rater og gør hvert program URL-adresserbart uden byggetrin. Denne artikel sporer, hvordan Processings idéer lever inde i AC piece-API'en, sammenligner livscyklusmodellerne, tegneprimitiver, inputhåndtering og tilstandsstyringsstrategier på tværs af Design By Numbers, Processing, p5.js og AC. Vi argumenterer for, at AC API-designet---med Processings immediate-mode grafikmodel som fundament---udvider \emph{skitsebogs}-metaforen (skriv, kør, kassér) til en \emph{instrument}-metafor (boot, spil, øv, vend tilbage).\end{quote}\vspace{0.5em}}]
% ============ 1. INTRODUKTION ============
\section{Introduktion}
Historien om kreative kodnings-API'er er en historie om at beslutte, hvad programmøren skal sige først. I Design By Numbers~\citep{maeda2001dbn} var den første udsagn en koordinat og en gråtoneværdi: \texttt{Paper 50}. I Processing~\citep{reas2003processing} var det \texttt{size(200, 200)} inde i \texttt{setup()}. I p5.js~\citep{mccarthy2015p5js} var det \texttt{createCanvas(400, 400)}. I \ac{} siger programmøren intet om lærredet overhovedet---køretiden leverer \texttt{screen.width} og \texttt{screen.height} som givne fakta, og den første meningsfulde udsagn er typisk \texttt{wipe()}, der rydder skærmen for at begynde at male.
Disse er ikke vilkårlige forskelle. Hver afspejler en beslutning om, hvad platformen antager versus hvad programmøren må specificere, og disse beslutninger akkumulerer til fundamentalt forskellige relationer mellem forfatter og maskine. Denne artikel sporer API-slægtskabet fra Processing gennem p5.js til AC og undersøger hver overgang som et sæt designtræk: hvad der blev beholdt, hvad der blev ændret, og hvad ændringen indebærer.
Bidraget er tredelt: (1) en detaljeret teknisk sammenligning af livscyklusmodellerne, tegne-API'erne, inputsystemerne og tilstandsstyringsstrategierne i Processing, p5.js og AC; (2) en analyse af designrationalet bag AC's afvigelser fra Processing-modellen; og (3) et argument for, at AC piece-API'en legemliggør et skift fra skitsebogsmetaforen til det, vi kalder \emph{instrumentmetaforen}---en model, hvor forholdet mellem programmør og program er vedvarende, performativt og praksisbaseret snarere end eksplorativt og engangs.
% ============ 2. PROCESSING-MODELLEN ============
\section{Processing-modellen (2001)}\label{sec:processing}
Processing~\citep{reas2007processing} blev designet som en ``software-skitsebog'' for billedkunstnere. Dets API er centreret om to livscyklusfunktioner og et bibliotek af globale tegneprimitiver.
\subsection{Livscyklus: \texttt{setup()} og \texttt{draw()}}
\begin{lstlisting}[style=processingstyle,caption={Minimal Processing-skitse.}]void setup() { size(400, 400); background(0);}
void draw() { stroke(255); ellipse(mouseX, mouseY, 20, 20);}\end{lstlisting}
\texttt{setup()} kører én gang; \texttt{draw()} kører hvert frame med standard 60fps. Denne to-funktions model er Processings mest indflydelsesrige designbeslutning. Den reducerer det kognitive overhead ved animation fra at styre en renderingsløkke til at udfylde to tomme felter: ``hvad sker én gang?'' og ``hvad sker hvert frame?''
Modellen er bevidst minimal. Der er ingen eksplicit \texttt{input()}-funktion---muse- og tastaturtilstand er tilgængelig som globale variabler (\texttt{mouseX}, \texttt{mouseY}, \texttt{key}, \texttt{keyCode}), der opdateres automatisk. Hændelses-callbacks (\texttt{mousePressed()}, \texttt{keyPressed()}) eksisterer, men er valgfrie supplementer, ikke påkrævede indgangspunkter.
\subsection{Tegneprimitiver}
Processings tegne-API bruger en \emph{tilstandsbaseret pipeline}-model arvet fra PostScript og OpenGL: tilstandssættende kald (\texttt{stroke()}, \texttt{fill()}, \texttt{strokeWeight()}) modificerer en vedvarende grafikkontekst, og formkald (\texttt{ellipse()}, \texttt{rect()}, \texttt{line()}) renderer med den kontekst. Konteksten vedbliver på tværs af frames, medmindre den eksplicit nulstilles.
\begin{lstlisting}[style=processingstyle,caption={Tilstandsbaseret tegnekontekst.}]void draw() { fill(255, 0, 0); // Sæt fyld: rød stroke(0); // Sæt streg: sort strokeWeight(3); // Sæt bredde: 3px ellipse(100, 100, 50, 50); // Bruger ovenstående rect(200, 100, 50, 50); // Bruger også ovenstående // Tilstand vedbliver til næste frame}\end{lstlisting}
Denne tilstandsvedvarenhed er både kraftfuld (mindre kode for ensartede stile) og fejlbehæftet (glemt tilstand lækker på tværs af frames). Processing adresserer dette med \texttt{pushStyle()}/\texttt{popStyle()} og \texttt{pushMatrix()}/\texttt{popMatrix()}, men disse er ekspertværktøjer.
\subsection{Globalt scope}
Alle Processing-programmer deler et enkelt globalt navnerum. Variabler erklæret uden for \texttt{setup()} og \texttt{draw()} er tilgængelige overalt. Tegnefunktionerne (\texttt{line()}, \texttt{ellipse()}, \texttt{background()}) er globale. Inputvariabler (\texttt{mouseX}, \texttt{mouseY}) er globale. Dette eliminerer behovet for at forstå scope, imports eller dependency injection---kritisk for begyndere---men gør programmer umulige at komponere eller isolere.
% ============ 3. P5.JS-OVERGANGEN ============
\section{p5.js-overgangen (2014)}\label{sec:p5js}
p5.js~\citep{mccarthy2015p5js} er en JavaScript-reimplementering af Processing. Dets primære bidrag er at bringe Processing-modellen til browseren, men porten krævede adskillige tilpasninger.
\subsection{Bevarelse af livscyklus}
\begin{lstlisting}[style=p5style,caption={Minimal p5.js-skitse.}]function setup() { createCanvas(400, 400);}
function draw() { background(220); ellipse(mouseX, mouseY, 50, 50);}\end{lstlisting}
\texttt{setup()}/\texttt{draw()}-modellen er bevaret nøjagtigt. Den kognitive model er identisk: to funktioner, globale tegneprimitiver, automatisk animationsløkke. Denne kontinuitet er bevidst---p5.js sigter mod at være Processing for webbet, ikke et nyt sprog.
\subsection{Oprettelse af lærred}
Den mest synlige ændring er \texttt{createCanvas()}, der erstatter \texttt{size()}. Dette er ikke kosmetisk: i Processing konfigurerer \texttt{size()} applikationsvinduet; i p5.js opretter \texttt{createCanvas()} et HTML \texttt{<canvas>}-element inden for DOM'en. Skitsen må forhandle med den eksisterende side snarere end at eje hele skærmen.
\subsection{Instance mode}
p5.js introducerer en vigtig flugtvej fra det globale navnerum: \emph{instance mode}.
\begin{lstlisting}[style=p5style,caption={p5.js instance mode.}]const sketch = (p) => { p.setup = () => { p.createCanvas(400, 400); }; p.draw = () => { p.background(220); p.ellipse(p.mouseX, p.mouseY, 50, 50); };};new p5(sketch);\end{lstlisting}
Instance mode pakker alle API-funktioner bag et navnerum (\texttt{p.}), hvilket tillader flere skitser på én side og undgår global forurening. Dog skrives det meste p5.js-kode i global tilstand, og instance mode mødes typisk kun ved indlejring af skitser i større applikationer. Præfiks-notationen (\texttt{p.ellipse} vs.\ \texttt{ellipse}) øger ordrigdommen og reducerer den ``bare skriv''-kvalitet, der gør Processing indbydende.
\subsection{Hvad der ændrede sig, hvad der ikke gjorde}
p5.js bevarede: to-funktions livscyklussen, globale tegneprimitiver, tilstandsbaseret grafikkontekst, frame-baseret animation og ``skitse''-identiteten. Det tilpassede: lærredsoprettelse til DOM'en, renderer-valg (2D/WebGL), hændelseshåndtering til browserhændelser og tilføjede instance mode til komposition. Det adresserede ikke: sammenblanding af simulation og rendering, manglen på struktureret inputhåndtering eller enkelt-fil-isolationsproblemet.
% ============ 4. AC PIECE-API'EN ============
\section{AC Piece-API'en (2021--)}\label{sec:ac}
\ac{}'s piece-API~\citep{scudder2026ac} er bygget på Processings kerneidéer---immediate-mode grafik, enkelt-fil programmer, livscyklusfunktioner---og udvider dem omkring fem hensyn i stedet for to.
\subsection{Fem livscyklusfunktioner}
\begin{lstlisting}[style=acjsstyle,caption={Minimalt AC piece.}]function boot({ screen, params }) { // Kører én gang ved indlæsning}
function paint({ wipe, ink, line, screen }) { wipe("navy"); ink("pink").circle( screen.width / 2, screen.height / 2, 50 );}
function act({ event: e }) { if (e.is("keyboard:down:space")) { // Håndtér mellemrumstast }}
function sim() { // Opdatér tilstand ved 120fps}
export { boot, paint, act, sim };\end{lstlisting}
De fem funktioner er:
\begin{itemize} \item \texttt{boot(\$api)} --- kører én gang, når piecet indlæses. Udvider Processings \texttt{setup()}, hvor skærmen leveres af køretiden snarere end konfigureres af programmøren. \item \texttt{paint(\$api)} --- kører hvert frame, der kræver rendering. Viderefører \texttt{draw()}'s immediate-mode model, men er rent visuelt: ingen logik, ingen tilstandsmutation (ved konvention). \item \texttt{act(\$api)} --- kaldes én gang per inputhændelse. Konsoliderer Processings hændelses-callbacks (\texttt{mousePressed()}, \texttt{keyPressed()}) til ét samlet indgangspunkt. \item \texttt{sim(\$api)} --- kører med faste 120Hz, potentielt flere gange per renderet frame. Har ingen ækvivalent i Processing; nærmeste analogi er fast-tidstrin spilsløjfen~\citep{nystrom2014game}. \item \texttt{leave(\$api)} --- oprydning ved afslutning. Ingen ækvivalent i Processing, hvor skitser simpelthen terminerer.\end{itemize}
Hver funktion er valgfri. Et piece, der kun eksporterer \texttt{paint}, er et gyldigt, fungerende program.
\subsection{API-injektion via destrukturering}
Den mest strukturelt betydningsfulde udvidelse af Processing-modellen er, at \textbf{ingen API-funktioner eksisterer i det globale scope}. Enhver funktion, piecet bruger, modtages som en parameter:
\begin{lstlisting}[style=acjsstyle,caption={API-destrukturering i AC.}]function paint({ wipe, ink, line, box, circle, screen, num }) { wipe(0, 0, 30); ink(255, 100, 180); const cx = num.lerp(0, screen.width, 0.5); circle(cx, screen.height / 2, 40);}\end{lstlisting}
Dette design har flere konsekvenser:
\begin{enumerate} \item \textbf{Ingen global forurening.} Modulniveau-variabler er piece-tilstand; API-funktioner er parametre. Der er intet omgivende navnerum at kollidere med. \item \textbf{Selvdokumenterende imports.} Destruktureringsmønstret øverst i hver funktion erklærer nøjagtigt, hvilke API-overflader funktionen bruger, og fungerer som et inline afhængighedsmanifest. \item \textbf{Komponerbarhed.} Flere pieces kan sameksistere i den samme JavaScript-kontekst uden API-kollisioner, hvilket muliggør platformens piece-skiftning og indlejringsmekanismer. \item \textbf{Opdagelighed.} Autokomplettering i editorer virker på det destrukturerede parameterobjekt og giver en naturlig måde at udforske API'en.\end{enumerate}
Dette er p5.js instance mode-mønstret ført til sin konklusion: i stedet for at præfikse hvert kald med \texttt{p.}, destrukturerer programmøren nøjagtigt de funktioner, de har brug for, én gang, ved funktionssignaturen.
\subsection{Adskillelse af simulation og rendering}\label{sec:simsep}
Processings \texttt{draw()} sammenblander to hensyn: opdatering af tilstand og rendering af pixels. Dette virker for simple skitser, men skaber problemer i takt med stigende kompleksitet: fysiksimulationer bundet til billedrate, inputlatenstid koblet til renderingsomkostninger og vanskelighed ved at adskille ``hvad der skete'' fra ``hvordan det ser ud.''
AC adskiller disse eksplicit:
\begin{itemize} \item \texttt{sim()} kører med faste 120Hz, uafhængigt af skærmens opdateringshastighed. På en 60Hz-skærm kører \texttt{sim()} to gange per \texttt{paint()}-kald. På en 144Hz-skærm justeres forholdet tilsvarende. \item \texttt{paint()} kører med skærmens opdateringshastighed (begrænset til ca. 165fps) og er kun ansvarlig for at rendere den aktuelle tilstand. \item \texttt{act()} kører én gang per inputhændelse, umiddelbart når hændelsen ankommer.\end{itemize}
Denne trevejsopsplitning afspejler arkitekturen i moderne spilmotorer~\citep{nystrom2014game}: et fast opdateringstick for deterministisk logik, et variabelt render-tick for jævn visning og en hændelseskø for input. Forskellen er, at AC eksponerer denne arkitektur som en førsteklasses API i stedet for at skjule den bag et framework.
\subsection{Samlet hændelseshåndtering}
Processing distribuerer inputhåndtering på tværs af globale variabler og valgfrie callbacks:
\begin{lstlisting}[style=processingstyle]// Processing: spredt inputmodelvoid draw() { if (mousePressed) { /* poll tilstand */ }}void mousePressed() { /* callback */ }void keyPressed() { /* callback */ }void mouseDragged() { /* callback */ }\end{lstlisting}
AC konsoliderer al input i \texttt{act()} med et strengbaseret hændelsesmatchningsystem:
\begin{lstlisting}[style=acjsstyle]function act({ event: e, pen }) { if (e.is("touch")) { } if (e.is("draw")) { } if (e.is("lift")) { } if (e.is("keyboard:down:a")) { } if (e.is("keyboard:down:space")){ } if (e.is("gamepad:a")) { } if (e.is("reframed")) { }}\end{lstlisting}
Mønstret \texttt{event.is()} giver en ensartet grænseflade på tværs af inputmodaliteter (berøring, mus, tastatur, gamepad, MIDI, håndstyring) gennem en enkelt funktion. Hændelsesstrenge er hierarkiske (\texttt{keyboard:down:a}) og kan matches på ethvert specificitetsniveau. Dette erstatter den kombinatoriske eksplosion af Processing-callbacks med en enkelt, filtrerbar strøm.
\subsection{Tegneprimitiver: tilstandsløse som standard}
Processing og p5.js bruger en tilstandsbaseret grafikkontekst, hvor \texttt{fill()}, \texttt{stroke()} og transformationskald vedvarer, indtil de eksplicit ændres. AC inverterer dette: \texttt{ink()}-funktionen sætter farve for det \emph{umiddelbart følgende} tegnekald og returnerer API-objektet til kædekobling:
\begin{lstlisting}[style=acjsstyle]function paint({ wipe, ink, line, circle }) { wipe("black"); ink("red").circle(50, 50, 20); ink("blue").line(0, 0, 100, 100); // Ingen tilstandslæk mellem kald}\end{lstlisting}
\texttt{ink()}-retur-og-kæde-mønstret gør farve-form-par visuelt atomare: hver tegneoperation er et selvstændigt udtryk snarere end en sekvens af kontekstmutationer. Dette eliminerer den fejlklasse, hvor glemte \texttt{fill()}- eller \texttt{stroke()}-kald fra et tidligere frame (eller en tidligere funktion) bløder ind i urelateret tegning.
\texttt{wipe()}-funktionen erstatter Processings \texttt{background()}, med et kortere, mere aktivt verbum. Denne navngivning er bevidst: ``wipe'' antyder en fysisk handling (at tørre en overflade) snarere end en egenskabsindstilling.
\subsection{Ingen lærredskonfiguration}
I Processing er den første linje i \texttt{setup()} typisk \texttt{size(w, h)}. I p5.js er det \texttt{createCanvas(w, h)}. I AC er der intet ækvivalent kald. Køretiden leverer lærredet i enhedens native opløsning, og pieces modtager \texttt{screen.width} og \texttt{screen.height} som skrivebeskyttede egenskaber.
Dette afspejler en mobil-først designfilosofi: på telefoner og tablets er den ``korrekte'' lærredsstørrelse enhedens skærm. At tillade programmøren at specificere dimensioner skaber en uoverensstemmelse mellem det faste lærred og den variable viewport. AC eliminerer denne uoverensstemmelse ved at gøre lærredet responsivt som standard.
% ============ 5. API-OVERFLADE SAMMENLIGNING ============
\section{API-overfladesammenligning}\label{sec:comparison}
Tabel~\ref{tab:lifecycle} sammenligner livscyklusmodellerne. Tabel~\ref{tab:drawing} sammenligner tegneprimitiver.
\begin{table}[h]\small\centering\begin{tabularx}{\columnwidth}{lXXX}\toprule & \textbf{Processing} & \textbf{p5.js} & \textbf{AC} \\\midruleInit & \texttt{setup()} & \texttt{setup()} & \texttt{boot(\$)} \\Render & \texttt{draw()} & \texttt{draw()} & \texttt{paint(\$)} \\Logik & (i draw) & (i draw) & \texttt{sim(\$)} \\Input & callbacks & callbacks & \texttt{act(\$)} \\Oprydning & --- & \texttt{remove()} & \texttt{leave(\$)} \\\midruleRenderrate & 60fps & 60fps & skærm Hz \\Logikrate & 60fps & 60fps & 120fps fast \\Scope & globalt & globalt/inst. & injiceret \\\bottomrule\end{tabularx}\caption{Livscyklussammenligning. \texttt{\$} betegner destruktureret API-injektion.}\label{tab:lifecycle}\end{table}
\begin{table}[h]\small\centering\begin{tabularx}{\columnwidth}{lXX}\toprule\textbf{Processing/p5} & \textbf{AC} & \textbf{Noter} \\\midrule\texttt{background()} & \texttt{wipe()} & Verbum, ikke egenskab \\\texttt{fill() + stroke()} & \texttt{ink()} & Samlet, kædebar \\\texttt{ellipse()} & \texttt{circle()} & Opkaldt efter form \\\texttt{rect()} & \texttt{box()} & Kortere navn \\\texttt{line()} & \texttt{line()} & Uændret \\\texttt{point()} & \texttt{plot()} & Graf-metafor \\\texttt{text()} & \texttt{write()} & Aktivt verbum \\--- & \texttt{flood()} & Fyld region \\--- & \texttt{paste()} & Buffer-kompositing \\--- & \texttt{form()} & 3D-rendering \\\bottomrule\end{tabularx}\caption{Sammenligning af tegneprimitiver.}\label{tab:drawing}\end{table}
\subsection{Navngivningsfilosofi}
Processings API-navne er beskrivende substantiver og adjektiver: \texttt{background}, \texttt{ellipse}, \texttt{rect}, \texttt{stroke}, \texttt{fill}. De beskriver \emph{hvad} der sættes eller tegnes. AC's navne er aktive verber: \texttt{wipe}, \texttt{ink}, \texttt{plot}, \texttt{write}, \texttt{flood}, \texttt{paste}. De beskriver \emph{hvad programmøren gør}---fysiske handlinger udført på en overflade.
Dette skift fra beskrivende til imperativ navngivning stemmer overens med instrumentmetaforen: et instruments grænseflade forstås gennem verber (tryk, pust, slå, pluk), ikke substantiver. AC-API'en læses som en sekvens af handlinger: ``tør skærmen, blæk den pink, tegn en cirkel, skriv noget tekst.''
\subsection{Farvemodel}
Processing bruger separate \texttt{fill()}- og \texttt{stroke()}-kald, der hver accepterer RGB-, HSB- eller hex-værdier. Fyld/streg-distinktionen afspejler vektorgrafik (SVG, PostScript), hvor former har indre farve og grænsefarve.
AC bruger et enkelt \texttt{ink()}-kald, der sætter farve for alle efterfølgende operationer. Der er ingen fyld/streg-distinktion: en \texttt{circle()} er fyldt eller streget baseret på dens parametre, ikke på omgivende kontekst. \texttt{ink()}-funktionen accepterer:
\begin{itemize} \item RGB-værdier: \texttt{ink(255, 100, 50)} \item Navngivne farver: \texttt{ink("pink")}, \texttt{ink("navy")} \item Gråtone: \texttt{ink(128)} \item Alfa: \texttt{ink(255, 0, 0, 128)}\end{itemize}
Navngivne farver er et betydningsfuldt brugervenligheds-valg for begyndere. Hvor Processing kræver \texttt{fill(255, 192, 203)} for pink, accepterer AC \texttt{ink("pink")}. Det navngivne farveordforråd er bevidst lille og evokativt, tættere på en malerkasse end en farvevælger.
% ============ 6. TILSTANDSSTYRING ============
\section{Tilstandsstyring}\label{sec:state}
\subsection{Processing: globale variabler}
\begin{lstlisting}[style=processingstyle]int x = 100;int y = 100;
void draw() { background(0); x += 1; ellipse(x, y, 20, 20);}\end{lstlisting}
Tilstand i Processing lever i globale variabler. Dette er simpelt, men har velkendte problemer: al tilstand er muterbar overalt, der er ingen indkapsling, og programtilstand er umulig at skelne fra API-tilstand.
\subsection{AC: modulniveau-closures}
\begin{lstlisting}[style=acjsstyle]let x = 100;let y = 100;
function sim() { x += 1;}
function paint({ wipe, ink, circle }) { wipe(0); ink(255).circle(x, y, 20);}
export { sim, paint };\end{lstlisting}
AC pieces er ES-moduler. Variabler erklæret på modulniveau er private for piecet---usynlige for køretiden, andre pieces og det globale scope. \texttt{export}-erklæringen gør kun livscyklusfunktionerne synlige. Dette er ikke en konvention håndhævet af dokumentation; det er en garanti fra JavaScript-modulsystemet.
Adskillelsen af tilstandsmutation (\texttt{sim}) fra tilstandsrendering (\texttt{paint}) opmuntrer til en disciplin, hvor \texttt{paint} er en ren funktion af modultilstand---den læser variabler og tegner, men modificerer dem ikke. Dette håndhæves ikke, men API-strukturen gør det til det naturlige mønster.
% ============ 7. SLÆGTSKABET ============
\section{Slægtskabet}\label{sec:genealogy}
\subsection{Design By Numbers (1999)}
Maedas Design By Numbers~\citep{maeda2001dbn} introducerede kerneindsigten: et programmeringsmiljø til visuel output, med den simplest mulige API. DBN havde ingen animationsløkke---programmer kørte én gang, fra top til bund. Primitivsættet var minimalt: \texttt{Paper} (baggrund), \texttt{Pen} (stregbredde), \texttt{Line}, \texttt{Set} (pixel) og kontrolflow. Hele sproget kunne læres på en eftermiddag.
AC arver DBN's minimalisme i navngivning (korte, aktive verber) og dets overbevisning om, at API'en bør være udtømmende lærbar.
\subsection{Processing (2001)}
Processing~\citep{reas2003processing} tilføjede, hvad DBN manglede: animation (\texttt{draw()}-løkke), interaktion (\texttt{mouseX/Y}) og et rigere primitivsæt. Det tilføjede også, hvad DBN bevidst undgik: tilstand (grafikkonteksten), et standardbibliotek (matematik, typografi, billedindlæsning) og et kompileringstrin (Java). Processings største innovation var ikke nogen enkelt funktion, men \texttt{setup()}/\texttt{draw()}-parret: det simplest mulige udtryk for interaktiv animation.
AC arver livscyklusfunktionsmodellen, men opdeler \texttt{draw()} i tre hensyn (\texttt{paint}, \texttt{sim}, \texttt{act}).
\subsection{p5.js (2014)}
p5.js~\citep{mccarthy2015p5js} bragte Processing til browseren og gjorde skitser øjeblikkeligt delbare via URL. Dette var en forudsætning for AC: browseren som kreativ platform. p5.js introducerede også instance mode, der forvarslede AC's API-injektionsmønster.
AC arver browser-native-antagelsen og delbarhedsprincippet (hvert piece er en URL), men erstatter bibliotek-i-en-side-modellen med en fuld køretid: pieces inkluderer ikke et \texttt{<script>}-tag; de indlæses af platformen.
\subsection{openFrameworks (2005)}
openFrameworks~\citep{openframeworks2005} brugte en lignende livscyklus (\texttt{setup()}, \texttt{update()}, \texttt{draw()}) men i C++, med adskillelse af opdateringslogik fra rendering. AC's \texttt{sim()}/\texttt{paint()}-opsplitning er tættere på denne model end på Processings samlede \texttt{draw()}.
\subsection{Instrumentvendingen}
Slægtskabet kan opsummeres som en række adskillelser:
\begin{enumerate} \item \textbf{DBN}: engangskørsel (ingen animationsløkke). \item \textbf{Processing}: init + render (\texttt{setup} + \texttt{draw}). \item \textbf{openFrameworks}: init + opdatering + render. \item \textbf{AC}: init + input + opdatering + render + oprydning (\texttt{boot} + \texttt{act} + \texttt{sim} + \texttt{paint} + \texttt{leave}).\end{enumerate}
Hvert trin adskiller hensyn, der tidligere var sammenblandet. AC's fem-funktions model er den mest fuldstændige nedbrydning af det interaktive programs livscyklus i navngivne, enkeltansvars-indgangspunkter. Resultatet ligner perception-handling-cyklussen i legemliggjort kognition~\citep{varela1991embodied}: percipér (\texttt{act}), tænk (\texttt{sim}), handl (\texttt{paint}), og de yderligere bogstøtter af fødsel (\texttt{boot}) og død (\texttt{leave}).
% ============ 8. GENNEMARBEJDET EKSEMPEL ============
\section{Gennemarbejdet eksempel: En hoppende bold}\label{sec:example}
For at konkretisere sammenligningen implementerer vi en hoppende bold i alle tre systemer.
\subsection{Processing}
\begin{lstlisting}[style=processingstyle]float x = 200, y = 200;float vx = 3, vy = 2;
void setup() { size(400, 400);}
void draw() { background(0); x += vx; y += vy; if (x < 0 || x > width) vx *= -1; if (y < 0 || y > height) vy *= -1; fill(255, 100, 180); noStroke(); ellipse(x, y, 30, 30);}\end{lstlisting}
Logik og rendering er sammenflettet i \texttt{draw()}. Tilstandsmutation (\texttt{x += vx}), grænsetjek og tegning deler alle én funktion.
\subsection{p5.js}
\begin{lstlisting}[style=p5style]let x = 200, y = 200;let vx = 3, vy = 2;
function setup() { createCanvas(400, 400);}
function draw() { background(0); x += vx; y += vy; if (x < 0 || x > width) vx *= -1; if (y < 0 || y > height) vy *= -1; fill(255, 100, 180); noStroke(); ellipse(x, y, 30, 30);}\end{lstlisting}
Strukturelt identisk med Processing. De eneste ændringer er syntaktiske: \texttt{let} vs.\ \texttt{float}, \texttt{createCanvas} vs.\ \texttt{size}.
\subsection{AC}
\begin{lstlisting}[style=acjsstyle]let x, y, vx = 3, vy = 2;
function boot({ screen }) { x = screen.width / 2; y = screen.height / 2;}
function sim({ screen }) { x += vx; y += vy; if (x < 0 || x > screen.width) vx *= -1; if (y < 0 || y > screen.height) vy *= -1;}
function paint({ wipe, ink, circle }) { wipe(0); ink(255, 100, 180).circle(x, y, 15);}
export { boot, sim, paint };\end{lstlisting}
Hensynene er adskilt: \texttt{boot} initialiserer tilstand relativt til den faktiske skærm, \texttt{sim} opdaterer fysik ved 120Hz (hvilket sikrer konsistent opførsel på tværs af skærmenes opdateringshastigheder), og \texttt{paint} renderer uden at modificere tilstand. \texttt{ink().circle()}-kæden erstatter tre linjer (\texttt{fill}, \texttt{noStroke}, \texttt{ellipse}).
% ============ 9. DESIGNRATIONALE ============
\section{Designrationale}\label{sec:rationale}
\subsection{Hvorfor fem funktioner?}
Fem-funktions modellen er ikke motiveret af softwareingeniør-stringens (``adskillelse af hensyn'' som dogme) men af instrumentmetaforen. Et musikinstrument har distinkte faser: du tager det op (boot), du lytter og reagerer (act), du tænker over, hvad der kommer næst (sim), du spiller (paint), og til sidst lægger du det fra dig (leave). Disse er ikke udskiftelige øjeblikke---du stemmer ikke instrumentet under optræden, og du optræder ikke, mens du lægger det væk. Livscyklusfunktionerne formaliserer disse distinktioner.
\subsection{Hvorfor injicere API'en?}
Globale API'er er praktiske for begyndere, men skaber en implicit afhængighed af platformen. En Processing-skitse kan ikke forstås uden at vide, at \texttt{ellipse()} er en Processing-funktion, ikke en brugerfunktion. AC's destruktureringsmønster gør afhængigheden eksplicit: hvis \texttt{circle} optræder i funktionskroppen, optræder den i funktionssignaturen. Dette er det samme designprincip bag ES-modulimports, anvendt på funktionsniveau.
Den praktiske fordel er hot-reloading: fordi pieces ikke fanger globale referencer, kan køretiden erstatte API-objektet mellem genindlæsninger uden at ugyldiggøre piecets closures.
\subsection{Hvorfor 120Hz simulation?}
Processings \texttt{draw()} kører med skærmraten (typisk 60fps). Det betyder, at fysiksimulationer, animationstiming og inputbehandling alle kører med samme rate som pixel-output. På en 144Hz-skærm kører en Processing-skitse 2,4$\times$ hurtigere; på en 30Hz-skærm kører den med halv hastighed.
AC afkobler simulation fra visning ved at køre \texttt{sim()} med faste 120Hz. Dette sikrer deterministisk opførsel: en hoppende bold bevæger sig med samme hastighed uanset skærmens opdateringshastighed. 120Hz-raten blev valgt som et multiplum af almindelige skærmrater (60, 120) og en rimelig øvre grænse for input-responsivitet.
\subsection{Hvorfor ingen lærredsstørrelse?}
At kræve \texttt{size()} eller \texttt{createCanvas()} antager, at programmøren kender (og bekymrer sig om) outputopløsningen. På desktop er dette rimeligt. På mobil---AC's primære mål---er det en kilde til friktion: den ``rigtige'' størrelse afhænger af enheden, orienteringen og pixeltætheden, som programmøren ikke bør behøve at håndtere. AC leverer skærmen som en given størrelse, som et lærred der allerede er strakt og grundet.
% ============ 10. UDVIDET LIVSCYKLUS ============
\section{Udvidet livscyklus}\label{sec:extended}
Ud over de fem kernefunktioner kan AC pieces eksportere yderligere livscyklus-hooks:
\begin{itemize} \item \texttt{beat(\$api)} --- kaldes én gang per metronom-tick. BPM sættes via \texttt{sound.bpm}. Dette har ingen ækvivalent i Processing; det afspejler AC's orientering mod musikalske anvendelser. \item \texttt{preview(\$api)} --- renderer et statisk thumbnailbillede for piecet. Bruges i piece-lister og social deling. \item \texttt{icon(\$api)} --- renderer et favicon til browserfanen. \item \texttt{meta()} --- returnerer \texttt{\{title, desc\}} metadata til Open Graph-tags. \item \texttt{receive(event)} --- håndterer beskeder fra andre pieces eller systemet, hvilket muliggør inter-piece-kommunikation.\end{itemize}
\texttt{beat()}-funktionen er særligt bemærkelsesværdig. Den ophøjer rytmisk timing fra en funktion, programmøren selv må implementere (via \texttt{millis()} i Processing), til en førsteklasses livscyklushændelse. Dette er en API-niveau-erklæring om, at musik og rytme er kernebrugsscenarier, ikke eftertanker.
% ============ 11. KONKLUSION ============
\section{Konklusion}\label{sec:conclusion}
Processings kerneindsigt---at et programmeringsmiljø for kreativt arbejde bør levere en livscyklus, ikke bare et sprog---lever i centrum af hvert AC piece. Vejen fra \texttt{setup()}/\texttt{draw()} til \texttt{boot()}/\texttt{paint()}/\texttt{act()}/\texttt{sim()}/\texttt{leave()} er ikke en afvigelse fra Processing, men et argument for, hvad Processings model er i stand til, når den udvides yderligere.
Processing beviste, at \texttt{setup()} + \texttt{draw()} var nok til at gøre animation tilgængelig. AC piece-API'en argumenterer for, at den samme immediate-mode, livscyklusdrevne tilgang---når den nedbrydes i fem funktioner i stedet for to---kan understøtte ikke bare skitsering, men \emph{øvelse}: at vende tilbage til det samme piece, forfine det, optræde med det, opbygge flydende beherskelse over tid.
Skitsebogsmetaforen (skriv, kør, kassér) og instrumentmetaforen (boot, spil, øv, vend tilbage) er ikke modsatte. De er punkter på det samme kontinuum. Processing viste, at kontinuummet eksisterer. AC argumenterer for, at det strækker sig længere, end vi troede---at \texttt{setup()} + \texttt{draw()} var begyndelsen på en idé, hvis fulde form kræver \texttt{boot} + \texttt{act} + \texttt{sim} + \texttt{paint} + \texttt{leave}.
API'en er instrumentet. Processing er dens kerne. Hvordan API'en nedbryder handlingen at programmere, bestemmer, hvad der skabes.
\vspace{0.5em}\noindent\textit{Oversat fra engelsk. Originalversion tilgængelig på \url{https://papers.aesthetic.computer}}
\bibliographystyle{plainnat}\bibliography{references}
\end{document}