Everything lives in `Udonite.Pens`; the editor API is `Udonite.Pens.Editor.PensSetup`.

## Pen and Eraser

Both are tools: they share how they are held and where they draw.

### Holding

| Member | |
|---|---|
| `holding` | `VrcPickup` follows the `VRCPickup` on this object; `Custom` waits for the calls below |
| `undoKey` | Desktop key that undoes while held through a `VRCPickup`. R by default |
| `returnAfter` | Seconds after it is let go before it returns to where the world placed it, through its `VRCObjectSync`. 0 leaves it |
| `haptics` | A short tick in the VR hand holding it through its `VRCPickup` when a stroke starts. On by default |
| `tip` | The point that draws in VR |
| `world` | The scene's `PenWorld`. Empty finds it |
| `SetHeld(bool)` | Whether the local player holds it |
| `SetUse(bool)` | Whether Use is down |
| `Undo()` | Undoes the holder's newest stroke |
| `PutBack()` | Lets go of it and sends it straight back to where the world placed it |
| `bool IsHeld`, `bool IsDrawing` | What the local player is doing with it |

### Where it draws

| Member | |
|---|---|
| `desktopAim` | What desktop and phone players draw from: `View`, where they look, or `Tip`, the nib of the tool in their hand where they see it, at the depth the stroke started |
| `drawInAir` | Draws in the air when no board is in reach. Off draws only on boards |
| `airDistance` | Metres ahead of a desktop or phone player's view that air ink goes. 0.5 by default |
| `reach` | Metres a desktop or phone player reaches a board they look at. 4 by default |
| `contactDistance` | Metres a VR tip may be from a board and still draw on it |
| `sendInterval` | Seconds between sends while drawing |

### Pen

| Member | |
|---|---|
| `colour`, `width` | The ink's colour and width in metres |
| `inkStyle` | Which of `PenWorld.inkStyles` it draws in |
| `spacing` | Metres the tip moves before a stroke adds a point |
| `steadiness` | Seconds the nib is steadied over while it moves slowly; fast strokes follow it closely. Points are never closer than half the width |
| `snap` | Puts every point on a grid this many metres apart. 0 draws freely |
| `pixelBrush` | Cells painted around the tip on a pixel board |

### Eraser

| Member | |
|---|---|
| `radius` | Metres around the tip, or the line of sight, that rub out a stroke |
| `pixelBrush` | Cells cleared on a pixel board |
| `eraseInterval` | Seconds between rubs |

## PenWorld

The scene's ink.

| Member | |
|---|---|
| `lines`, `pointsPerLine` | The pool of lines, and points per line; a longer stroke carries on in the next |
| `inkStyles` | Template lines a stroke's line copies: material, width curve, texture mode, caps, corners |
| `smoothing` | Points drawn along a curve between each two a pen sends. 4 by default; 1 draws straight segments |
| `taper` | Stroke widths over which a stroke narrows at each end. 0.5 rounds the ends off; 0 cuts them square |
| `inkLifetime` | Seconds before ink fades on its own. 0 keeps it |
| `keepLeaversInk` | Keeps a player's ink when they leave |
| `lateJoinerBytes`, `joinDelay`, `catchUpSeconds` | How much ink a player who joins later receives, and when |
| `boards` | Every board, in an order all clients share. Filled by Refresh Boards |
| `StrokeTable Strokes` | The strokes this client shows, for a world that reads them |
| `StartStroke`, `AddInk`, `SendInk` | Draw a stroke from code |
| `EraseAt(point, radius)`, `EraseAlong(from, to, radius)` | Erase as an eraser would |
| `UndoLatest()` | Undoes the local player's newest stroke |
| `ClearPen(pen)` | Rubs out every stroke in a pen's colour, width and style, whoever drew it, for everyone |
| `Paint(board, kind, colour, cells)` | Paints pixel board cells for everyone |
| `ClearBoard(board)`, `ClearInk(surface)`, `ClearEverything()` | Clear for everyone |

## Whiteboard

| Member | |
|---|---|
| `mode` | `Ink` or `PixelGrid` |
| `size`, `inkLift` | The drawing area in metres, and how far ink floats in front of it |
| `columns`, `rows` | Pixel board cells, up to 256 each |
| `palette`, `background` | Pixel board colours, and the one erasers paint |
| `surface`, `textureProperty`, `smoothPixels` | How the pixels are shown |
| `publishDelay`, `publishInterval` | How soon the picture is kept for players who join later |
| `int ColourAt(cell)` | The colour index a cell shows |
| `int CellAt(point)` | The cell under a point |

## ClearButton

| Member | |
|---|---|
| `boards` | The boards it clears |
| `clearAirInk` | Also clears ink in the air |
| `access` | `Everyone` or the instance owner |
| `label` | What the button says |

## Editor

Every menu item under **Udonite > Pens** is a wrapper over `PensSetup`. Each call returns what it
made, or what is already there by that name.

| Member | |
|---|---|
| `CreatePenSet(Vector3)` | Four pens and an eraser on a tray |
| `CreatePen(name, colour, position, inkStyle, width)` | One pen |
| `CreateEraser(name, position)`, `CreateTray(position)` | The eraser, the tray |
| `CreateWhiteboard(name, mode, position, rotation, size)` | An ink board or a pixel board |
| `CreateClearButton(board)` | A clear button beside a board |
| `CreateInkStyle(name, material, widthCurve)` | An ink style; returns its index |
| `SetInkLines(world, count)` | Sets the pool size |
| `Refresh()` | Lists the scene's boards on `PenWorld` |
| `SyncPreset.Light`, `Balanced`, `Smooth` | `Apply(world, pens, erasers)` sets the network settings at once |
