Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions apps/editor/lib/css-build.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { expect, test } from 'bun:test'
import { readFile } from 'node:fs/promises'
import tailwindcss from '@tailwindcss/postcss'
import postcss from 'postcss'

const stylesheet = new URL('../app/globals.css', import.meta.url)

test('the editor stylesheet emits shared layout, theme and reduced-motion styles', async () => {
const result = await postcss([tailwindcss()]).process(await readFile(stylesheet, 'utf8'), {
from: stylesheet.pathname,
})

expect(result.warnings()).toEqual([])
expect(result.css).not.toContain('@apply')
expect(result.css).toContain('.flex')
expect(result.css).toContain('var(--background)')
expect(result.css).toContain('prefers-reduced-motion')
})

test('zero spacing remains a length in calc and shadows support fractional opacity', async () => {
const result = await postcss([tailwindcss({ optimize: false })]).process(
'@import "tailwindcss"; @source inline("w-[calc(--spacing(0)+1px)] shadow-sm/12.5");',
{ from: stylesheet.pathname },
)
const values: string[] = []
result.root.walkDecls((declaration) => {
values.push(declaration.value)
})

expect(values).toContain('calc(0px + 1px)')
expect(values.some((value) => value.includes('12.5%'))).toBe(true)
})
24 changes: 12 additions & 12 deletions apps/editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,22 @@
"@pascal-app/plugin-trees": "github:pascalorg/plugin-trees#56d978cd9b409b716207b3f3d269455d3cd6f067",
"@pascal-app/viewer": "*",
"@radix-ui/react-tooltip": "^1.4.1",
"@react-three/drei": "^10.7.7",
"@react-three/fiber": "^9.8.1",
"@react-three/xr": "^6.6.30",
"@tailwindcss/postcss": "^4.2.1",
"@react-three/drei": "^10.7.9",
"@react-three/fiber": "^9.8.2",
"@react-three/xr": "^6.6.32",
"@tailwindcss/postcss": "^4.3.3",
"@webxr/plugin": "github:sudhir9297/webxr-pascal-plugin#9cd90457fc823d5d633d38e9575856c854aeb4d4",
"clsx": "^2.1.1",
"geist": "^1.7.2",
"lucide-react": "^1.57.0",
"next": "16.4.0",
"postcss": "^8.5.6",
"react": "19.3.0",
"geist": "^1.8.1",
"lucide-react": "^1.58.0",
"next": "16.4.2",
"postcss": "^8.5.30",
"react": "19.3.1",
"react-colorful": "^5.8.1",
"react-dom": "19.3.0",
"react-dom": "19.3.1",
"tailwind-merge": "^3.7.0",
"tailwindcss": "^4.2.1",
"three": "^0.186.0",
"tailwindcss": "^4.3.3",
"three": "^0.186.1",
"zod": ">=4.6.7 <4.7"
},
"devDependencies": {
Expand Down
20 changes: 10 additions & 10 deletions apps/ifc-converter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,18 @@
"@pascal-app/ifc-converter": "*",
"@pascal-app/nodes": "*",
"@pascal-app/viewer": "*",
"lucide-react": "^1.57.0",
"@react-three/drei": "^10.7.7",
"@react-three/fiber": "^9.8.1",
"@tailwindcss/postcss": "^4.2.1",
"lucide-react": "^1.58.0",
"@react-three/drei": "^10.7.9",
"@react-three/fiber": "^9.8.2",
"@tailwindcss/postcss": "^4.3.3",
"clsx": "^2.1.1",
"next": "16.4.0",
"postcss": "^8.5.6",
"react": "19.3.0",
"react-dom": "19.3.0",
"next": "16.4.2",
"postcss": "^8.5.30",
"react": "19.3.1",
"react-dom": "19.3.1",
"tailwind-merge": "^3.7.0",
"tailwindcss": "^4.2.1",
"three": "^0.186.0",
"tailwindcss": "^4.3.3",
"three": "^0.186.1",
"web-ifc": "^0.0.78"
},
"devDependencies": {
Expand Down
217 changes: 116 additions & 101 deletions bun.lock

Large diffs are not rendered by default.

21 changes: 11 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,18 @@
"@types/react": "19.3.0",
"@types/react-dom": "19.3.0",
"@types/three": "0.186.0",
"next": "16.4.0",
"next": "16.4.2",
"react-grab": "0.2.0",
"three": "0.186.0",
"react": "19.3.0",
"react-dom": "19.3.0",
"@react-three/fiber": "9.8.1"
"three": "0.186.1",
"react": "19.3.1",
"react-dom": "19.3.1",
"@react-three/fiber": "9.8.2"
},
"optionalDependencies": {
"@tailwindcss/oxide-darwin-arm64": "4.3.0",
"@tailwindcss/oxide-darwin-x64": "4.3.0",
"@tailwindcss/oxide-linux-arm64-gnu": "4.3.0",
"@tailwindcss/oxide-linux-x64-gnu": "4.3.0",
"@tailwindcss/oxide-darwin-arm64": "4.3.3",
"@tailwindcss/oxide-darwin-x64": "4.3.3",
"@tailwindcss/oxide-linux-arm64-gnu": "4.3.3",
"@tailwindcss/oxide-linux-x64-gnu": "4.3.3",
"lightningcss-darwin-arm64": "1.32.0",
"lightningcss-darwin-x64": "1.32.0",
"lightningcss-linux-arm64-gnu": "1.32.0",
Expand All @@ -67,6 +67,7 @@
],
"patchedDependencies": {
"iwer@2.3.0": "patches/iwer@2.3.0.patch",
"three@0.186.0": "patches/three@0.186.0.patch"
"three@0.186.1": "patches/three@0.186.1.patch",
"three-bvh-csg@0.0.18": "patches/three-bvh-csg@0.0.18.patch"
}
}
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"typescript": "7.0.2"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.30.0"
"@modelcontextprotocol/sdk": "^1.32.1"
},
"engines": {
"node": ">=22.13.0"
Expand Down
4 changes: 2 additions & 2 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@
"three": "^0.186"
},
"dependencies": {
"@pascal-app/lingo": "^0.2.0",
"@pascal-app/lingo": "^0.5.0",
"dedent": "^1.7.2",
"idb-keyval": "^6.3.0",
"mitt": "^3.0.1",
Expand All @@ -154,7 +154,7 @@
"@types/react": "19.3.0",
"@types/three": "^0.186.0",
"@typescript/typescript6": "6.0.2",
"fake-indexeddb": "^6.2.5",
"fake-indexeddb": "^6.2.6",
"typescript": "7.0.2"
},
"keywords": [
Expand Down
8 changes: 4 additions & 4 deletions packages/editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"@number-flow/react": "^0.6.2",
"@pascal-app/geometry-script": "^1.0.4",
"@pascal-app/ifc-converter": "^1.0.4",
"@pascal-app/lingo": "^0.2.0",
"@pascal-app/lingo": "^0.5.0",
"@radix-ui/react-alert-dialog": "^1.2.1",
"@radix-ui/react-context-menu": "^2.4.1",
"@radix-ui/react-dialog": "^1.3.1",
Expand All @@ -53,15 +53,15 @@
"cmdk": "^1.1.1",
"fflate": "^0.8.3",
"howler": "^2.2.4",
"lucide-react": "^1.57.0",
"lucide-react": "^1.58.0",
"manifold-3d": "3.5.4",
"mitt": "^3.0.1",
"motion": "^14.2.0",
"motion": "^14.3.0",
"nanoid": "^6.0.2",
"pdfkit": "^0.20.2",
"tailwind-merge": "^3.7.0",
"three-bvh-csg": "^0.0.18",
"three-mesh-bvh": "~0.9.8",
"three-mesh-bvh": "~0.9.16",
"zod": ">=4.6.7 <4.7",
"zustand": "^5.0.15"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,7 @@ function createElevatorColliderMesh(
;(bvhGeometry as any).computeBoundsTree = computeBoundsTree
;(bvhGeometry as any).disposeBoundsTree = disposeBoundsTree
bvhGeometry.computeBoundsTree?.({
maxLeafSize: 12,
targetLeafSize: 12,
strategy: 0,
} as never)
bvhGeometry.computeBoundingBox()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ export function buildFirstPersonColliderWorldFromRegistry(): FirstPersonCollider
;(bvhGeometry as any).computeBoundsTree = computeBoundsTree
;(bvhGeometry as any).disposeBoundsTree = disposeBoundsTree
bvhGeometry.computeBoundsTree?.({
maxLeafSize: 12,
targetLeafSize: 12,
strategy: 0,
} as never)
bvhGeometry.computeBoundingBox()
Expand Down
23 changes: 23 additions & 0 deletions packages/editor/src/lib/measurements.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { describe, expect, test } from 'bun:test'
import { measurementHint, parseMeasurement } from '../index'
import {
buildMeasurementAngleArcPoints,
cubicMetersToVolumeUnit,
Expand Down Expand Up @@ -190,3 +191,25 @@ describe('volume measurements', () => {
expect(formatVolumeLabel(Number.NEGATIVE_INFINITY, 'metric')).toBe('--')
})
})

describe('typed measurement fields', () => {
test('canonicalizes explicit, compound, and scientific dimensions', () => {
const length = { kind: 'length', unitId: 'm' } as const
expect(parseMeasurement('180cm', length)).toBeCloseTo(1.8)
expect(parseMeasurement('1m80', length)).toBeCloseTo(1.8)
expect(parseMeasurement(`5'11"`, length)).toBeCloseTo(1.8034)
expect(parseMeasurement('1.234e-4 m', length)).toBeCloseTo(0.0001234, 10)
expect(parseMeasurement('6', length, { bareUnit: 'ft' })).toBeCloseTo(1.8288)
expect(parseMeasurement('180deg', { kind: 'angle', unitId: 'rad' })).toBeCloseTo(Math.PI)
})

test('rejects ranges, incomplete arithmetic, and nonfinite input', () => {
const length = { kind: 'length', unitId: 'm' } as const
for (const input of ['2+3 m', '2-3 m', 'between 2 and 3 m', '1e999 m']) {
expect(parseMeasurement(input, length)).toBeNull()
expect(measurementHint(input, length)).toBeNull()
}
expect(measurementHint('180cm', length)).toBe('= 1.80 m')
expect(measurementHint('6', length)).toBeNull()
})
})
2 changes: 1 addition & 1 deletion packages/eslint-config/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
},
"devDependencies": {
"@eslint/js": "^10.0.1",
"@next/eslint-plugin-next": "16.4.0",
"@next/eslint-plugin-next": "16.4.2",
"eslint": "^10.12.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-only-warn": "^1.2.1",
Expand Down
4 changes: 2 additions & 2 deletions packages/mcp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@
"@pascal-app/core": "^1.0.4"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.30.0",
"@modelcontextprotocol/sdk": "^1.32.1",
"@pascal-app/geometry-script": "^1.0.4",
"@pascal-app/lingo": "^0.2.0",
"@pascal-app/lingo": "^0.5.0",
"zod": ">=4.6.7 <4.7"
},
"devDependencies": {
Expand Down
8 changes: 8 additions & 0 deletions packages/mcp/src/tools/measurement.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ describe('measurement()', () => {
expect(r.success).toBe(false)
})

test('accepts scientific dimensions without choosing one endpoint of a range', () => {
const field = measurement('length', 'm')
expect(field.parse('1.234e-4 m')).toBeCloseTo(0.0001234, 10)
for (const input of ['2+3 m', '2-3 m', 'between 2 and 3 m']) {
expect(field.safeParse(input).success).toBe(false)
}
})

test('emits a number|string JSON schema advertising natural language', () => {
const schema = z.toJSONSchema(
measurement('length', 'm', { min: 0, description: 'Wall thickness.' }),
Expand Down
4 changes: 2 additions & 2 deletions packages/nodes/src/chimney/roof-trim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ export function trimChimneyBodyAgainstRoof(
indexed.clearGroups()
if (indexCount > 0) indexed.addGroup(0, indexCount, 0)
;(
indexed as unknown as { computeBoundsTree?: (opts: { maxLeafSize: number }) => void }
).computeBoundsTree?.({ maxLeafSize: 10 })
indexed as unknown as { computeBoundsTree?: (opts: { targetLeafSize: number }) => void }
).computeBoundsTree?.({ targetLeafSize: 10 })

const chimneyBrush = new Brush(indexed, visibleMat as unknown as THREE.MeshStandardMaterial)
chimneyBrush.updateMatrixWorld()
Expand Down
4 changes: 2 additions & 2 deletions packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"typescript": "7.0.2"
},
"dependencies": {
"react": "19.3.0",
"react-dom": "19.3.0"
"react": "19.3.1",
"react-dom": "19.3.1"
}
}
2 changes: 1 addition & 1 deletion packages/viewer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
},
"dependencies": {
"three-bvh-csg": "^0.0.18",
"three-mesh-bvh": "^0.9.8",
"three-mesh-bvh": "~0.9.16",
"zustand": "^5"
},
"devDependencies": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ function buildGlbColliderWorld(scene: Object3D): GlbColliderWorld | null {
}
;(merged as any).computeBoundsTree = computeBoundsTree
;(merged as any).disposeBoundsTree = disposeBoundsTree
;(merged as any).computeBoundsTree({ maxLeafSize: 12, strategy: 0 })
;(merged as any).computeBoundsTree({ targetLeafSize: 12, strategy: 0 })
merged.computeBoundingBox()

const mesh = new Mesh(merged, colliderMaterial)
Expand Down
2 changes: 1 addition & 1 deletion packages/viewer/src/components/viewer/scene-bvh.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export const SceneBvh = forwardRef<Group, SceneBvhProps>(
verbose,
setBoundingBox,
maxDepth,
maxLeafSize,
targetLeafSize: maxLeafSize,
indirect,
}
const group = ref.current
Expand Down
16 changes: 15 additions & 1 deletion packages/viewer/src/lib/csg-utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// depend on @types/bun so the import type is unresolved at compile time.
import { describe, expect, test } from 'bun:test'
import * as THREE from 'three'
import { ensureRenderableGeometryAttributes } from './csg-utils'
import { computeGeometryBoundsTree, ensureRenderableGeometryAttributes } from '../index'

describe('ensureRenderableGeometryAttributes', () => {
test('fills missing render attributes to match position count', () => {
Expand Down Expand Up @@ -71,3 +71,17 @@ describe('ensureRenderableGeometryAttributes', () => {
expect(geometry.getAttribute('uv2')?.count).toBe(3)
})
})

describe('computeGeometryBoundsTree', () => {
test('builds a queryable tree for prepared geometry', () => {
const geometry = new THREE.BoxGeometry(2, 2, 2)
computeGeometryBoundsTree(geometry)
const hit = geometry.boundsTree!.raycastFirst(
new THREE.Ray(new THREE.Vector3(0, 0, 3), new THREE.Vector3(0, 0, -1)),
THREE.FrontSide,
)
expect(hit?.distance).toBeCloseTo(2)
expect(hit?.point.z).toBeCloseTo(1)
geometry.dispose()
})
})
4 changes: 2 additions & 2 deletions packages/viewer/src/lib/csg-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ export function computeGeometryBoundsTree(geometry: THREE.BufferGeometry) {
;(geometry as unknown as { computeBoundsTree: typeof computeBoundsTree }).computeBoundsTree =
computeBoundsTree
;(
geometry as unknown as { computeBoundsTree: (opts: { maxLeafSize: number }) => void }
).computeBoundsTree({ maxLeafSize: 10 })
geometry as unknown as { computeBoundsTree: (opts: { targetLeafSize: number }) => void }
).computeBoundsTree({ targetLeafSize: 10 })
}

export function prepareBrushForCSG(brush: Brush) {
Expand Down
11 changes: 11 additions & 0 deletions packages/viewer/src/lib/dispose-object3d.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
import { describe, expect, test } from 'bun:test'
import { BoxGeometry, Group, Mesh, MeshBasicMaterial } from 'three'
import { MeshBasicNodeMaterial } from 'three/webgpu'
import { disposeObject3DResources } from './dispose-object3d'

describe('disposeObject3DResources', () => {
test('disposes a distributed WebGPU node material through the resource lifecycle', () => {
const material = new MeshBasicNodeMaterial()
let disposals = 0
material.addEventListener('dispose', () => disposals++)

disposeObject3DResources(new Mesh(new BoxGeometry(), material))

expect(disposals).toBe(1)
})

test('disposes nested geometry and materials once', () => {
const root = new Group()
const nested = new Group()
Expand Down
4 changes: 2 additions & 2 deletions packages/viewer/src/lib/pointer-events.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ function perfWindow(search = '?perf') {
return probeWindow
}

describe('R3F 9.8.1 pointer-event differential', () => {
describe('R3F 9.8.2 pointer-event differential', () => {
test('handle-like two-arg raycasts cache when tagged and report fallback when untagged', async () => {
const probeWindow = perfWindow()
const { stock, cached } = await differential((f) => {
Expand Down Expand Up @@ -558,7 +558,7 @@ describe('R3F 9.8.1 pointer-event differential', () => {

test('pins the vendored closure to the installed R3F version', () => {
const pkg = JSON.parse(readFileSync(require.resolve('@react-three/fiber/package.json'), 'utf8'))
expect(pkg.version, 'R3F version drift: re-vendor pointer-events.ts').toBe('9.8.1')
expect(pkg.version, 'R3F version drift: re-vendor pointer-events.ts').toBe('9.8.2')
})

test('nested handlers preserve the complete ordered hit metadata and callback/hover order', async () => {
Expand Down
Loading
Loading