Skip to content

fix: paint and texture tools - #74

Merged
jasonjgardner merged 7 commits into
jasonjgardner:mainfrom
heide-oficial:fix/paint-and-textures
Oct 1, 2026
Merged

jasonjgardner merged 7 commits into
jasonjgardner:mainfrom
heide-oficial:fix/paint-and-textures

Conversation

@heide-oficial

@heide-oficial heide-oficial commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Fixes for the paint and texture tools, found while auditing 1.9.3 with Blockbench 5.2.1 on Windows. One commit per issue:

  • texture_selection: it called rectangle-selection methods that no longer exist in Blockbench 5.2, and left an Undo edit open, so the next paint call failed. This is also where tsc reports 16 errors on main. Selections are now read and written per pixel through IntMatrix, inputs are checked before the edit opens, and feather_selection is refused with an explanation.
  • apply_texture marked the texture modified: it called updateChangesAfterEdit(), which re-encodes the bitmap, turns a file texture into an internal one and flags it unsaved. A Ctrl+S then rewrote the PNG although only face assignments changed. The call is removed.
  • apply_texture with applyTo: "none": it mapped to Texture.apply(false), which textures the faces selected in the UV editor and all six faces of box-UV cubes. none now changes nothing, and the option's description says what each mode does.
  • paint_fill_tool seeds:
    • In face and element modes, a seed that hit no face made Blockbench fill the whole texture.
    • Seeds outside the texture, or outside the active layer of a layered texture, made color fills match every transparent pixel.
    • Seeded fills now need a pixel inside the texture and the active layer. Face and element fills also need a face, found the way Painter.useFilltool finds it (UVEditor.findFaceAtUV). All checks run before anything is activated.
  • paint_with_brush:
    • It stamped pixels itself, so blend mode, pixel-perfect drawing, lock alpha, mirror painting and the current brush were ignored, and omitted settings reset the brush to a 1 px black square.
    • It now paints one native brush_tool stroke like the other paint tools, and writes only the given settings to the brush.
    • Hex colours are normalized, so #F00 paints #FF0000 instead of #F00000. Other colour strings are accepted as before.
    • On hosts older than 5.2, disconnected points are painted as separate strokes.
  • create_texture: it required layer_name with fill_color but never used it. It is now optional and documented as deprecated.
  • color_picker_tool: it was annotated read-only, although it changes the active colours and can switch the tool. It is now annotated as a non-destructive state change.

Behaviour changes to be aware of:

  • apply_texture none is a no-op.
  • paint_fill_tool rejects seeds outside the texture or the active layer, and face/element seeds that hit no face.
  • In paint_with_brush, omitted settings keep the current brush.
  • Clients that auto-approve read-only tools will now ask before color_picker_tool.

Not included: with Blockbench's colour-picker tool switch on, picking a transparent pixel sets no colour, and color_picker_tool then reports the previous colour.

Testing:

  • bun test: 1,208 pass, 0 fail (main: 1,184). bunx tsc --noEmit: only the 3 errors main already has in lib/factories.ts; the 16 in selection-tools.ts are gone. bun run build and bun run docs:build pass.
  • Live, with all the related PRs loaded together in Blockbench 5.2.1 on Windows 11, each of these failed in the audit of 1.9.3 and passes now:
    • Painting after texture_selection.
    • applyTo: "none" on a box-UV cube.
    • #F00 painting #FF0000.
    • A face fill seeded outside the texture.
  • Upstream's test:actions:live (61 checks) and test:pbr:live (75 checks) pass against the same build. The action-wrappers and mcp-identity smoke scripts are updated for the new behaviour.

Related PRs from the same audit: #70 (HTTP server, settings and file inputs), #71 (views and captures), #72 (modeling tools), #73 (animation, GeckoLib and display), #75 (headless server), #69 (loopback bind). All of them merge together without conflicts (checked).

🤖 Generated with Claude Code

