Repository navigation
Releases: meterup/pascal-editor
Release list
@meterup/pascal-viewer@1.0.0-beta.6
Minor Changes
-
d3aa350: Let a host bind the 3D camera's gestures.
The bindings were fixed: left drag selects unless you're in preview mode or
holding space, middle pans, right rotates, wheel zooms. A host whose scene is
read-only, or whose users are on laptop trackpads with no middle button, had no
say — panning meant the space bar.cameraInputonuseViewermerges over the defaults rather than replacing
them, so an unset entry keeps whatever the current mode asked for:useViewer.getState().setCameraInput({ mouseButtons: { left: "pan" }, touches: { one: "pan" }, });
Actions are named for what the user sees (
pan,rotate,zoom,dolly,
andzoomPan/dollyPanfor the combined two-finger gestures) rather than
mirroring the camera library's enum, so the binding API doesn't tie a host to
that dependency. The wheel and the one-finger slots take narrower sets than the
others, because a wheel has one axis and a pinch needs two fingers.Merging also covers the modifier path, which rebuilds the bindings on every key
change, so holding space no longer drops a host's overrides. -
2f5c4e1: Rebase the fork onto upstream
pascalorg/editor@4c34032c(2026-08-24) — 478
commits, and a move off the fork's own0.9.xline onto upstream's1.0.0-beta
versioning. The fork now carries nothing but its release machinery and two
editor patches; everything else is upstream.Nothing we previously exported was removed. The public API grew substantially
(core 172 → 388 exports, viewer 106 → 193, editor 156 → 470) without breaking
underneath consumers.What matters most for consumers:
- Near-collinear wall junctions no longer explode.
calculateJunctionIntersectionsnow rejects a miter on its outcome, capped
atMITER_LIMIT(10) half-thicknesses, rather than only rejecting walls that
are exactly parallel. A junction where two walls run straight through each
other but miss collinearity by a fraction of a degree used to put a plan
vertexhalfThickness / sin(θ)away — kilometres out, collapsing the 2D
fit-to-bounds into one flat rectangle and firing beams across the 3D scene. It
now butts. Imported floor plans with off-axis wall runs render correctly. - Level assembly is dramatically faster.
findJunctionsbuckets walls into
a spatial grid by AABB instead of testing every wall against every junction
point. On a 1081-wall imported floor that is 584 ms → 11 ms per call, and
WallSystemrepeats the call every frame while progressively rebuilding. - Vertical building model. Scenes now carry explicit building and level
structure (buildingId,schema/nodes/building.ts), with load-time
migrations for saves that predate it — vertical, site-child, wall-slot,
elevator, retired-floorplan and construction-dimension. Anything synthesizing
aSceneGraphrather than loading a saved one needs to match the new shape;
this is the single change most likely to require work on the consumer side. - New packages:
capture-protocol,capture-viewer,cli. New core
systems alongsidewall/andstair/:fence/,slab/,elevator/. healSceneNodesrepairs already-saved scenes on load, dropping
degenerate nodes such as zero-length walls.
Three fork patches are dropped here because upstream made them redundant:
- The
floorplan-registry-layergeometry cache. Upstream landed its own
geometryCacheRef/levelDataCacheRefmemoisation plus thefindJunctions
prefilter above, which together address the same stall from further up. - The
ThreeElements/lineBasicNodeMaterialnarrowing inviewerthat let
tsgocheck the package. Upstream adopted the TypeScript 7 native compiler
and landed the identical narrowing. crossOriginon the 2D guide image. It forced the 2D<image>to fetch in
the same CORS mode as the 3D texture load so the two shared one browser cache
entry instead of downloading the image twice. Consumers that hand Pascal
same-origin blob URLs never hit the split in the first place, and the flag is
actively wrong for guide images served without CORS headers.
- Near-collinear wall junctions no longer explode.
-
e1d3a5a: Add
showSiteBoundaryto hide the site's boundary geometry.The boundary was always drawn, with no way to turn it off. It is a useful
reference while laying out a site and pure noise on a surface that only presents
a finished building.showSiteBoundaryjoinsuseViewernext toshowGrid/showZonesand
governs both views from one flag, because it is the same polygon in each:useViewer.getState().setShowSiteBoundary(false);
In 2D that drops the dashed polygon, its edge labels and its handles. In 3D it
drops the ground pad and the amber outline. Buildings, items and the horizon
ground are unaffected, so the scene loses its lot outline rather than its floor
— the horizon disc punches holes for slab footprints, not for the site polygon,
so it still covers the ground the pad was covering.Two things stay deliberately outside the flag. The fitted viewport still sizes
itself from the site polygon, so toggling this doesn't reframe the plan. And
sculpted terrain keeps rendering, since that is modelled geometry rather than
boundary chrome.Defaults to
trueand isn't persisted, so nothing changes until a host sets it.
Patch Changes
-
54e1b19: Let a scene theme set the ground grid's line colours and idle opacity.
appearancehardcoded both colours, and in dark mode<Grid>also ignored its
owncellColor/sectionColorprops, so neither a theme nor a host could
adjust how the grid read. That matters because the grid is drawn over the lit
groundfill: its contrast against that surface is a property of the pair, and
a light/dark flag can't settle it.groundandbackgroundSkywere already
carved out ofappearancefor the same reason.const theme = SCENE_THEMES.find((t) => t.id === "night"); theme.grid = { cell: "#2b2d3a", section: "#343747", idleOpacity: 0.18 };
All three keys are optional and fall back to the previous
appearance-derived
values, so existing themes render identically.idleOpacityapplies to the
always-on ground reference only; an active placement patch keeps its own
brightened treatment.
@meterup/pascal-nodes@1.0.0-beta.6
Minor Changes
-
2f5c4e1: Rebase the fork onto upstream
pascalorg/editor@4c34032c(2026-08-24) — 478
commits, and a move off the fork's own0.9.xline onto upstream's1.0.0-beta
versioning. The fork now carries nothing but its release machinery and two
editor patches; everything else is upstream.Nothing we previously exported was removed. The public API grew substantially
(core 172 → 388 exports, viewer 106 → 193, editor 156 → 470) without breaking
underneath consumers.What matters most for consumers:
- Near-collinear wall junctions no longer explode.
calculateJunctionIntersectionsnow rejects a miter on its outcome, capped
atMITER_LIMIT(10) half-thicknesses, rather than only rejecting walls that
are exactly parallel. A junction where two walls run straight through each
other but miss collinearity by a fraction of a degree used to put a plan
vertexhalfThickness / sin(θ)away — kilometres out, collapsing the 2D
fit-to-bounds into one flat rectangle and firing beams across the 3D scene. It
now butts. Imported floor plans with off-axis wall runs render correctly. - Level assembly is dramatically faster.
findJunctionsbuckets walls into
a spatial grid by AABB instead of testing every wall against every junction
point. On a 1081-wall imported floor that is 584 ms → 11 ms per call, and
WallSystemrepeats the call every frame while progressively rebuilding. - Vertical building model. Scenes now carry explicit building and level
structure (buildingId,schema/nodes/building.ts), with load-time
migrations for saves that predate it — vertical, site-child, wall-slot,
elevator, retired-floorplan and construction-dimension. Anything synthesizing
aSceneGraphrather than loading a saved one needs to match the new shape;
this is the single change most likely to require work on the consumer side. - New packages:
capture-protocol,capture-viewer,cli. New core
systems alongsidewall/andstair/:fence/,slab/,elevator/. healSceneNodesrepairs already-saved scenes on load, dropping
degenerate nodes such as zero-length walls.
Three fork patches are dropped here because upstream made them redundant:
- The
floorplan-registry-layergeometry cache. Upstream landed its own
geometryCacheRef/levelDataCacheRefmemoisation plus thefindJunctions
prefilter above, which together address the same stall from further up. - The
ThreeElements/lineBasicNodeMaterialnarrowing inviewerthat let
tsgocheck the package. Upstream adopted the TypeScript 7 native compiler
and landed the identical narrowing. crossOriginon the 2D guide image. It forced the 2D<image>to fetch in
the same CORS mode as the 3D texture load so the two shared one browser cache
entry instead of downloading the image twice. Consumers that hand Pascal
same-origin blob URLs never hit the split in the first place, and the flag is
actively wrong for guide images served without CORS headers.
- Near-collinear wall junctions no longer explode.
Patch Changes
-
e1d3a5a: Add
showSiteBoundaryto hide the site's boundary geometry.The boundary was always drawn, with no way to turn it off. It is a useful
reference while laying out a site and pure noise on a surface that only presents
a finished building.showSiteBoundaryjoinsuseViewernext toshowGrid/showZonesand
governs both views from one flag, because it is the same polygon in each:useViewer.getState().setShowSiteBoundary(false);
In 2D that drops the dashed polygon, its edge labels and its handles. In 3D it
drops the ground pad and the amber outline. Buildings, items and the horizon
ground are unaffected, so the scene loses its lot outline rather than its floor
— the horizon disc punches holes for slab footprints, not for the site polygon,
so it still covers the ground the pad was covering.Two things stay deliberately outside the flag. The fitted viewport still sizes
itself from the site polygon, so toggling this doesn't reframe the plan. And
sculpted terrain keeps rendering, since that is modelled geometry rather than
boundary chrome.Defaults to
trueand isn't persisted, so nothing changes until a host sets it.
@meterup/pascal-mcp@1.0.0-beta.7
Minor Changes
-
2f5c4e1: Rebase the fork onto upstream
pascalorg/editor@4c34032c(2026-08-24) — 478
commits, and a move off the fork's own0.9.xline onto upstream's1.0.0-beta
versioning. The fork now carries nothing but its release machinery and two
editor patches; everything else is upstream.Nothing we previously exported was removed. The public API grew substantially
(core 172 → 388 exports, viewer 106 → 193, editor 156 → 470) without breaking
underneath consumers.What matters most for consumers:
- Near-collinear wall junctions no longer explode.
calculateJunctionIntersectionsnow rejects a miter on its outcome, capped
atMITER_LIMIT(10) half-thicknesses, rather than only rejecting walls that
are exactly parallel. A junction where two walls run straight through each
other but miss collinearity by a fraction of a degree used to put a plan
vertexhalfThickness / sin(θ)away — kilometres out, collapsing the 2D
fit-to-bounds into one flat rectangle and firing beams across the 3D scene. It
now butts. Imported floor plans with off-axis wall runs render correctly. - Level assembly is dramatically faster.
findJunctionsbuckets walls into
a spatial grid by AABB instead of testing every wall against every junction
point. On a 1081-wall imported floor that is 584 ms → 11 ms per call, and
WallSystemrepeats the call every frame while progressively rebuilding. - Vertical building model. Scenes now carry explicit building and level
structure (buildingId,schema/nodes/building.ts), with load-time
migrations for saves that predate it — vertical, site-child, wall-slot,
elevator, retired-floorplan and construction-dimension. Anything synthesizing
aSceneGraphrather than loading a saved one needs to match the new shape;
this is the single change most likely to require work on the consumer side. - New packages:
capture-protocol,capture-viewer,cli. New core
systems alongsidewall/andstair/:fence/,slab/,elevator/. healSceneNodesrepairs already-saved scenes on load, dropping
degenerate nodes such as zero-length walls.
Three fork patches are dropped here because upstream made them redundant:
- The
floorplan-registry-layergeometry cache. Upstream landed its own
geometryCacheRef/levelDataCacheRefmemoisation plus thefindJunctions
prefilter above, which together address the same stall from further up. - The
ThreeElements/lineBasicNodeMaterialnarrowing inviewerthat let
tsgocheck the package. Upstream adopted the TypeScript 7 native compiler
and landed the identical narrowing. crossOriginon the 2D guide image. It forced the 2D<image>to fetch in
the same CORS mode as the 3D texture load so the two shared one browser cache
entry instead of downloading the image twice. Consumers that hand Pascal
same-origin blob URLs never hit the split in the first place, and the flag is
actively wrong for guide images served without CORS headers.
- Near-collinear wall junctions no longer explode.
All notable changes to @meterup/pascal-mcp will be documented in this file.
The format is based on Keep a Changelog,
and this project adheres to Semantic Versioning.
@meterup/pascal-ifc-converter@1.0.0-beta.6
Minor Changes
-
2f5c4e1: Rebase the fork onto upstream
pascalorg/editor@4c34032c(2026-08-24) — 478
commits, and a move off the fork's own0.9.xline onto upstream's1.0.0-beta
versioning. The fork now carries nothing but its release machinery and two
editor patches; everything else is upstream.Nothing we previously exported was removed. The public API grew substantially
(core 172 → 388 exports, viewer 106 → 193, editor 156 → 470) without breaking
underneath consumers.What matters most for consumers:
- Near-collinear wall junctions no longer explode.
calculateJunctionIntersectionsnow rejects a miter on its outcome, capped
atMITER_LIMIT(10) half-thicknesses, rather than only rejecting walls that
are exactly parallel. A junction where two walls run straight through each
other but miss collinearity by a fraction of a degree used to put a plan
vertexhalfThickness / sin(θ)away — kilometres out, collapsing the 2D
fit-to-bounds into one flat rectangle and firing beams across the 3D scene. It
now butts. Imported floor plans with off-axis wall runs render correctly. - Level assembly is dramatically faster.
findJunctionsbuckets walls into
a spatial grid by AABB instead of testing every wall against every junction
point. On a 1081-wall imported floor that is 584 ms → 11 ms per call, and
WallSystemrepeats the call every frame while progressively rebuilding. - Vertical building model. Scenes now carry explicit building and level
structure (buildingId,schema/nodes/building.ts), with load-time
migrations for saves that predate it — vertical, site-child, wall-slot,
elevator, retired-floorplan and construction-dimension. Anything synthesizing
aSceneGraphrather than loading a saved one needs to match the new shape;
this is the single change most likely to require work on the consumer side. - New packages:
capture-protocol,capture-viewer,cli. New core
systems alongsidewall/andstair/:fence/,slab/,elevator/. healSceneNodesrepairs already-saved scenes on load, dropping
degenerate nodes such as zero-length walls.
Three fork patches are dropped here because upstream made them redundant:
- The
floorplan-registry-layergeometry cache. Upstream landed its own
geometryCacheRef/levelDataCacheRefmemoisation plus thefindJunctions
prefilter above, which together address the same stall from further up. - The
ThreeElements/lineBasicNodeMaterialnarrowing inviewerthat let
tsgocheck the package. Upstream adopted the TypeScript 7 native compiler
and landed the identical narrowing. crossOriginon the 2D guide image. It forced the 2D<image>to fetch in
the same CORS mode as the 3D texture load so the two shared one browser cache
entry instead of downloading the image twice. Consumers that hand Pascal
same-origin blob URLs never hit the split in the first place, and the flag is
actively wrong for guide images served without CORS headers.
- Near-collinear wall junctions no longer explode.
Patch Changes
@meterup/pascal-editor@1.0.0-beta.6
Minor Changes
-
d3aa350: Let a host bind the 3D camera's gestures.
The bindings were fixed: left drag selects unless you're in preview mode or
holding space, middle pans, right rotates, wheel zooms. A host whose scene is
read-only, or whose users are on laptop trackpads with no middle button, had no
say — panning meant the space bar.cameraInputonuseViewermerges over the defaults rather than replacing
them, so an unset entry keeps whatever the current mode asked for:useViewer.getState().setCameraInput({ mouseButtons: { left: "pan" }, touches: { one: "pan" }, });
Actions are named for what the user sees (
pan,rotate,zoom,dolly,
andzoomPan/dollyPanfor the combined two-finger gestures) rather than
mirroring the camera library's enum, so the binding API doesn't tie a host to
that dependency. The wheel and the one-finger slots take narrower sets than the
others, because a wheel has one axis and a pinch needs two fingers.Merging also covers the modifier path, which rebuilds the bindings on every key
change, so holding space no longer drops a host's overrides. -
068468e: Add
onHeadingChangeto the floor-plan compass slot.needleRefis the only way a host gets the per-frame heading, and it's typed
RefObject<SVGSVGElement>for the element that visually rotates. That works for
a host whose rotating element is an<svg>it owns, and not at all for one
composing an existing icon component, which has nowhere to put the ref and
falls back to re-rendering per commit.onHeadingChangecarries the same values as a subscription:floorplanCompassSlot={({ northRotationDeg, alignToNorth, onHeadingChange }) => { const heading = useMotionValue(northRotationDeg) useEffect(() => onHeadingChange((deg) => heading.set(deg)), [onHeadingChange]) return <motion.div style={{ rotate: heading }} onClick={alignToNorth}>{glyph}</motion.div> }}
It fires immediately with the current heading, because each source only writes
on its own updates and a still view sends nothing, so a subscriber that waited
would show north until the first movement.Deliberately a callback rather than an animation library's value type, so the
slot contract stays library-agnostic and a host can drive a plain style write
instead if it prefers.needleRefis unchanged. -
9a4878b: Add
floorplanDividerSlotfor host-owned split-view dividers.The divider's pill was a fixed neutral capsule, so a host whose own resize
handles look nothing like it had no way to reconcile the two, and nowhere to
hang a control that belongs on the boundary between the panes.The slot replaces the pill and receives the handler that starts the pane drag,
so a host can put it on whatever the user actually grabs:<Editor floorplanDividerSlot={({ startResize }) => ( <MyControlGroup> <MyToggle onClick={(event) => event.stopPropagation()} /> <MyGrabHandle onPointerDown={startResize} /> </MyControlGroup> )} />
The divider itself still starts a drag on pointer down, so controls that aren't
the grab handle need to stop propagation or clicking them resizes the panes.Only rendered in split view. Omitting the slot keeps the built-in pill, which
also now carriesdata-pascal-floorplan-divider-thumbfor hosts that only want
to restyle it. -
2f5c4e1: Rebase the fork onto upstream
pascalorg/editor@4c34032c(2026-08-24) — 478
commits, and a move off the fork's own0.9.xline onto upstream's1.0.0-beta
versioning. The fork now carries nothing but its release machinery and two
editor patches; everything else is upstream.Nothing we previously exported was removed. The public API grew substantially
(core 172 → 388 exports, viewer 106 → 193, editor 156 → 470) without breaking
underneath consumers.What matters most for consumers:
- Near-collinear wall junctions no longer explode.
calculateJunctionIntersectionsnow rejects a miter on its outcome, capped
atMITER_LIMIT(10) half-thicknesses, rather than only rejecting walls that
are exactly parallel. A junction where two walls run straight through each
other but miss collinearity by a fraction of a degree used to put a plan
vertexhalfThickness / sin(θ)away — kilometres out, collapsing the 2D
fit-to-bounds into one flat rectangle and firing beams across the 3D scene. It
now butts. Imported floor plans with off-axis wall runs render correctly. - Level assembly is dramatically faster.
findJunctionsbuckets walls into
a spatial grid by AABB instead of testing every wall against every junction
point. On a 1081-wall imported floor that is 584 ms → 11 ms per call, and
WallSystemrepeats the call every frame while progressively rebuilding. - Vertical building model. Scenes now carry explicit building and level
structure (buildingId,schema/nodes/building.ts), with load-time
migrations for saves that predate it — vertical, site-child, wall-slot,
elevator, retired-floorplan and construction-dimension. Anything synthesizing
aSceneGraphrather than loading a saved one needs to match the new shape;
this is the single change most likely to require work on the consumer side. - New packages:
capture-protocol,capture-viewer,cli. New core
systems alongsidewall/andstair/:fence/,slab/,elevator/. healSceneNodesrepairs already-saved scenes on load, dropping
degenerate nodes such as zero-length walls.
Three fork patches are dropped here because upstream made them redundant:
- The
floorplan-registry-layergeometry cache. Upstream landed its own
geometryCacheRef/levelDataCacheRefmemoisation plus thefindJunctions
prefilter above, which together address the same stall from further up. - The
ThreeElements/lineBasicNodeMaterialnarrowing inviewerthat let
tsgocheck the package. Upstream adopted the TypeScript 7 native compiler
and landed the identical narrowing. crossOriginon the 2D guide image. It forced the 2D<image>to fetch in
the same CORS mode as the 3D texture load so the two shared one browser cache
entry instead of downloading the image twice. Consumers that hand Pascal
same-origin blob URLs never hit the split in the first place, and the flag is
actively wrong for guide images served without CORS headers.
- Near-collinear wall junctions no longer explode.
-
068468e: Add
useFloorplanNavigationControlsfor host-driven 2D navigation.A host could already move the plan with
publishNavigationSyncPose, but only by
knowing rather a lot: that a pose is{ target, azimuth, viewWidth }, that
'host'is the one source that always reaches the plan, that azimuth is
radians, that screen deltas have to be rotated into the plan by its own azimuth
before they can move the target, and that animating means publishing a stream
rather than a single pose. The demo inapps/editordid all of that by hand.The hook does it instead:
const plan = useFloorplanNavigationControls() useGesture({ onDrag: ({ delta: [dx, dy] }) => plan.panByPixels(-dx, -dy), onPinch: ({ offset: [scale] }) => plan.zoomTo(scale), }) <button onClick={() => plan.rotateByDegrees(90, { durationMs: 260 })}>Rotate</button>
Rotation tweens take the short way round, so turning from 350° to 10° travels
20° forwards rather than 340° back, and an in-flight tween is cancelled by the
next command or by unmount.Whether a command moves the 3D camera too is the link's business, not the
hook's: these publish as'host', which always drives the plan, and the camera
follows only whilefloorplanNavigationLinkis on.The hook reads the shared pose at call time through
getPose()and
getMetersPerPixel()rather than subscribing to it.navigationSyncPose
changes every frame while anything is moving, so a subscription would re-render
the caller at that rate, which for a component that renders the editor is the
whole cost the imperative viewport exists to avoid. The returned object has a
stable identity, so it can go straight into an effect's dependencies.Supporting this, the floor-plan panel now publishes its measured size in CSS
pixels. A pose carries only its width in metres, so until now nobody but the
panel could convert one back to screen space, which is why the playground had
to stand inwindow.innerWidthand why it was wrong in split view. The panel
also republishesnavigationSyncPoseon every committed viewport change rather
than seeding it once: a single seed goes stale as soon as the plan moves any
other way, most obviously the initial fit, and a host reading that stale pose
and publishing it back dragged the plan to wherever the seed was taken. -
5fbeb64: Add
hideBuiltInOverlays, and let hosts style the split-view divider.Hosts that bring their own toolbar had one way to get rid of the editor's
floating overlays: hold capture mode on. That works, but capture mode is a
snapshot mode. It also unmountsSelectionManager, which owns the highlight
material and the outliner as well as click handling, so the canvas ends up
unselectable and nothing highlights even when something is selected from the
2D plan. Permanent capture mode is the wrong tool and this was the cost.hideBuiltInOverlayshides exactly the chrome and nothing else:<Editor hideBuiltInOverlays layoutVersion="v2" />
That drops the level selector, the action menu, the panel manager, the helper
manager, the built-in Plugins rail entry and the camera-controls hint, in both
layout versions. The Plugins entry matters becauseuseHostPanelsappends it
in theeditworkspace, so a host passingsidebarTabs={[]}still got a
non-empty tab bar and the v2 layout rendered a left column for a panel it never
as...
@meterup/pascal-core@1.0.0-beta.6
Minor Changes
-
2f5c4e1: Rebase the fork onto upstream
pascalorg/editor@4c34032c(2026-08-24) — 478
commits, and a move off the fork's own0.9.xline onto upstream's1.0.0-beta
versioning. The fork now carries nothing but its release machinery and two
editor patches; everything else is upstream.Nothing we previously exported was removed. The public API grew substantially
(core 172 → 388 exports, viewer 106 → 193, editor 156 → 470) without breaking
underneath consumers.What matters most for consumers:
- Near-collinear wall junctions no longer explode.
calculateJunctionIntersectionsnow rejects a miter on its outcome, capped
atMITER_LIMIT(10) half-thicknesses, rather than only rejecting walls that
are exactly parallel. A junction where two walls run straight through each
other but miss collinearity by a fraction of a degree used to put a plan
vertexhalfThickness / sin(θ)away — kilometres out, collapsing the 2D
fit-to-bounds into one flat rectangle and firing beams across the 3D scene. It
now butts. Imported floor plans with off-axis wall runs render correctly. - Level assembly is dramatically faster.
findJunctionsbuckets walls into
a spatial grid by AABB instead of testing every wall against every junction
point. On a 1081-wall imported floor that is 584 ms → 11 ms per call, and
WallSystemrepeats the call every frame while progressively rebuilding. - Vertical building model. Scenes now carry explicit building and level
structure (buildingId,schema/nodes/building.ts), with load-time
migrations for saves that predate it — vertical, site-child, wall-slot,
elevator, retired-floorplan and construction-dimension. Anything synthesizing
aSceneGraphrather than loading a saved one needs to match the new shape;
this is the single change most likely to require work on the consumer side. - New packages:
capture-protocol,capture-viewer,cli. New core
systems alongsidewall/andstair/:fence/,slab/,elevator/. healSceneNodesrepairs already-saved scenes on load, dropping
degenerate nodes such as zero-length walls.
Three fork patches are dropped here because upstream made them redundant:
- The
floorplan-registry-layergeometry cache. Upstream landed its own
geometryCacheRef/levelDataCacheRefmemoisation plus thefindJunctions
prefilter above, which together address the same stall from further up. - The
ThreeElements/lineBasicNodeMaterialnarrowing inviewerthat let
tsgocheck the package. Upstream adopted the TypeScript 7 native compiler
and landed the identical narrowing. crossOriginon the 2D guide image. It forced the 2D<image>to fetch in
the same CORS mode as the 3D texture load so the two shared one browser cache
entry instead of downloading the image twice. Consumers that hand Pascal
same-origin blob URLs never hit the split in the first place, and the flag is
actively wrong for guide images served without CORS headers.
- Near-collinear wall junctions no longer explode.
Patch Changes
-
2251db5: Add an
alignmentGuideStrokeslot toFloorplanPaletteand draw the 2D snap
guides from it.FloorplanAlignmentGuideLayerhardcoded#ef4444, so the one piece of 2D
chrome most visible during a drag was the one piece a theme couldn't reach.
It already consumes the render context, so it now reads the slot and keeps the
red as its no-provider fallback. -
5ea6e96: Let plugins type their node kinds into
AnyNodeby declaration merging.Plugin kinds were absent from
AnyNode,AnyNodeTypeandAnyNodeId, so
plugin code and anything consuming it had to widen tostringor cast. Ids
made it worse:objectIdproduces`${kind}_${string}`, so a plugin node's
id was never assignable toAnyNodeIdand generic scene code reached for
as AnyNodeId.Declare kinds in
PluginNodesand they join all three unions, which restores
exhaustiveswitches and drops the casts:declare module "@meterup/pascal-core/plugin-nodes" { interface PluginNodes { tree: z.infer<typeof TreeNode>; } }
Purely type-level and additive. The interface ships empty,
PluginNodeType
resolves tonever, andAnyNodestays exactly equal to the newBuiltinNode
alias, so a host with no plugins sees no change at all. There is no runtime
component and no API signature churn;nodeRegistry.getstill takesstring,
which it has to, sincesetPluginDiscoveryallows kinds that were never
compiled against.Two design points worth knowing:
The interface lives in its own module and is reachable only at
@meterup/pascal-core/plugin-nodes.declare modulemerges only with the module
that declares the interface, and the package entry is a pure barrel, so
augmenting@meterup/pascal-corewould quietly declare an unrelated second
interface and widen nothing. Nothing else is exported from that module, so an
augmentation has nothing to shadow.PluginNodeadds the commonBaseNodefields and takestypefrom the key
rather than trusting the declared shape.AnyNodeis a union, and a union only
exposes properties present on every member, so a declaration that
under-described itself would silently stripparentIdand friends from
AnyNodeacross the entire host, with the errors landing in host code far from
the plugin responsible. -
Updated dependencies [2f5c4e1]
- @meterup/pascal-capture-protocol@1.0.0-beta.5
@meterup/pascal-cli@1.0.0-beta.2
Minor Changes
-
2f5c4e1: Rebase the fork onto upstream
pascalorg/editor@4c34032c(2026-08-24) — 478
commits, and a move off the fork's own0.9.xline onto upstream's1.0.0-beta
versioning. The fork now carries nothing but its release machinery and two
editor patches; everything else is upstream.Nothing we previously exported was removed. The public API grew substantially
(core 172 → 388 exports, viewer 106 → 193, editor 156 → 470) without breaking
underneath consumers.What matters most for consumers:
- Near-collinear wall junctions no longer explode.
calculateJunctionIntersectionsnow rejects a miter on its outcome, capped
atMITER_LIMIT(10) half-thicknesses, rather than only rejecting walls that
are exactly parallel. A junction where two walls run straight through each
other but miss collinearity by a fraction of a degree used to put a plan
vertexhalfThickness / sin(θ)away — kilometres out, collapsing the 2D
fit-to-bounds into one flat rectangle and firing beams across the 3D scene. It
now butts. Imported floor plans with off-axis wall runs render correctly. - Level assembly is dramatically faster.
findJunctionsbuckets walls into
a spatial grid by AABB instead of testing every wall against every junction
point. On a 1081-wall imported floor that is 584 ms → 11 ms per call, and
WallSystemrepeats the call every frame while progressively rebuilding. - Vertical building model. Scenes now carry explicit building and level
structure (buildingId,schema/nodes/building.ts), with load-time
migrations for saves that predate it — vertical, site-child, wall-slot,
elevator, retired-floorplan and construction-dimension. Anything synthesizing
aSceneGraphrather than loading a saved one needs to match the new shape;
this is the single change most likely to require work on the consumer side. - New packages:
capture-protocol,capture-viewer,cli. New core
systems alongsidewall/andstair/:fence/,slab/,elevator/. healSceneNodesrepairs already-saved scenes on load, dropping
degenerate nodes such as zero-length walls.
Three fork patches are dropped here because upstream made them redundant:
- The
floorplan-registry-layergeometry cache. Upstream landed its own
geometryCacheRef/levelDataCacheRefmemoisation plus thefindJunctions
prefilter above, which together address the same stall from further up. - The
ThreeElements/lineBasicNodeMaterialnarrowing inviewerthat let
tsgocheck the package. Upstream adopted the TypeScript 7 native compiler
and landed the identical narrowing. crossOriginon the 2D guide image. It forced the 2D<image>to fetch in
the same CORS mode as the 3D texture load so the two shared one browser cache
entry instead of downloading the image twice. Consumers that hand Pascal
same-origin blob URLs never hit the split in the first place, and the flag is
actively wrong for guide images served without CORS headers.
- Near-collinear wall junctions no longer explode.
@meterup/pascal-capture-viewer@1.0.0-beta.5
Minor Changes
-
2f5c4e1: Rebase the fork onto upstream
pascalorg/editor@4c34032c(2026-08-24) — 478
commits, and a move off the fork's own0.9.xline onto upstream's1.0.0-beta
versioning. The fork now carries nothing but its release machinery and two
editor patches; everything else is upstream.Nothing we previously exported was removed. The public API grew substantially
(core 172 → 388 exports, viewer 106 → 193, editor 156 → 470) without breaking
underneath consumers.What matters most for consumers:
- Near-collinear wall junctions no longer explode.
calculateJunctionIntersectionsnow rejects a miter on its outcome, capped
atMITER_LIMIT(10) half-thicknesses, rather than only rejecting walls that
are exactly parallel. A junction where two walls run straight through each
other but miss collinearity by a fraction of a degree used to put a plan
vertexhalfThickness / sin(θ)away — kilometres out, collapsing the 2D
fit-to-bounds into one flat rectangle and firing beams across the 3D scene. It
now butts. Imported floor plans with off-axis wall runs render correctly. - Level assembly is dramatically faster.
findJunctionsbuckets walls into
a spatial grid by AABB instead of testing every wall against every junction
point. On a 1081-wall imported floor that is 584 ms → 11 ms per call, and
WallSystemrepeats the call every frame while progressively rebuilding. - Vertical building model. Scenes now carry explicit building and level
structure (buildingId,schema/nodes/building.ts), with load-time
migrations for saves that predate it — vertical, site-child, wall-slot,
elevator, retired-floorplan and construction-dimension. Anything synthesizing
aSceneGraphrather than loading a saved one needs to match the new shape;
this is the single change most likely to require work on the consumer side. - New packages:
capture-protocol,capture-viewer,cli. New core
systems alongsidewall/andstair/:fence/,slab/,elevator/. healSceneNodesrepairs already-saved scenes on load, dropping
degenerate nodes such as zero-length walls.
Three fork patches are dropped here because upstream made them redundant:
- The
floorplan-registry-layergeometry cache. Upstream landed its own
geometryCacheRef/levelDataCacheRefmemoisation plus thefindJunctions
prefilter above, which together address the same stall from further up. - The
ThreeElements/lineBasicNodeMaterialnarrowing inviewerthat let
tsgocheck the package. Upstream adopted the TypeScript 7 native compiler
and landed the identical narrowing. crossOriginon the 2D guide image. It forced the 2D<image>to fetch in
the same CORS mode as the 3D texture load so the two shared one browser cache
entry instead of downloading the image twice. Consumers that hand Pascal
same-origin blob URLs never hit the split in the first place, and the flag is
actively wrong for guide images served without CORS headers.
- Near-collinear wall junctions no longer explode.
@meterup/pascal-capture-protocol@1.0.0-beta.5
Minor Changes
-
2f5c4e1: Rebase the fork onto upstream
pascalorg/editor@4c34032c(2026-08-24) — 478
commits, and a move off the fork's own0.9.xline onto upstream's1.0.0-beta
versioning. The fork now carries nothing but its release machinery and two
editor patches; everything else is upstream.Nothing we previously exported was removed. The public API grew substantially
(core 172 → 388 exports, viewer 106 → 193, editor 156 → 470) without breaking
underneath consumers.What matters most for consumers:
- Near-collinear wall junctions no longer explode.
calculateJunctionIntersectionsnow rejects a miter on its outcome, capped
atMITER_LIMIT(10) half-thicknesses, rather than only rejecting walls that
are exactly parallel. A junction where two walls run straight through each
other but miss collinearity by a fraction of a degree used to put a plan
vertexhalfThickness / sin(θ)away — kilometres out, collapsing the 2D
fit-to-bounds into one flat rectangle and firing beams across the 3D scene. It
now butts. Imported floor plans with off-axis wall runs render correctly. - Level assembly is dramatically faster.
findJunctionsbuckets walls into
a spatial grid by AABB instead of testing every wall against every junction
point. On a 1081-wall imported floor that is 584 ms → 11 ms per call, and
WallSystemrepeats the call every frame while progressively rebuilding. - Vertical building model. Scenes now carry explicit building and level
structure (buildingId,schema/nodes/building.ts), with load-time
migrations for saves that predate it — vertical, site-child, wall-slot,
elevator, retired-floorplan and construction-dimension. Anything synthesizing
aSceneGraphrather than loading a saved one needs to match the new shape;
this is the single change most likely to require work on the consumer side. - New packages:
capture-protocol,capture-viewer,cli. New core
systems alongsidewall/andstair/:fence/,slab/,elevator/. healSceneNodesrepairs already-saved scenes on load, dropping
degenerate nodes such as zero-length walls.
Three fork patches are dropped here because upstream made them redundant:
- The
floorplan-registry-layergeometry cache. Upstream landed its own
geometryCacheRef/levelDataCacheRefmemoisation plus thefindJunctions
prefilter above, which together address the same stall from further up. - The
ThreeElements/lineBasicNodeMaterialnarrowing inviewerthat let
tsgocheck the package. Upstream adopted the TypeScript 7 native compiler
and landed the identical narrowing. crossOriginon the 2D guide image. It forced the 2D<image>to fetch in
the same CORS mode as the 3D texture load so the two shared one browser cache
entry instead of downloading the image twice. Consumers that hand Pascal
same-origin blob URLs never hit the split in the first place, and the flag is
actively wrong for guide images served without CORS headers.
- Near-collinear wall junctions no longer explode.
@meterup/pascal-viewer@0.9.1
Published to GitHub Packages.