Edit Trajectory In Another Tab
The Canvas Tab fork that hands you the brushstrokes
- mask
- canvas
- IMAGE
- MASK
- STRING
The pixels were never the problem - the strokes were
Most canvas editors hand you an image and call it a day. This node is a fork of Lerc's Canvas Tab - the full-page image editor that runs in a separate browser tab - with one addition: it also records the actual path of every brushstroke and passes it out as a JSON string. So alongside the composited image and its mask, you get the drawing data itself, [[x,y],[x,y],...] per stroke, as something you can feed into another node.
That's the entire pitch. If you only want a big paint editor wired into ComfyUI, the upstream Canvas Tab is the mature, documented one. This fork is for when you specifically need the trajectory - the trace of what was drawn, not just where the pixels landed. It's a niche use case (trajectory-conditioned generation, sketch-path analysis, feeding stroke data to a custom model), and the repo reads like exactly that: an experiment, not a polished product.
How it works
The heavy lifting is frontend. The node registers a CANVAS widget type, and the extension in web/main.js opens web/page/index.html - the actual editor - in another tab. When you finish a stroke, bspaint.js appends its point list to a trajectory array and posts the canvas, mask, and trajectory back to the ComfyUI page over a MessageChannel. The extension matches editor images to nodes by title: rename your node, or keep the default "Edit Trajectory In Another Tab" and it grabs whatever image is currently selected in the editor. Flip the "Queue on change" toggle on the node and it auto-queues a run every time you commit a stroke.
On execution, the Python side is a thin bridge: it reads the canvas and mask file paths the widget wrote, loads them with folder_paths, converts them to tensors, and returns them alongside the trajectory string, which it just passes through untouched. No API calls, no models, no heavy deps - just PIL and torch, both already in ComfyUI.
The inputs and outputs that matter
Three inputs, and you barely touch two of them:
- canvas and mask (
CANVAS) - set automatically when you draw in the editor. The mask is read from the alpha channel; if the layer has no alpha you get a zeroed 64×64 mask, so expect that if a layer comes back blank. - trajectory (
STRING, default[[]]) - the JSON stroke list, editable by hand if you want to inject coordinates.
Outputs: IMAGE (the composited canvas), MASK (the alpha), and STRING (the trajectory JSON). The STRING is the reason this fork exists - that's the wire into whatever consumes the stroke path.
Installing it
ComfyUI Manager: search "ComfyUI-Trajectory" and install. Or by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/chaojie/ComfyUI-Trajectory
Then restart ComfyUI. There's no requirements.txt, no model download, nothing to configure. The pack also ships a Send_To_Editor node (unregistered here) for pushing generated images back into the editor, and the upstream canvas_tab workflows folder with a Turbo SDXL and ControlLLite-depth example.
Where people get burned
The README in this repo is basically one acknowledgement line - the real docs live in the upstream canvas_tab README, so go read that one. Two practical traps from the code itself: only one editor instance is really supported ("for now that means only one editor node is practical" is a comment in the source), and the title-matching means a node with an unusual title can silently stop receiving images. If the canvas comes through but the trajectory is [[]], you drew on a layer whose strokes weren't committed to the trajectory array - a fresh draw usually fixes it. It's a small, single-purpose fork; if it misbehaves, that's likely it.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| mask | CANVAS | — | |
| canvas | CANVAS | — | |
| trajectory | STRING | [[]] | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |
| MASK | MASK | — |
| STRING | STRING | — |