heide-oficial and others added 7 commits September 30, 2026 22:11
The tool called rectangle-selection methods that no longer exist and left an undo edit open, so the next paint failed. Selections are now read and written per pixel through IntMatrix, inputs are checked before the edit opens, and feather_selection is refused with an explanation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
apply_texture called updateChangesAfterEdit(), which re-encodes the bitmap, converts a file texture to an internal one and flags it unsaved, so a Ctrl+S rewrote the PNG although only face assignments changed. The call is removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
applyTo none mapped to Texture.apply(false), which textures the faces selected in the UV editor and all six faces of box-UV cubes. none now changes nothing and only checks the element and texture, and the option's description says what each mode does.

Behaviour change: applyTo none is now a no-op that records no history entry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…er or any face

In face and element modes, a seed that hit no face made Blockbench fill the whole texture, and color fills seeded outside the texture, or outside a smaller or offset active layer, read a transparent seed and recolored every transparent pixel. Seeded fills now need a pixel inside the texture; color and color_connected fills also need it on the active layer they sample (after the paint target is resolved), and face and element fills need a face found the way Painter.useFilltool finds it (UVEditor.findFaceAtUV). The texture and face checks run before the texture is activated or any stroke starts.

Behaviour change: these seeds are now errors instead of fills of the whole texture or layer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d short hex colors

paint_with_brush stamped pixels itself, so blend mode, pixel-perfect drawing, lock alpha, mirror painting and the user's current brush were ignored, and it painted #F00 as #F00000. It now paints one native brush_tool stroke like the other paint tools and writes only the given settings to the brush.

Behaviour changes:
- Brush settings the call omits keep the current brush; before, they reset it to a 1 px opaque black square.
- connect_strokes false stamps the points as separate dabs of one stroke (one undo entry) on Blockbench 5.2 and later. Older hosts, which are not trusted to stamp a move without a line, paint one stroke per point, one undo entry each.
- Colors are accepted as before (any string, an alpha part ignored). Hex colors are normalized to #rrggbb, so #RGB and #RGBA expand per digit, and color names, which were parsed as hex digits, now paint in the named color.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
create_texture rejected fill_color without layer_name, yet never used the name: it creates textures without layers. layer_name is now optional and documented as deprecated and ignored; texture_layer_management create_layer adds a named layer. Calls that pass it are still accepted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
color_picker_tool claimed readOnlyHint although it changes the active colors, selects the texture and, with pick_opacity or depending on Blockbench's settings, sets the brush opacity or switches the active paint tool. It is now annotated as non-destructive and idempotent, and its description says what it changes, so clients that run read-only tools without asking now ask first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 59 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 2 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Repository: jasonjgardner/blockbench-mcp-plugin/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 04b521f9-0c4f-41c9-b5b0-cb541639ae0d

📥 Commits

Reviewing files that changed from the base of the PR and between 6295e20 and 4dd816e.

📒 Files selected for processing (18)
  • lib/factories.test.ts
  • server/tools/paint/brush-stroke.ts
  • server/tools/paint/brush-tools.ts
  • server/tools/paint/docs.ts
  • server/tools/paint/layer-tools.test.ts
  • server/tools/paint/native-painter.ts
  • server/tools/paint/paint-math.test.ts
  • server/tools/paint/paint-math.ts
  • server/tools/paint/schemas.ts
  • server/tools/paint/selection-tools.ts
  • server/tools/paint/stroke-tools.ts
  • server/tools/texture.ts
  • server/tools/texture/apply-texture.ts
  • tests/apply-texture.test.ts
  • tests/live/action-wrappers-smoke.ts
  • tests/live/mcp-identity-smoke.ts
  • tests/paint-wrappers.test.ts
  • tests/texture-undo.test.ts
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@jasonjgardner
jasonjgardner merged commit ec29e40 into jasonjgardner:main Oct 1, 2026
1 check passed
@jasonjgardner jasonjgardner mentioned this pull request Oct 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants