72 lines
5.4 KiB
TypeScript
72 lines
5.4 KiB
TypeScript
import { BitbybitGeometryRuntime } from './facade/geometryRuntime'
|
|
import type { ShapeHandle } from './facade/types'
|
|
|
|
type PrimitiveEvidence = { name: string; meshVertices: number; meshTriangles: number; volume?: number; length?: number }
|
|
type PrimitiveReport = { schemaVersion: 1; status: 'pass' | 'failed'; browserId: 'chrome'; operations: PrimitiveEvidence[]; beforeRelease: { shapeCount: number; kernelReferenceCount: number }; afterRelease: { shapeCount: number; kernelReferenceCount: number }; opfs?: { markerSuite: string; markerOperations: number; markerRemoved: boolean }; error?: string }
|
|
|
|
const status = (message: string) => { document.querySelector('#status')!.textContent = message }
|
|
|
|
const run = async (): Promise<PrimitiveReport> => {
|
|
const runtime = new BitbybitGeometryRuntime()
|
|
const context = { documentId: 'chrome-part-primitives', documentVersion: 1 }
|
|
const owned: ShapeHandle[] = []
|
|
const operations: PrimitiveEvidence[] = []
|
|
try {
|
|
const capabilities = await runtime.initialize()
|
|
if (capabilities.status !== 'ready') throw new Error(capabilities.reason || `Bitbybit runtime status is ${capabilities.status}.`)
|
|
const capture = async (name: string, shape: ShapeHandle, includeMass = true, requireMesh = true) => {
|
|
if (!requireMesh) {
|
|
const length = await runtime.linearLength(shape)
|
|
if (!(length > 0)) throw new Error(`${name} returned a zero-length wire.`)
|
|
operations.push({ name, meshVertices: 0, meshTriangles: 0, length })
|
|
return
|
|
}
|
|
let mesh
|
|
try { mesh = await runtime.mesh(shape) } catch (error) { throw new Error(`${name}: ${error instanceof Error ? error.message : String(error)}`) }
|
|
if (mesh.positions.length < 9 || mesh.indices.length < 3) throw new Error(`${name} returned an empty mesh.`)
|
|
const mass = includeMass ? await runtime.massProperties(shape) : undefined
|
|
operations.push({ name, meshVertices: mesh.positions.length / 3, meshTriangles: mesh.indices.length / 3, ...(mass ? { volume: mass.volume } : {}) })
|
|
}
|
|
const ellipsoid = await runtime.createEllipsoid({ ...context, radius1: 2, radius2: 3, radius3: 4 })
|
|
owned.push(ellipsoid); await capture('ellipsoid', ellipsoid)
|
|
const torus = await runtime.createTorus({ ...context, majorRadius: 5, minorRadius: 1, angle: 360 })
|
|
owned.push(torus); await capture('torus', torus)
|
|
const prism = await runtime.createPrism({ ...context, polygon: 6, circumradius: 2, height: 4 })
|
|
owned.push(prism); await capture('prism', prism)
|
|
const wedge = await runtime.createWedge({ ...context, xmin: 0, ymin: 0, zmin: 0, z2min: 0, x2min: 0, xmax: 4, ymax: 5, zmax: 6, z2max: 6, x2max: 4 })
|
|
owned.push(wedge); await capture('wedge', wedge)
|
|
const helix = await runtime.createHelix({ ...context, radius: 2, pitch: 3, height: 6 })
|
|
owned.push(helix); await capture('helix', helix, false, false)
|
|
const markerDirectory = await navigator.storage.getDirectory()
|
|
const markerName = 'part-primitives-chrome-marker.json'
|
|
const marker = await markerDirectory.getFileHandle(markerName, { create: true })
|
|
const writable = await marker.createWritable()
|
|
await writable.write(JSON.stringify({ suite: 'PART-ALL', operations: operations.length }))
|
|
await writable.close()
|
|
const markerPayload = JSON.parse(await (await marker.getFile()).text())
|
|
await markerDirectory.removeEntry(markerName)
|
|
let markerRemoved = false
|
|
try { await markerDirectory.getFileHandle(markerName) } catch (error) { markerRemoved = error instanceof DOMException && error.name === 'NotFoundError' }
|
|
const beforeRelease = { shapeCount: runtime.capabilities().shapeCount, kernelReferenceCount: runtime.capabilities().kernelReferenceCount }
|
|
await Promise.all(owned.map((shape) => runtime.release(shape)))
|
|
const afterRelease = { shapeCount: runtime.capabilities().shapeCount, kernelReferenceCount: runtime.capabilities().kernelReferenceCount }
|
|
runtime.dispose()
|
|
if (afterRelease.shapeCount !== 0 || afterRelease.kernelReferenceCount !== 0) throw new Error(`Part primitive ownership gate failed: ${JSON.stringify(afterRelease)}`)
|
|
return { schemaVersion: 1, status: capabilities.status === 'ready' && operations.length === 5 && markerPayload.suite === 'PART-ALL' && markerPayload.operations === 5 && markerRemoved ? 'pass' : 'failed', browserId: 'chrome', operations, beforeRelease, afterRelease, opfs: { markerSuite: markerPayload.suite, markerOperations: markerPayload.operations, markerRemoved } }
|
|
} catch (error) {
|
|
const beforeRelease = { shapeCount: runtime.capabilities().shapeCount, kernelReferenceCount: runtime.capabilities().kernelReferenceCount }
|
|
await Promise.all(owned.map((shape) => runtime.release(shape).catch(() => {})))
|
|
const afterRelease = { shapeCount: runtime.capabilities().shapeCount, kernelReferenceCount: runtime.capabilities().kernelReferenceCount }
|
|
runtime.dispose()
|
|
return { schemaVersion: 1, status: 'failed', browserId: 'chrome', operations, beforeRelease, afterRelease, error: error instanceof Error ? error.message : String(error) }
|
|
}
|
|
}
|
|
|
|
run().then((report) => {
|
|
;(window as Window & { __bitbybitPartPrimitiveReport?: PrimitiveReport }).__bitbybitPartPrimitiveReport = report
|
|
document.documentElement.dataset.status = report.status
|
|
status(JSON.stringify(report))
|
|
}).catch((error) => { document.documentElement.dataset.status = 'failed'; status(error instanceof Error ? error.message : String(error)) })
|
|
|
|
export {}
|