Repository navigation
Interior views in view_scene, paint and search_materials with native scene materials - #1034
Merged
Merged
Conversation
planWallPaint and plannedWallIds move from nodes/src/wall/paint-plan.ts to core/src/systems/wall/wall-paint-plan.ts, unchanged, and core exports them. The editor's wall paint imports them from core; the agent's paint operation (next commit) writes a wall's faces through the same plan instead of a copy. Co-authored-by: Adam NAILI <adam.naili.pro@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
view_scene takes interior: { levelId }. The plan checks the level
(interior_level_invalid; interior_hidden for a hidden level or ancestor;
interior_transform_unsupported for a building tipped off the vertical) and,
with no target, eye or camera given, frames the floor from 55 degrees above.
The host gets only the level id: the MCP passes it to its SceneViewHost, and
the editor's capture works the cutaway out from its own scene with core's
sceneViewInterior. For that one render it hides the other floors and this
floor's roofs and ceilings, cuts the floor's walls and their shadows at 0.65
of the storey (a ClippingGroup on the level), draws its walls whole whatever
the wall mode, and lifts the user's solo and isolation on it
(temporarilyShowPresentation in the viewer). Everything is put back after
the render, through the capture's existing restore list.
The plan now frames buildings where they stand: what is under a building is
drawn in its frame, so its position and yaw move and turn the boxes, and an
opening is seen from its outside on the site. A roof, or a roof level holding
only roofs, frames its segments from its seat to its peak instead of
refusing nothing_to_view.
An authored snapshot pose passes the walls' finish refs when it swaps their
materials, as the wall renderer does, so painted faces keep their finishes.
From Adam's #1024. This keeps the capture on the snapshot
path view_scene already uses (it waits for the scene to build and holds the
viewport's last frame) instead of #1024's read-only transaction (per-node
commit tracking in NodeRenderer, a frame-loop freeze, control and object
state snapshots, asset readiness refusals).
Co-authored-by: Adam NAILI <adam.naili.pro@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
paint gives walls, columns, slabs, ceilings, fences, doors, windows and roofs a finish in one call, as the editor's Paint does: the slots its slot paint writes, a wall's faces through the shared wall paint plan, a roof's or a segment's top, edge or wall role field (refused shadowed_field when the roof's segments have their own). exterior and interior resolve to a wall's faces from the rooms on its sides. The finish is a colour (the nearest library colour, said with how near), a library or scene ref, a native material, or erase. Any unknown target, role or material refuses the whole call. A native material is kept as a scene material, reused when the scene holds one the material schema reads as equal. The operation returns it in SceneChanges.materials and needs the scene's materials in AgentContext.materials; a host without them refuses a native material (materials_unavailable) and still paints refs and colours. Scene refs are checked against those materials, and an unknown library material's refusal points to search_materials. get_node returns the scene materials a node's finishes use. search_materials finds library refs by words, as the library writes them (timber is wood, render is stucco), by shade and by surface, and names the words no material answers. On the MCP both are shared tools. SceneOperations gains supportsMaterialUpserts and getMaterials: the bridge lends its materials as the context and applies SceneChanges.materials as upsert_material patches, written before the nodes in the same history step. upsert_material is not part of apply_patch's schema. From Adam's #1024, without the run_batch and plan-reference hooks it was written with. Co-authored-by: Adam NAILI <adam.naili.pro@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every other floor is left out of an interior view, so a target on one framed nothing the picture shows. view_scene with interior and a target off that floor is refused interior_target_elsewhere, naming both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 45c5a14. Configure here.
…ds, interiors refuse what they leave out - paint: a wall face is painted whole, its slot and an override in each room whose wall finish shows over it, as the editor's Paint writes a click on that room's face; painted parts keep theirs and the note names them. A curtain wall's exterior or interior is refused with its roles. - search_materials: query words match whole words of a material (or begin one, from four letters), short and common words are dropped, and a flat colour suits every surface filter. - view_scene interior: a level holding only roofs and ceilings is refused, a target the picture leaves out (a roof, a ceiling) is interior_target_elsewhere, and a hidden site no longer blocks the floors on it. The contract says what is cut: everything on the floor at 0.65 of the storey height. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… and keeps the perspective it asks for
- An authored pose or an interior view asks for whole walls on
thumbnail:before-capture ({ wholeWalls: true }), and WallCutout swaps them
with the resolver the renderer mounted it with (wallsForCapture). The
capture's own swap used the plain wall palette, so a curtain wall's glass
came out opaque.
- A capture with a perspective view of its own (view_scene's) stays
perspective when the user's camera is orthographic
(capturesOrthographically); it took the user's orthographic view while
the result reported the planned camera.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Aymericr
force-pushed
the
feedback/interior-materials
branch
from
October 12, 2026 21:21
60df900 to
b566369
Compare
This was referenced Oct 13, 2026
Open
AxiomeCG
added a commit
to AxiomeCG/editor
that referenced
this pull request
Oct 13, 2026
…and search_materials pascalorg#1034, and 7 more) into the bundle 2 editor branch Main wins duplicates: pascalorg#1034 took view_scene's interior view, paint, search_materials and native scene materials from this branch and reshaped them; main's text, shape and tests are kept for all of it, and what this branch added on top of the same things and main has no word for stays. Taken from main (add/add or both-changed, one implementation each): - agent-operations/paint, scene-materials, search-materials, material-refs, get-node, create-stair's change type, systems/wall/wall-paint-plan; agent-tools/paint, search-materials, view-scene's interior input and text; mcp scene-bridge's upsert_material patch. - view_scene's interior: main's sceneViewInterior (level, bounds, cut height, hidden ids, refusals interior_*) and its editor cutaway on the capture's snapshot path replace this branch's SceneViewInteriorPolicy, graph key and read-only capture transaction (per-node commit tracking in NodeRenderer, frame-loop freeze, control and object snapshots, asset readiness refusals, the nodes' read-only batch hide). The wait for a scene that never settles (08ee96e) is main's untilSceneBuilt, which lets a stalled count go. - events/bus: main's { wholeWalls } before-capture payload; ThumbnailCapturePolicy is gone. - paint is annotated destructive, as main has it. Kept from this branch where main has nothing: - sceneViewFacing (Follow Pascal's camera), session/checkpoint context, agentSession on SceneOperations, run_batch / place_in_room / merge_windows / checkpoint registrations, AgentHostRuntime, view_scene's editor_tab_busy refusal text, create_room's room_named_by_person and corner window guide text, the pascal-3d skill's corner-window sentence. Tests: our interior policy tests and read-only capture tests go with the code they tested; the agent-guide test lists the five hosted project-context tools main's guide now names. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

What
The E2 set from Adam's #1024, curated onto main. Two capabilities:
view_scenecan look inside a floor.paintandsearch_materialsare shared agent tools, with native scene materials.Interior views (
view_scene)core/agent-tools/view-scene.ts): new inputinterior: { levelId }. The description only covers what main does; feat: Bundle 2 editing, interior captures and native materials #1024'srequest_uploadwording is gone.core/agent-operations/scene-view.ts):sceneViewInterior(nodes, levelId)returns the floor's box, a cut at 0.65 of the storey, and the ids to hide (the other floors, plus this floor's roofs and ceilings).interior_level_invalid: not a level, or a level holding only roofs and ceilings.interior_hidden: the level or a parent is hidden. A hidden site doesn't count, because it only hides its own ground.interior_transform_unsupported: a tilted building.interior_target_elsewhere: a target on another floor, or one of this floor's roofs or ceilings.thumbnail-generator.tsx):interiorCutawayruns inside the capture's existing set-up and restore cycle, for one render.temporarilyShowPresentation, new in the viewer).WallCutout. An authored pose or an interior view emitsthumbnail:before-capturewith{ wholeWalls: true }, andwallsForCaptureswaps each wall's palette using the resolver the renderer mounted, so a curtain wall keeps its glass. This replaces the capture's own swap, which used the plain wall palette.view_scenedoes) stays perspective when the user's camera is orthographic (capturesOrthographically).view-scene.ts): passesinterioron to itsSceneViewHost.nothing_to_view.paintandsearch_materialsplanWallPaintandplannedWallIdsmove unchanged fromnodes/src/wall/paint-plan.tstocore/src/systems/wall/wall-paint-plan.ts. The editor's hand paint and the agent'spaintshare one plan instead of feat: Bundle 2 editing, interior captures and native materials #1024's copy.paintgives one finish to walls, columns, slabs, ceilings, fences, doors, windows and roofs. The finish is one of:library:orscene:ref;rolepicks the surface: a slot, a wall'sexteriororinteriorface (worked out from the rooms on each side), or a roof'stop,edgeorwall.notenames them.exteriororinterioron a curtain wall.shadowed_fieldrefuses a roof role that a segment's own finish would hide.Native materials are reused when the scene already holds one the material schema reads as equal; otherwise they become a new scene material through
SceneChanges.materials. A host that can't store scene materials refuses them (materials_unavailable) but still paints refs and colours.search_materialsfinds library refs by words (timber is wood, render is stucco), by shade and by surface, and names the words nothing matched.tilematchestiles).surfacefilter.Other core changes:
AgentContext.materialsis new.requireMaterialRefchecks scene refs against the scene's materials, and its refusal now points tosearch_materials.get_nodereturns the scene materials a node's finishes use.mergeSceneChangescarries materials through.MCP:
SceneBridgetakesupsert_materialpatches, written before the nodes in the same history step. This is an internal op, not part ofapply_patch's schema.supportsMaterialUpsertsandgetMaterialsare added onSceneOperations.paintis registered as destructive andsearch_materialsas read-only.wiki/architecture/agent-surfaces.md.Not ported, on purpose:
model-loaderresource failures,ktx2-loaderload state). Interior views stay on the snapshot pathview_scenealready uses, which waits for the scene to build and holds the viewport's last frame. The asset-readiness and scene-revision gaps are on that path for everyview_scenepicture today (see Review).material-swatches.ts(only the facade elevation reads it; facades are held back).sceneViewFacing(Follow Pascal).run_batchand plan-reference hooks.Why
From the owner's feedback (plan
plans/scene-agent/ai-architect-chat-feedback.md, slice E-materials):Adam's interior views and native materials come in as shared tools: one contract and one operation in core, so the chat and the MCP get the same
paint,search_materialsandview_scene. The editor's hand paint and the agent's paint now share one wall paint plan.How to test
From a checkout that has this branch as its
editor/submodule (the commands run from the repo root):Results on this branch (head b566369):
--force): clean.Viewer and editor show only the failures that happen without this branch too: the R3F version pin, and the
history.test.tssubprocess stderr. Both come from the hosted install, not editor CI.Checked in the running app on a two-storey test scene. The chat doesn't pass
interioruntil the hosted bump, so this used a local hook that calls the chat'sexecuteViewScenedirectly.interior_target_elsewhereandinterior_level_invalidcame back as refusals.Deployment notes
paint,search_materialsandinteriorinto the chat and the hosted MCP. Until then the hosted app doesn't offer them.agent-surface-parity,hosted-mcp-tool-effectsand the hosted MCP tool count. That's expected.GEOMETRY_SCRIPT_MIME_TYPE,language) breaks hosted typecheck on its own. Any hosted bump past Blender (bpy) modules as a second geometry-script language #1033 needs that adaptation as well.agent-tools/index.ts,agent-operations/index.ts,mcp/src/tools/shared-tools.ts). Whichever lands second rebases.registerSharedToolson aSceneBridge, so it getspaintandsearch_materials, with native materials. That puts them next to the Architect plugin'sset_materialandlist_materials, which have different semantics: slots named interior/exterior, missing targets skipped. One of each pair has to be retired or routed to the other with the bump.search_materialssearches the built-in catalog only. Community and workspace materials (library:mtl_…, or registered at runtime) still need an owner beforelist_materialsretires.interiorreaches the capture on either host: the chat'sexecuteViewSceneand the hostedSceneViewHostboth drop it today. Test it on both surfaces.thumbnail:before-capturenow takes an optional{ wholeWalls }payload. Existing listeners that ignore it are unaffected.Review
Both reviews (Claude adversarial, GPT-6 Astra) were checked against the code.
Fixed:
formatchedforest,redmatchedprepared, andamatched everything. It now matches whole words and drops short and common ones. A universal flat colour now passes asurfacefilter.view_scene's requested perspective camera.WallCutout's own resolver.exteriorandinterioron a curtain wall wrote unused face slots. They are now refused.Not changed:
view_sceneand sheet capture already waits for the scene to build, then renders. The interior view adds no new path.view_sceneas a whole is a follow-up.library:mtl_…refs pass without a check (Astra). That is main's behaviour, unchanged here: the host checks community refs against its catalog. Scene refs are now checked whenever the host lends its materials.readOnly(Astra). This is in the shared runner and affects every mutating shared tool, not justpaint, so it is out of scope for this PR.findMatchingSceneMaterialcopies use core's normalising matcher, so agent-made materials aren't duplicated by hand paint.Supersedes
Supersedes in part #1024 by Adam NAILI (@AxiomeCG): its E2 set (interior captures and native materials). Adam is co-author on every commit that ports his work. The rest of #1024's curated set (E1) comes in a separate PR. Plan reference, vectorize, facades, unit layouts, photo tools, coherence, batch/checkpoints, visual references and
request_uploadare held back.🤖 Generated with Claude Code