Sketch structure

Every sketch inherits from Sketch and implements Draw(). A host calls Setup() once, then Draw() on every frame, at the rate set by FrameRate().

On this page · 19 entries

Setup

  • Setup() → void

Runs once before the first frame. Use it to set the canvas size and any one-time state.

Drawabstract

  • Draw() → void

Runs once per frame while IsLooping is true. The only member every sketch must implement.

Size

  • Size(int w, int h)

Sets the canvas dimensions. Call from Setup().

FrameRate

  • FrameRate(int fps)

Sets the target frame rate. Minimum 1.

NoLoop

  • NoLoop() / Loop()

Stops or resumes automatic per-frame redraw via IsLooping.

Delay

  • Delay(int ms)

Halts the calling thread for ms milliseconds. Since Draw() runs on whatever thread the host pumps its render loop on, a long Delay() blocks that same thread/frame — exactly like Processing blocking its own animation thread.

Not for animation pacing. Use FrameRate() for smooth motion. Delay() is meant for sketches that only need to redraw occasionally and would rather sit idle than burn CPU on frames nobody will see change — a slow-updating clock, a sensor readout, an ambient display.

Thread

  • Thread(string methodName)

Runs a no-argument method of this sketch on a background thread and returns immediately, like Processing's thread(functionName). Looks the method up by name via reflection (public or private, instance method) — same string-based API as Processing's own.

No automatic locking. Write results to a field the background method owns, and have Draw() just read that field each frame. Keep the handoff to something simple (a single field write/read, or your own lock) to avoid tearing.

[Tweak] · [Tweak(float min, float max)] · ShowTweaks · HideTweaks

  • [Tweak]
  • [Tweak(float min, float max)]
  • ShowTweaks()
  • HideTweaks()

Put [Tweak] above a float, double, int, bool or Color field and it gets a live control in a panel over the running sketch: a slider (a checkbox for bool, three R/G/B sliders for Color). Drag it and the field changes while the sketch keeps running — no Run, no restart. [Tweak(0, 20)] sets the range; plain [Tweak] goes from 0 to twice the starting value. Label = "..." changes the text. Click the panel's header to fold it; HideTweaks() hides it (before SaveFrame(), say) and ShowTweaks() brings it back.

The panel takes the mouse first. A press on the panel, the drag that follows and its click never reach MousePressed()/MouseClicked(), so dragging a slider doesn't also paint on your canvas. The values live in your own fields, so ⚡ Hot Reload keeps whatever you tuned.
Put it back in the code. In the IDE, Sketch → Apply tweaks to code (also under the ▾ next to Run) writes the values you moved into those fields' initializers — only the sliders you actually touched, in one step, so a single Ctrl+Z undoes it. From code, GetTweakValues() returns each [Tweak] field's current value already written as C#.

OnStopvirtual

  • OnStop() → void

Override to let go of anything the sketch opened outside the engine — a camera, a serial port, a MIDI or audio device, a socket — like Processing's dispose(). Called once, when the sketch stops for good: ■ Stop (the Run switch) in the IDE, another Run replaces it, or its window closes. Not called on ⚡ Hot Reload, where those same objects carry over to the new code. Without it, a device opened by the previous Run stays busy until the IDE closes.

Shade · CreateShader2D · LoadShader2D

  • Shade(string sksl)
  • Shade(PShader2D shader, x?, y?, w?, h?)
  • CreateShader2D(sksl)
  • LoadShader2D(path)

Fills the canvas (or a rectangle) with a fragment shader written in SkSL — Skia's shading language: GLSL with half4/float2 instead of vec4/vec2 and a half4 main(float2 fragCoord). Runs in the plain 2D renderer on every OS. When declared, these uniforms are filled in for you: iTime, iResolution, iMouse (x, y, pressed), iFrame, iAmplitude and iSpectrum[8|16|32|64]; set your own with shader.Set("name", ...). fragCoord is in sketch pixels with y pointing down.

Live editing. Shade(source) compiles once and caches by the text, so editing the shader and pressing ⚡ Hot Reload swaps it in without restarting time or music. If the new code doesn't compile, the last good shader keeps running and the error shows bottom-left. It runs on the CPU: keep the canvas modest.

WindowResizedvirtual

  • WindowResized() → void

Called when the canvas size changes after the first frame.

DisplayDensity · PixelDensity

  • DisplayDensity() → int
  • PixelDensity(int density)

