Skip to content

Add Save button and Holtmont messaging bridge to Pascal Editor - #786

Open
Luis-Dokkaebi wants to merge 6 commits into
pascalorg:mainfrom
Luis-Dokkaebi:main
Open

Add Save button and Holtmont messaging bridge to Pascal Editor#786
Luis-Dokkaebi wants to merge 6 commits into
pascalorg:mainfrom
Luis-Dokkaebi:main

Conversation

@Luis-Dokkaebi

@Luis-Dokkaebi Luis-Dokkaebi commented Sep 8, 2026

Copy link
Copy Markdown

What does this PR do?

How to test

Screenshots / screen recording

Checklist

  • I've tested this locally with bun dev
  • My code follows the existing code style (run bun check to verify)
  • I've updated relevant documentation (if applicable)
  • This PR targets the main branch

Note

Medium Risk
Changes scene load path, iframe postMessage contract, and core level schema plus viewer render fallback—high impact on embedded Holtmont and 3D display, but guarded by new tests and fail-safe import behavior.

Overview
Adds Holtmont ↔ Pascal integration for the Pre Work Order iframe: a global HoltmontBridge handles HOLTMONT_3D_IMPORT by running normalizeHoltmontScene (Zod AnyNode, catalog synonym resolution, per-node drops with parent/child pruning) before setScene, replies with PASCAL_READY / ACK / ERROR (failed imports leave the current scene), and exposes __holtmontProbe for geometry-based checks. Toolbar adds export to parent (HOLTMONT_3D_EXPORT) and Save Build JSON download.

Regression guards: fixture JSON under public/holtmont-fixtures/, bun test contract tests, /test-holtmont harness, and a Playwright smoke script that asserts drawn geometry—not just store state. LevelNode now allows item children so furnished Holtmont scenes validate; @pascal-app/core/schema is exported for import validation.

Viewer fix: post-processing skips the WebGPU TSL pipeline when renderer.backend.isWebGPUBackend is false (not merely navigator.gpu), avoiding a black canvas on WebGL2 fallback (e.g. CI/SwiftShader).

Reviewed by Cursor Bugbot for commit 9a47735. Bugbot is set up for automated code reviews on this repo. Configure here.

google-labs-jules Bot and others added 4 commits May 16, 2026 20:43
- Added a `SaveButton` component to `viewer-toolbar.tsx`.
- Integrated it into `ViewerToolbarRight`.
- The button uses the central `useScene` state to extract `nodes` and `rootNodeIds`, formats them into a JSON Blob, and triggers a file download for layout preservation.
- Uses standard toolbar styling and the lucide-react 'Save' icon.

Co-authored-by: Luis-Dokkaebi <26320381+Luis-Dokkaebi@users.noreply.github.com>
…1530435

Add Save Button to Pascal Editor
Implementa el protocolo completo de comunicación iframe para
integrar el editor Pascal dentro de REAL-HOLTMONT (Vue 3).

Protocolo:
- PASCAL_READY: emitido al montar el listener para eliminar
  carreras de tiempo con el padre.
- HOLTMONT_3D_IMPORT: aplica la escena recibida al store via
  setScene() (migrations + orphan cleanup + dirty marks).
  Collections se restauran con setState si vienen no vacías.
- HOLTMONT_3D_IMPORT_ACK: enviado al padre tras aplicar la
  escena con éxito, para detener los reintentos cada 800ms.
- HOLTMONT_3D_EXPORT: botón "Guardar en Holtmont" en
  ViewerToolbarLeft que envía {nodes, rootNodeIds, collections}.

Archivos añadidos/modificados:
- apps/editor/app/holtmont-bridge.tsx  (nuevo — cliente)
- apps/editor/app/layout.tsx           (monta HoltmontBridge)
- apps/editor/app/test-holtmont/page.tsx (página de prueba)
- packages/editor/src/components/ui/HoltmontExportButton.tsx (nuevo)
- packages/editor/src/components/ui/viewer-toolbar.tsx (ViewerToolbarLeft)

https://claude.ai/code/session_01T8wymt2MFFyrZ61TzFNg5b
…ging-MOQVk

feat: add Holtmont ↔ editor postMessage bridge
@pascal

pascal Bot commented Sep 8, 2026

Copy link
Copy Markdown

