feat: establish reproducible FreeCAD web compatibility baseline
This commit is contained in:
59
public/chrome-topology-harness.html
Normal file
59
public/chrome-topology-harness.html
Normal file
@@ -0,0 +1,59 @@
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>Chrome Topology Harness</title>
|
||||
<pre id="result">running</pre>
|
||||
<script type="module">
|
||||
import { BitbybitGeometryRuntime } from '/src/facade/geometryRuntime.ts'
|
||||
|
||||
const output = document.querySelector('#result')
|
||||
const report = { schemaVersion: 1, browserId: 'chrome', crossOriginIsolated: globalThis.crossOriginIsolated === true, status: 'running' }
|
||||
const persistTopologyInOpfs = async (topology) => {
|
||||
if (!navigator.storage?.getDirectory) return false
|
||||
const root = await navigator.storage.getDirectory()
|
||||
const directory = await root.getDirectoryHandle('bitbybit-topology-harness', { create: true })
|
||||
const name = `topology-${crypto.randomUUID()}.json`
|
||||
const payload = JSON.stringify({ adjacency: topology.adjacency, ids: topology.entries.map((entry) => entry.ref.persistentId) })
|
||||
try {
|
||||
const handle = await directory.getFileHandle(name, { create: true })
|
||||
const writable = await handle.createWritable()
|
||||
await writable.write(payload)
|
||||
await writable.close()
|
||||
const restored = JSON.parse(await (await handle.getFile()).text())
|
||||
return JSON.stringify(restored) === JSON.stringify(JSON.parse(payload))
|
||||
} finally {
|
||||
await directory.removeEntry(name).catch(() => {})
|
||||
}
|
||||
}
|
||||
try {
|
||||
const runtime = new BitbybitGeometryRuntime()
|
||||
report.capabilities = await runtime.initialize()
|
||||
const shape = await runtime.createBox({ documentId: 'chrome-topology', documentVersion: 1, width: 10, length: 20, height: 30, originOnCenter: false })
|
||||
try {
|
||||
const topology = await runtime.topology(shape, 0.05)
|
||||
const analyticFaces = topology.entries.filter((entry) => entry.ref.kind === 'face' && entry.signature.analytic?.type === 'Plane').length
|
||||
const analyticEdges = topology.entries.filter((entry) => entry.ref.kind === 'edge' && entry.signature.analytic?.type === 'Line').length
|
||||
const adjacency = topology.adjacency
|
||||
const opfsTopologyRoundTrip = await persistTopologyInOpfs(topology)
|
||||
report.topology = {
|
||||
faces: topology.faces.length,
|
||||
edges: topology.edges.length,
|
||||
vertices: topology.vertices.length,
|
||||
analyticFaces,
|
||||
analyticEdges,
|
||||
adjacencyKeys: adjacency ? Object.values(adjacency).map((map) => Object.keys(map).length) : [],
|
||||
transientIndexFree: topology.entries.every((entry) => !/index|faceIndex|edgeIndex|vertexIndex/i.test(entry.ref.persistentId)),
|
||||
opfsTopologyRoundTrip,
|
||||
}
|
||||
report.status = report.crossOriginIsolated && report.capabilities.status === 'ready' && topology.faces.length === 6 && topology.edges.length === 12 && topology.vertices.length === 8 && analyticFaces === 6 && analyticEdges === 12 && adjacency && Object.values(adjacency).every((map) => Object.keys(map).length > 0) && report.topology.transientIndexFree && opfsTopologyRoundTrip ? 'pass' : 'failed'
|
||||
} finally {
|
||||
await runtime.release(shape)
|
||||
runtime.dispose()
|
||||
}
|
||||
} catch (error) {
|
||||
report.status = 'failed'
|
||||
report.error = error instanceof Error ? error.message : String(error)
|
||||
}
|
||||
output.textContent = JSON.stringify(report)
|
||||
await fetch('/__topology-report', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(report) })
|
||||
if (report.status !== 'pass') throw new Error(report.error || 'Chrome topology harness failed.')
|
||||
</script>
|
||||
Reference in New Issue
Block a user