@aectooling/slopifc-wasm
v0.1.0-rc.0
Published
WebAssembly bindings for slopifc: IFC parsing, metadata and render data for browsers and Node
Downloads
89
Readme
@slopifc/wasm
WebAssembly bindings for slopifc: IFC parsing, typed metadata and Three.js-shaped render data, for browsers and Node.
The package is the only supported browser-facing interface to slopifc. Applications never instantiate the module, manage linear memory, free strings or call raw exports.
Status: runtime, conversion, metadata, render data and Three.js adapter.
createSlopIfc(), isolated model instances, typed lazy entities, projected metadata, file conversion, retained zero-copy render tables, Three.js wrappers and deterministic disposal are implemented. Nothing is published to npm yet.
The current generated runtime accepts IFC2X3 (IFC2X3, IFC2X3TC1) and IFC4
(IFC4, IFC4ADD2, IFC4ADD2TC1). Other schema releases, including IFC4X3,
are rejected at open time until their generated metadata tables are added.
Contract
The normative contract — integer widths, ownership, prepare() defaults, the
model state machine, the close/detachment sequence, status codes and every
byte-exact descriptor layout — is
docs/spec-wasm-package-abi.md. The
roadmap it belongs to is pack-wasm-plan.md.
Current usage
Convert an IFC source into JavaScript-owned Blobs suitable for download. OBJ
returns its referenced MTL file explicitly as sidecar.
const converted = await runtime.convert(file, {
format: 'obj',
geometry: { scopes: ['building'], subtractOpenings: true },
})
function save(output: { name: string; blob: Blob }) {
const url = URL.createObjectURL(output.blob)
const link = document.createElement('a')
link.href = url
link.download = output.name
link.click()
setTimeout(() => URL.revokeObjectURL(url), 0)
}
save(converted.output)
if (converted.sidecar) save(converted.sidecar)An open model can be converted repeatedly before preparation:
import { createSlopIfc } from '@slopifc/wasm'
const runtime = await createSlopIfc()
const model = await runtime.open(file)
const json = await model.convert({ format: 'json' })
const prepared = await model.prepare({
render: { coordinateToOrigin: true, subtractOpenings: true },
metadata: {
entityTypes: ['IFCPRODUCT'],
includeSubtypes: true,
attributes: ['GlobalId', 'Name', 'OwnerHistory'],
},
})
const names = prepared.getMetadata()?.column('Name')
const render = prepared.renderData
const wall = model.getEntities().byGuid('2Ab$4Ad$L9QuMOSyGoOAgE')
console.log(names?.kind === 'utf8' ? names.get(0) : undefined)
console.log(render?.geometries.count, render?.instances.count)
console.log(wall?.getExpressID(), wall?.getTypeName())
prepared.dispose()Compile-checked versions of both flows live in examples/.
Layout
| Path | Contents |
| --- | --- |
| src/index.ts | public API barrel |
| src/index-internal.ts | internal barrel for tests; not in exports |
| src/raw-api.ts | private ABI adapter: descriptor layouts, status codes |
| src/memory-views.ts | bounds/alignment-checked views over sealed memory |
| src/prepare-options.ts | prepare() option types and defaults |
| src/conversion.ts | conversion option validation, output names and public result types |
| src/decode-value.ts | WASM lazy-value → typed IfcValue |
| src/entities.ts, src/model.ts, src/runtime.ts | public runtime surface |
| src/render-data.ts, src/metadata-table.ts | descriptor → public tables |
| src/three/ | optional adapter, published as @slopifc/wasm/three |
| tests/fixtures/ | hand-built descriptor fixtures (no WASM required) |
The core never imports three; it is an optional peer dependency of the
/three subpath only.
Development
bun install
bun run typecheck
bun run test
bun run build # zig build wasm, then tsc + dist/slopifc.wasm
bun run check:pack # pack a throwaway tarball and verify its contents
bun run check # all of the abovezig build wasm stays a Zig-only step writing to zig-out/wasm/slopifc.wasm;
copying it into dist/ is the package build's job. Set
SLOPIFC_SKIP_ZIG_BUILD=1 to reuse an artifact a previous step already built.
