Coming from Processing or p5.js
Most of what you know carries over: same functions, same order of thinking, Setup() once and Draw() every frame. The differences are mostly C# itself. These are the ones that trip people up in the first hour.
On this page · 3 entries
The differences that matter
| In DanaProcessing | Why it matters |
|---|---|
Names are PascalCase: Fill, MouseX, FrameCount | C# convention. Lowercase fill() is a compile error with a clear message. |
Your sketch is a class: public class MySketch : Sketch | Processing hides that class from you; here you write it. Variables you keep between frames are fields of that class. |
public override void Draw() | Setup, Draw and every event (MousePressed, KeyPressed…) are overrides. The editor completes them for you. |
Decimal literals need f: 0.5f | Most of the API uses float, and C# reads 0.5 as double. |
5 / 2 is 2 | Integer division, like Java, unlike JavaScript. Write 5 / 2f for 2.5. |
Color is a type, not an int | Color c = Color(255, 0, 0); read channels with c.R or Red(c). |
PVector is a value (a struct) | Copying it copies the numbers, so var a = b; a.X = 5; doesn't change b. It has + - * / operators. |
Rotate() takes radians | As in Processing. RotateDegrees() is there when degrees read better. |
| Mouse state vs mouse events | Processing's mousePressed is both a variable and a function; here the variable is IsMousePressed and the event is MousePressed(). Same for keys. |
List<T>, LINQ, $"...", NuGet | All of .NET is available: generic lists, string interpolation, async, and any NuGet package with a // nuget: line. |
Equivalence table
| What | Processing (Java) | p5.js | DanaProcessing (C#) |
|---|---|---|---|
| Sketch structure | void setup() { } void draw() { } | function setup() { } function draw() { } | public class MySketch : Sketch { public override void Setup() { } public override void Draw() { } } |
| Canvas | size(600, 400); | createCanvas(600, 400); | Size(600, 400); |
| 3D canvas | size(600, 400, P3D); | createCanvas(600, 400, WEBGL); | Size(600, 400, RendererKind.Renderer3D); |
| Colors | color c = color(255, 0, 0); fill(c); | let c = color(255, 0, 0); fill(c); | Color c = Color(255, 0, 0); Fill(c); |
| HSB | colorMode(HSB, 360, 100, 100); fill(h, s, b); | colorMode(HSB); fill(h, s, b); | FillHSB(h, s, b); or ColorMode(ColorSpaceMode.HSB, 360, 100, 100); |
| Shapes | ellipse(x, y, w, h); circle(x, y, d); rect(x, y, w, h); | ellipse(x, y, w, h); circle(x, y, d); rect(x, y, w, h); | Ellipse(x, y, w, h); Circle(x, y, d); Rect(x, y, w, h); |
| Rotation | rotate(radians(45)); | rotate(radians(45)); (or angleMode(DEGREES)) | Rotate(Radians(45)); or RotateDegrees(45); |
| Transform stack | pushMatrix(); popMatrix(); push(); pop(); | push(); pop(); | PushMatrix(); PopMatrix(); PushStyle(); PopStyle(); |
| Mouse position | mouseX, mouseY, pmouseX | mouseX, mouseY, pmouseX | MouseX, MouseY, PMouseX |
| Is the mouse down? | mousePressed (boolean variable) | mouseIsPressed | IsMousePressed |
| Mouse event | void mousePressed() { } | function mousePressed() { } | public override void MousePressed() { } |
| Keys | key, keyCode, keyPressed, UP | key, keyCode, keyIsPressed, UP_ARROW | Key, KeyCode, IsKeyPressed, UP |
| Time | frameCount, millis(), frameRate(30) | frameCount, millis(), frameRate(30) | FrameCount, Millis(), FrameRate(30) |
| Math | map(), lerp(), constrain(), dist() | map(), lerp(), constrain(), dist() | Map(), Lerp(), Constrain(), Dist() |
| Random & noise | random(10), random(5, 10), noise(t) | random(10), random(5, 10), noise(t) | Random(10), Random(5, 10), Noise(t) |
| Vectors | PVector v = new PVector(1, 2); v.add(w); | let v = createVector(1, 2); v.add(w); | var v = new PVector(1, 2); v += w; (a value type) |
| Growable list | ArrayList<Ball> balls = new ArrayList<Ball>(); balls.add(b); balls.size() | let balls = []; balls.push(b); balls.length | var balls = new List<Ball>(); balls.Add(b); balls.Count |
| Arrays | int[] a = new int[10]; a.length | let a = new Array(10); a.length | int[] a = new int[10]; a.Length |
| Text | text("hi", x, y); textSize(20); | text("hi", x, y); textSize(20); | Text("hi", x, y); TextSize(20); |
| String formatting | nf(x, 2, 1), "x = " + x | nf(x, 2, 1), `x = ${x}` | Nf(x, 2, 1), $"x = {x:0.0}" |
| Images | PImage img = loadImage("a.png"); image(img, 0, 0); | let img = loadImage("a.png"); image(img, 0, 0); | PImage img = LoadImage("a.png"); Image(img, 0, 0); |
| Offscreen canvas | PGraphics pg = createGraphics(200, 200); | let pg = createGraphics(200, 200); | var pg = CreateGraphics(200, 200); |
| Pixels | loadPixels(); pixels[i] = color(0); updatePixels(); | loadPixels(); pixels[i*4] = 0; updatePixels(); | LoadPixels(); Pixels[i] = Color(0); UpdatePixels(); |
| Saving | save("a.png"); saveFrame("f-####.png"); | saveCanvas("a", "png"); | Save("a.png"); SaveFrame("f-####.png"); |
| Console | println(x); | console.log(x); | Println(x); |
| Data from the web | loadJSONObject("https://...") (waits) | loadJSON("https://...", gotData) | LoadJSONObject("https://...") (waits), or RequestJSONObject(url) and check .Ready in Draw() |
| Image pixels | img.loadPixels(); img.pixels[i] | img.loadPixels(); img.pixels[i*4] | img.LoadPixels(); img.Pixels[i] |
| Rounded rect | rect(x, y, w, h, 8); | rect(x, y, w, h, 8); | Rect(x, y, w, h, 8); |
| Data files | loadJSONObject("d.json"), loadTable("t.csv", "header") | loadJSON("d.json"), loadTable("t.csv", "csv", "header") | LoadJSONObject("d.json"), LoadTable("t.csv", "header") |
| Sound | Sound library: new SinOsc(this).play(); | p5.sound: new p5.Oscillator().start(); | Play(60); and [LiveLoop] async Task Beat() { ... await Sleep(1); } (built in) |
A sketch, ported
Processing's classic bouncing ball, line for line. Left out: nothing.
// Processing // DanaProcessing
float x = 100, vx = 3; // float x = 100, vx = 3; (fields)
void setup() { // public override void Setup() {
size(400, 200); // Size(400, 200);
} // }
void draw() { // public override void Draw() {
background(30); // Background(30);
x += vx; // x += vx;
if (x < 20 || x > width - 20) // if (x < 20 || x > Width - 20)
vx = -vx; // vx = -vx;
ellipse(x, height / 2, 40, 40); // Ellipse(x, Height / 2, 40, 40);
} // }
Run it: the same sketch, complete:
public class Bounce : Sketch { float x = 100, vx = 3; public override void Setup() { Size(400, 200); } public override void Draw() { Background(30); x += vx; if (x < 20 || x > Width - 20) vx = -vx; Ellipse(x, Height / 2, 40, 40); } }