HiDPI helpers kept for API parity. DisplayDensity() always returns 1 — DanaProcessing draws everything at logical-pixel resolution and leaves any HiDPI scaling to the host. PixelDensity() only validates its argument (1 or 2, like Processing) and otherwise has no effect.

PixelWidth · PixelHeight

  • PixelWidth
  • PixelHeight → int

Width/height of the sketch's backing buffer in actual pixels, like Processing's pixelWidth/pixelHeight. Since DanaProcessing always draws at 1:1 (see PixelDensity() above), these are always equal to Width/Height — kept so sketches ported from Processing that read them directly (e.g. when indexing LoadPixels()'s array by hand) keep working unchanged.

Settingsvirtual

  • Settings() → void

Runs once, before Setup(), like Processing's settings(). The host is responsible for calling it immediately before Setup().

Optional in C#. Real Processing needs this only because size() is special-cased by the preprocessor and can't take a variable inside setup(). Plain C# has no such restriction — Size() works fine called directly inside Setup() too. Overriding Settings() is provided purely so sketches ported from Processing that rely on the setup-order guarantee (settings() strictly before setup()) keep behaving the same way.

FullScreen · WindowMove · WindowResize · WindowResizable · WindowTitle · WindowRatio

  • FullScreen(bool fullScreen = true)
  • WindowMove(x, y)
  • WindowResize(w, h)
  • WindowResizable(bool)
  • WindowTitle(string)
  • WindowRatio(w, h)

Window-management requests, each backed by an event a host can subscribe to and act on — the same pattern RedrawRequested/ExitRequested already use. SetLocation(), SetResizable(), and SetTitle() are classic-API aliases for WindowMove(), WindowResizable(), and WindowTitle() respectively.

callevent raisedreadable state
FullScreen(bool)FullScreenRequestedIsFullScreen
WindowMove(x, y)WindowMoveRequested—
WindowResize(w, h)WindowResizeRequested—
WindowResizable(bool)WindowResizableChangedIsWindowResizable
WindowTitle(string)WindowTitleChangedWindowTitleText
WindowRatio(w, h)WindowRatioRequested—
Host-dependent. Calling any of these always updates the readable state and raises its event — that part works regardless of host. Whether the actual OS window visibly moves/resizes/retitles depends entirely on whether the host you're running in (the bundled IDE, a custom Avalonia/WPF shell) subscribes to that event and acts on it. A host that doesn't wire these up yet will accept the calls silently rather than throwing.

Redraw

  • Redraw() → void

Requests a single extra frame while NoLoop() is in effect, raising the RedrawRequested event. Looping sketches don't need this — they're already rendering continuously.

Exit

  • Exit() → void

Raises the ExitRequested event. DanaProcessing doesn't own a process to terminate — whatever hosts the sketch (a window, a canvas control) should subscribe and close/stop accordingly.

Print · Println · LogWarning · LogError

  • Print(object message)
  • Println(message)
  • LogWarning(message)
  • LogError(message)

Print writes with no trailing newline and no timestamp/coloring — meant for building a line piece by piece across calls, finished off with a Println. Println/LogWarning/LogError go through DanaLogger, timestamped and color-coded by level.

propertytypemeaning
FrameCountintFrames drawn so far.
Width / HeightintCurrent canvas size.
TargetFrameRateintSet via FrameRate().
IsLoopingboolWhether the host should keep calling Draw().
DisplayWidth / DisplayHeightintSize of the screen the sketch runs on. 0 until the host sets it.

Runnable example

A complete sketch using this section. Test in Dana opens it in the IDE, or paste it into a new tab and press Run.

C#
// Setup() runs once, Draw() every frame. NoLoop()/Loop() pause and resume.
public class Structure : Sketch
{
    float angle;

    public override void Setup()
    {
        Size(500, 300);
        FrameRate(60);
    }

    public override void Draw()
    {
        Background(30, 32, 40);
        angle += 0.05f;
        Fill(255, 180, 120);
        NoStroke();
        Circle(Width / 2 + Cos(angle) * 150, Height / 2, 40);

        Fill(255);
        Text($"frame {FrameCount} · click to {(IsLooping ? "pause" : "resume")}", 12, 20);
    }

    public override void MousePressed()
    {
        if (IsLooping) NoLoop(); else Loop();
    }
}