PixelWeaver v0.5.0 /server.src.pixelweaver.command_raster
On this page

Server-side rasterizer that interprets dispatched MCP drawing commands and writes the resulting pixels directly into the target canvas frame buffer.

#server.src.pixelweaver.command_raster

#server.src.pixelweaver.command_raster

Server-side rasterizer for MCP drawing commands.

The collaboration server is the single source of truth for pixel data, but historically the drawing tools only recorded a command in command_history and relied on a connected frontend to rasterize it into pixels. In a headless MCP session (no frontend attached) those mutations were silently dropped: the server's authoritative pixel_data buffers stayed empty, GET /api/state/full returned a blank canvas, and save_project persisted empty PNGs.

This module closes that gap. apply_command interprets a dispatched drawing command (as produced by MCPCommandRegistry._make_command) and writes the resulting pixels directly into the target canvas frame, so the state the MCP pushes back actually carries the drawn pixels.

Geometry (line/rect/ellipse/diamond/flood-fill) mirrors the frontend plugins/builtin/drawing-utils.ts so the server and the UI agree on shapes. Write semantics are "replace" (overwrite RGBA), matching applyPixels / buffer.setPixel. Only RGBA drawing commands are handled; every other command type is a no-op here (role-plane and structural commands mutate state through their own paths).

#parse_hex_rgba

python
def parse_hex_rgba(color: str) -> tuple[int, int, int, int]

Parse #rrggbb or #rrggbbaa into an (r, g, b, a) tuple.

A 6-digit hex has no alpha channel and is treated as fully opaque, matching the frontend hexToRgba.

#_Buffer

Thin mutable view over a canvas frame's RGBA byte buffer.

#in_bounds

python
def in_bounds(self, x: int, y: int) -> bool

#get_pixel

python
def get_pixel(self, x: int, y: int) -> tuple[int, int, int, int]

#set_pixel

python
def set_pixel(self, x: int, y: int, r: int, g: int, b: int, a: int) -> None

#bresenham_line

python
def bresenham_line(x0: int, y0: int, x1: int, y1: int) -> list[tuple[int, int]]

Standard Bresenham line, inclusive of both endpoints.

#rect_filled

python
def rect_filled(x: int, y: int, w: int, h: int) -> list[tuple[int, int]]

Every pixel in the w x h rectangle at (x, y) (port of drawing-utils rectFilled).

#rect_outline

python
def rect_outline(x: int, y: int, w: int, h: int) -> list[tuple[int, int]]

Border pixels of the w x h rectangle at (x, y) (port of drawing-utils rectOutline).

#ellipse_outline

python
def ellipse_outline(cx: int, cy: int, rx: int, ry: int) -> list[tuple[int, int]]

Midpoint ellipse outline (port of drawing-utils ellipseOutline).

#ellipse_filled

python
def ellipse_filled(cx: int, cy: int, rx: int, ry: int) -> list[tuple[int, int]]

Solid ellipse via scanline-fill of the outline (port of drawing-utils ellipseFilled).

#diamond_outline

python
def diamond_outline(cx: int, cy: int, rx: int, ry: int) -> list[tuple[int, int]]

Diamond border through the four axis vertices (port of drawing-utils diamondOutline).

#diamond_filled

python
def diamond_filled(cx: int, cy: int, rx: int, ry: int) -> list[tuple[int, int]]

Solid diamond of radius (rx, ry) at (cx, cy) (port of drawing-utils diamondFilled).

#flood_fill

python
def flood_fill(buffer: _Buffer, start_x: int, start_y: int, tolerance: int=0) -> list[tuple[int, int]]

4-connected flood fill (port of drawing-utils floodFill).

#_srgb_to_linear

python
def _srgb_to_linear(c: float) -> float

sRGB channel (0..1) to linear light (port of culori convertRgbToLrgb).

#_rgb_to_oklab

python
def _rgb_to_oklab(r: int, g: int, b: int) -> tuple[float, float, float]

8-bit sRGB to OKLab (port of culori convertRgbToLrgb + convertLrgbToOklab).

Matches colorDistance in src/lib/color/color-utils.ts (culori's differenceEuclidean('oklab')) so the tolerance fill selects the same region as the browser.

#oklab_distance

python
def oklab_distance(c1: tuple[int, int, int], c2: tuple[int, int, int]) -> float

Perceptual OKLab Euclidean distance in [0, 1] between two RGB triples.

Port of colorDistance (color-utils.ts): Euclidean distance in OKLab, clamped to 1. Operates on the RGB channels only (the client passes rgbToHex(r, g, b), dropping alpha).

#flood_fill_tolerance

python
def flood_fill_tolerance(buffer: _Buffer, start_x: int, start_y: int, tolerance: float) -> list[tuple[int, int]]

4-connected flood fill with OKLab color tolerance.

Line-for-line port of floodFillTolerance in plugins/builtin/advanced-fill-tool.ts: transparent targets match only transparent neighbours; opaque targets match opaque neighbours whose OKLab distance from the start pixel is <= tolerance.

#scanline_fill_polygon

python
def scanline_fill_polygon(vertices: list[tuple[int, int]]) -> list[tuple[int, int]]

Scanline fill of an arbitrary polygon (port of drawing-primitives scanlineFillPolygon). Vertices are (x, y) pairs.

#_resolve_frame

python
def _resolve_frame(canvas: CanvasState, params: dict[str, Any])

Pick the frame this command targets (explicit frame_index else current).

#_resolve_layer_id

python
def _resolve_layer_id(canvas: CanvasState, params: dict[str, Any]) -> str | None

Pick the target layer id (explicit layer_id else the first layer).

#apply_command

python
def apply_command(canvas: CanvasState, command: dict[str, Any]) -> bool

Rasterize a drawing command into canvas's pixel data.

Returns True if the command was a recognized drawing command that was applied, False otherwise (structural/role/unknown commands are no-ops). Bounds are clipped; out-of-canvas geometry is simply not written.

#_rasterize

python
def _rasterize(cmd_type: str, params: dict[str, Any], buffer: _Buffer) -> None

Dispatch a single drawing command onto the buffer.

Search