Projects, archives and twins
When you load something with the core API you are working with a source for model data. There are two kinds of sources, and it helps to know which one you're dealing with: a project/archive or a twin. They look similar when you list them, but they play different roles — and twins are built from archives.
The two types of model sources
| Project / Archive | Twin |
|---|---|---|
What it is | A container holding the raw files you have uploaded (IFC, DWG, PDF, …). | A model assembled according to a specification from files imported from one or more archives. |
What it contains | Source files and their version history. | A ready-to-render model plus twin-level metadata (name, property sets, quantities). |
Versioning | Each file is versioned on its own. | The twin itself is versioned. Every twin version pins an exact version of each file it uses. |
Linked to | — | One or more archives, listed in the twin's |
How you load it |
|
|
How they relate
A twin copies files that are imported from archives named in its relatedContainerIds and pins an exact
version of each one. That makes a twin a stable snapshot: it keeps rendering the same thing even
after new files are uploaded to the archive, until a new twin version is published.
So the rule of thumb is:
Reach for a project/archive when you want to work directly with the files you uploaded — pick which IFCs to load, filter them, and so on.
Reach for a twin when you want the curated, versioned model that has been built from those files, without caring which individual files went into it. This lets you keep stable references to objects in the model and work with the most reliable representation of the current state of the building.
Working with projects and archives
This is the everyday case covered in Containers and loading your digital twin: list your containers, pick the one you want, fetch its IFC files and add them to the scene.
async function loadArchive(): Promise<void> {
const api = await getApi();
// Containers are your projects and archives.
const containers = await api.backend.getContainers();
const archive = containers.find(
(c) => c.name.toLowerCase() === 'hellotwinfinityworld'
);
// Set the container, but skip auto-loading geometry so we stay in control
// of exactly what gets loaded.
await api.setContainer(archive!, 'skip-ifc-load');
// Fetch the IFC files in the archive and add the ones you are interested in.
const files = await api.backend.getIfcChanges(archive!);
await api.ifc.add(files);
api.viewer.addOrUpdateEnvironment({ boundingInfo: api.ifc.regionBoundingInfo });
api.viewer.camera.zoomToExtent(api.ifc.regionBoundingInfo, 'top');
}getIfcChanges() returns the IFC files; if you need other file types (DWG, PDF, blobs, …) use the more
general api.backend.getChanges(container, query) with a PredefinedBimChangeMetadataQuery.
Working with twins
Twins are reached through the same api client, under api.backend.twins. List the twins that belong to
an archive by passing that archive's container id, then load the one you want straight into the scene. A
TwinInput is just another input to api.ifc.add — exactly like an IFC file.
import { TwinInput } from '@twinfinity/core';
async function loadTwin(): Promise<void> {
const api = await getApi();
// List the twins related to this archive (pass its container id).
const twins = await api.backend.twins.listAllTwins();
const twin = twins.find((t) => t.name === 'My building');
// Need more detail? getTwin returns the full metadata for a twin:
// its version, related archives and property sets.
// const details = await api.backend.twins.getTwin(twin!.id);
// Load the latest version of the twin into the scene.
await api.ifc.add(TwinInput.create(twin!));
// ...or load a specific, pinned version instead:
// await api.ifc.add(new TwinInput(twin!.id, twin!.version));
api.viewer.addOrUpdateEnvironment({ boundingInfo: api.ifc.regionBoundingInfo });
api.viewer.camera.zoomToExtent(api.ifc.regionBoundingInfo, 'top');
}A few useful calls on api.backend.twins:
listTwins(relatedContainerId?, page?, limit?)— a single page of twins, optionally filtered to one archive.listAllTwins(relatedContainerId?)— the same, but auto-paginated into one array.getTwin(twinId)orgetTwin({ id, version })— full metadata for a twin (or a specific version of it).
Loading vs. inspecting.
TwinInput+api.ifc.addrenders the twin's geometry in the viewer. If you only need its data — property sets, quantities, related archives —getTwingives you that without loading any geometry.
Note: Only a twin that has finished processing into a renderable model can be loaded. If you pass a
twin that has no model yet, api.ifc.add will reject. Use the metadata from getTwin / listTwins to
decide what to offer in your UI.
In short
Both projects/archives and twins are model sources you load through the core API.
An archive holds your raw files; a twin is a versioned model built from a pinned set of those files and linked back to its archive(s) via
relatedContainerIds.Load an archive with
getIfcChanges()→api.ifc.add(files); load a twin withTwinInput→api.ifc.add(twinInput).Browse and inspect twins through
api.backend.twins.