Pixel-art network API
Syncs a PixelDocument through a pixelart:<assetId> room. Browser code imports @jolly-pixel/asset.pixel-art/client; asset-server code imports @jolly-pixel/asset.pixel-art/server.
import {
pixelArtRoom,
SyncedPixelDocument
} from "@jolly-pixel/asset.pixel-art/client";
const room = pixelArtRoom(client, assetId);
const synced = new SyncedPixelDocument(room);
room.join();
await synced.ready;
// On teardown: synced.dispose(); room.leave();Pending edits, acknowledgements, rebase and resume follow CommandSync.
Document synchronization
pixelArtRoom(client, assetId)returns the typed room. The caller joins and leaves it.new SyncedPixelDocument(room, { maxSize? })is a networkSyncedDocument. Itsdocumentis 1 by 1 until the first snapshot. Create it beforeroom.join().pixelArtDocumentKind(options?)buildsSyncedPixelDocuments for an@jolly-pixel/editor.hostlease.blankPixelDocument(options?)creates the 1 by 1 document, for a synced document that owns more than pixels (see voxel-map'sSyncedBlockset).createPixelArtAsset(catalog, path, document)creates apixelartasset, suffixes a conflicting path, and returns its ID.
PixelSyncClient
new PixelSyncClient({ room, document }) syncs a document you already own. It is a CommandSync, so it emits snapshot, ready, command and notice; call destroy() before leaving the room.
documentis aPixelSyncTarget: thecommandevent,applyRemoteCommand(),replayPendingCommand(),loadSnapshot()and a change source.- Local edits are sent with the
basisof their history change, and the server's answers reach the receipts ofpixelEdits(document). - A peer stroke skips the pixels a pending local stroke will win. A pending
global-fill,resizedortexture-replacedcannot be rebased, so the client asks for a snapshot. - PNG snapshots decode asynchronously (
loadPixelSnapshot). Commands that arrive meanwhile are applied after the decode. - A refused or narrowed
strokeorselect-editis answered with aselect-editcorrection holding the server's colors. Any other refused edit is answered with a snapshot.
PixelArtCanvas plugs in through canvas.document. runLocalRestore(fn) keeps the changes made inside fn local.
Wire data
interface PixelBufferSnapshot {
size: Vec2;
pixels: string; // base64 RGBA8
uvRegions: UVRegionData[];
normalMap?: NormalMapData;
palette?: RGBA8[]; // ten colors
}PixelWireSnapshotis the same snapshot withpixelseither base64 orPngPixels. A joining client gets PNG pixels fromencodePixelSnapshot().PixelNetworkCommandis a renderer buffer event plus the network command header.PixelWireCommandis what travels and is stored: strokes and selection edits may be packed as flatxypositions andrgbachannels.packPixelEvent()andunpackPixelCommand()convert between both.stroke,select-edit,global-fill,resizedandtexture-replacededit pixels. Theuv-region-*commands edit UV regions; deleting one drops its normal map zone.palette-color-changedcarries{ index, color }for slots0to9. A snapshot without a palette restores the defaults.- The
normal-map-*commands change normal map settings. The renderer docs describe every payload.
Presence
new PixelCollaboration({ room, canvas, color, label?, onRemoteUvDragging? }) shows peers' cursors, strokes, selections and UV drags on a canvas. Call destroy() before destroying the canvas.
color(clientId, profile)picks a peer's color.labeldefaults to the profileusername.peerStyle(room, style)binds either one to the room's peer profiles.- Editors that need only some previews use
PixelCursorSync,PixelStrokeGhostSync,SelectionGhostSyncorUVGhostSync. Each takesroomandcanvas, and all but the stroke one takecolor. - Previews are coalesced per animation frame and never touch the document. A preview stays until its peer publishes
nullor leaves; accepted commands and snapshots clear overlapping stroke and UV previews. - A selection stays visible until its owner deselects, leaves select mode, deletes a floating paste, or replaces or resizes the texture. It is room presence, never part of snapshots or history.
- A malformed payload clears that peer's preview.
Server protocol
PixelCommandArbiteris a networkKeyedCommandArbiteroverPIXEL_COMMAND_RULES. A narrowed stroke or selection edit is returned packed.resizedandtexture-replacedreset the pixel keys, and a validnormal-map-toggledresets the normal map keys. Aglobal-fillclaims the pixels it repaints and restores nothing at room start.pixelCommandKeys(command)andnarrowPixelCommand(command, keep)are shared by the arbiter and the client reconciler. Architecture lists the keys.correctPixelCommand(buffer, command, admitted)builds theselect-editcorrection, or returnsnullfor commands that paint nothing.applyPixelCommand(state, command)folds a command into a rendererPixelDocumentStatewith the same applier the clients use.isPixelCommand(command)narrows a union that embeds pixel commands, such as a blockset room's.pixelCommandProtocolvalidates commands andpixelSnapshotSchemavalidates snapshots.uvRegionSchemavalidates a UV region.uvLayoutSchemavalidates its geometry alone (UVLayoutData), for documents that keep regions a texture disowned.
Restricted rooms use the pixelart extension and its command actions in a rights table. Resolve roles from a trusted server session.