I hit an error while handling your request (Model unavailable on AI Gateway free tier: Free tier users do not have access to this model. Upgrade to paid credits at https://vercel.com/d?to=%2F%5Bteam%5D%2F%7E%2Fai%3Fmodal%3Dtop-up for unrestricted…).

Please try again, rephrase, or reach out if it keeps failing.

Error id: 3f8b0133-3c6a-4061-b177-e59a40a4ba9b

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 21db2b0. Configure here.

// setScene always resets collections to {}; restore them if present
if (Object.keys(collections).length > 0) {
useScene.setState({ collections: collections as any })
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import leaves editor selection stale

High Severity

HoltmontBridge applies an imported graph with setScene only and never runs applySceneGraphToEditor or syncEditorSelectionFromCurrentScene. Viewer buildingId and levelId keep pointing at the previous scene, so the floorplan resolves no walls, slabs, or ceilings and the imported project looks empty after a successful ACK.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 21db2b0. Configure here.


export function HoltmontExportButton() {
const handleExport = () => {
if (typeof window === 'undefined' || window.parent === window.self) return

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Holtmont button dead outside iframe

Medium Severity

HoltmontExportButton is always rendered on the left toolbar, but handleExport returns immediately when window.parent === window.self. In the standalone editor the control stays visible and the click does nothing.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 21db2b0. Configure here.

claude and others added 2 commits September 8, 2026 19:15
El Plano 3D de la Pre Work Order salía en negro con cualquier diseño. Eran dos
fallos independientes, y los dos dejaban el mismo síntoma: la interfaz entera
bien y el lienzo vacío, sin ningún aviso.

1. WebGPU se daba por disponible con `'gpu' in navigator`. Chromium expone
   `navigator.gpu` en máquinas donde el dispositivo no se puede crear, y ahí
   three cae solo a WebGL2 ("WebGPURenderer: WebGPU is not available, running
   under WebGL2 backend") mientras el visor seguía montando la tubería TSL de
   post-proceso, que es WebGPU puro. Resultado: nada dibujado y la consola
   llena de "GL_INVALID_OPERATION: Feedback loop formed between Framebuffer and
   active Texture". Ahora se comprueba el backend que quedó
   (`renderer.backend.isWebGPUBackend`), que para cuando corre el efecto ya es
   el definitivo porque el Canvas espera a `renderer.init()`.

2. `useScene.setScene()` no valida: guarda el objeto tal cual. Un nodo con un
   campo de la forma equivocada —una puerta con `position: 0.5` en vez de
   `[x, y, z]`, que es lo que mandaba el generador de Holtmont— importaba sin
   quejarse y reventaba después dentro del `useFrame` de `DoorSystem`, matando
   el bucle de render. El puente ahora pasa cada nodo por `AnyNode` antes de
   tocar el store: rellena los valores por defecto que `setScene` no rellena,
   descarta lo que no se puede dibujar y responde con `HOLTMONT_3D_IMPORT_ACK`
   (con la lista de descartes) o `HOLTMONT_3D_IMPORT_ERROR`. Una escena que no
   deja ningún nodo en pie se rechaza y la anterior se queda en pantalla, en
   vez de sustituirla por una vacía.

De paso:

- `LevelNode.children` no admitía ids de `item`, aunque su propia descripción
  los nombra y la herramienta de muebles crea los nodos con el nivel como
  padre. Un nivel amueblado no pasaba `LevelNode.parse()`.
- Los muebles llegan con el nombre en `metadata.holtmontAsset` y el puente los
  resuelve contra `CATALOG_ITEMS`: el catálogo de modelos vive aquí, no en el
  generador.

Pruebas

- `bun test` (13): cada nodo de cada escena de `public/holtmont-fixtures/`
  contra el Zod real, más las escenas rotas (puerta con `position` numérico,
  tipo desconocido, mensaje sin nodos, huérfanos en cascada).
- `node apps/editor/scripts/holtmont-smoke.mjs`: abre el editor en un navegador,
  le manda las cinco escenas por `postMessage` y comprueba la geometría
  dibujada, no el store. Las cinco pasan: cuarto 5x4 con puerta, bodega 12x8 con
  dos puertas y cuatro ventanas, oficina sin vanos, casa de dos pisos con
  ventanas al frente y atrás (dos niveles, escalera y techo) y cuarto amueblado.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012KkjqdcUER3S3GX2ahziMQ
…-a6ksfv

Add Holtmont scene import with validation and test fixtures
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