IFC Viewer SDK v1.18.0 Viewer öffnen
Deutsch

IFC Viewer SDK · v1.18.0

Binde den IFC-Viewer in dein eigenes Produkt ein

Füge denselben Browser-Viewer in dein CDE, deinen digitalen Zwilling oder interne Projekt-Tools ein. Lade IFC-Daten direkt aus deiner App, während jedes Modell im Client geparst wird.

Drei Zeilen bis zum ersten Rendern

JavaScript
const viewer = new IfcViewer("#viewer");

await viewer.add("project.ifc", ifcBytes);
// → rendered, validated, all on the client

Einrichtung

Schnellstart

Wähle deinen Stack. Kopieren, einfügen, rendern — ohne Build-Schritt, ohne API-Key.

HTML
<div id="viewer" style="height:520px"></div>
<script type="module">
  import { IfcViewer } from "https://www.ifcvieweronline.eu/sdk/ifc-viewer.es.js";

  const viewer = new IfcViewer("#viewer");

  // Load IFC bytes from your app — nothing is uploaded
  const bytes = await fetch("/models/project.ifc").then(r => r.arrayBuffer());
  await viewer.add("project.ifc", bytes);
</script>

Gehostet oder selbst gehostet

Die Snippets importieren von unserem CDN, das auf jedem Origin funktioniert. Zum Selbsthosten lieferst du ifc-viewer.es.js von deiner eigenen Domain aus — das SDK ermittelt die App-URL relativ zum Skript. Läuft die App woanders? Setze die Option baseUrl.

Noch kein npm-Paket: Modul per URL importieren (oben) oder ifc-viewer.es.js in deine App übernehmen.

Beweis

Live-Demo

Diese Seite führt das SDK aus. Klicke einen Schalter, um ein Beispiel-IFC zu laden und den Viewer zu steuern — jeder Button zeigt den Aufruf, den er macht.

bereit
Letzter Aufruf —

Architektur

So funktioniert es

Ein winziger Wrapper in deiner Seite, der vollständige Viewer in einem isolierten iframe, deine Bytes dazwischen übertragen — und dort verarbeitet, wo sie ohnehin liegen.

Browser der Besucher — nichts wird hochgeladenDeine AppSDK · ~6 KBIsoliertes iframethree.js · web-ifc · WASMIFC-BytespostMessage

Deine App

Ein ES-Modul von ~6 KB, das ein iframe und eine typisierte JS-API erzeugt. Nichts vom schweren 3D- und Parsing-Gewicht landet in deinem Bundle.

postMessage-Brücke

IFC-Bytes werden als ArrayBuffer an das iframe übertragen (ohne Kopie). Befehle und Abfragen sind korrelierte Request/Response-Nachrichten.

Der Viewer

three.js + web-ifc, zu WebAssembly kompiliert, parsen und rendern das Modell im iframe — auf dem Rechner der Besucherin oder des Besuchers.

Warum es privat ist

Modelle erreichen nie einen Server. Keine Upload-Pipeline abzusichern, keine Frage der Datenresidenz, keine Warteschlange nach Dateigröße.

Warum es skaliert

Die Berechnung läuft auf dem Gerät der jeweiligen Besucher. Ein 200-MB-Modell auszuliefern kostet dasselbe wie ein 2-MB-Modell — es ist eine statische Datei.

Konzepte

Kernkonzepte

Vier Dinge, die man vor dem Bauen wissen sollte.

Mounten & Bereitschaft

new IfcViewer(target) mountet sofort und stellt Befehle in eine Warteschlange, bis der Viewer bereit ist. await IfcViewer.create(target) (oder whenReady()) liefert eine Instanz, die du direkt verwenden kannst.

JavaScript
// queues commands until ready
const viewer = new IfcViewer("#viewer");

// …or await an instance that is ready to use
const viewer = await IfcViewer.create("#viewer");

Bytes oder URL

add(name, bytes) überträgt Bytes, die du bereits hast — kein CORS, nichts hochgeladen; der Buffer wird transferiert (detached), gib also eine Kopie mit, wenn du ihn noch brauchst. addFromUrl(url) lädt stattdessen eine öffentliche URL mit CORS.

JavaScript
// you already have the bytes — no CORS, nothing uploaded
await viewer.add("a.ifc", bytes);

// …or load a public, CORS-enabled URL
await viewer.addFromUrl("https://host/b.ifc");

Events

Mit on(event, cb) abonnieren, das eine Funktion zum Abbestellen zurückgibt. Verfügbar sind ready, model-progress, model-loaded, validation-completed, model-error und element-selected.

JavaScript
const off = viewer.on("model-loaded", (m) => {
  console.log(m.fileName, m.elementCount);
});
// later: off();

Abfragen

Daten bei Bedarf abrufen: getModels, getElement, getValidation, getStats, getIssues, checkIds, checkEir, screenshot. Jede ist Request/Response und wird nach einem Timeout abgelehnt (30 s; IDS / EIR bis 120 s).

JavaScript
const models = await viewer.getModels();
const { qualityScore } = await viewer.getValidation();
const png = await viewer.screenshot();

Referenz

API-Referenz

Jede Methode, gruppiert — mit Signaturen und Rückgabetypen. Danach folgen Konstruktor-Optionen, Events und die Web Component <ifc-viewer>.

Konstruktor

new IfcViewer(target, options?)IfcViewer

In einen CSS-Selektor oder ein Element einhängen. Siehe die Optionen unten.

IfcViewer.create(target, options?)Promise<IfcViewer>

Erzeugt einen Viewer und löst auf, sobald er Befehle annehmen kann.

Modelle laden

add(name, bytes)Promise<ModelLoadedEvent>

IFC-Bytes (ArrayBuffer/Uint8Array) aus deiner App laden. Der Buffer wird für eine kopierfreie Übergabe transferiert.

addFromUrl(url, name?)Promise<ModelLoadedEvent>

Eine öffentliche, CORS-fähige IFC-URL laden.

removeModel(modelId)void

Entlädt ein Modell per id.

clear()void

Alle geladenen Modelle entfernen.

Kamera & Auswahl

select(expressId | globalId, modelId?)void

Ein Element auswählen und einpassen — per IFC-expressID oder per GlobalId (die auch sein Modell findet).

setView(view)void

Zu einer benannten Ansicht der Szene fliegen — iso, front, back, left, right, top, bottom — mit der ganzen Szene im Bild. Ohne Antwort (von 1.14 bis 1.17 ignorierte der Viewer sie).

frame({ view?, fill?, azimuth?, elevation?, animate? })Promise<{ scope }>

Bildausschnitt für die Präsentation: Das Modell füllt `fill` des Bildes (0,2–0,98, Standard 0,85), an seine Ecken angepasst statt an die Hüllkugel. azimuth / elevation wählen jeden Blickwinkel.

frame(elementId, modelId?, options?)Promise<{ scope: 'element' }>

Ein Element (expressID) einpassen: aus dem aktuellen Blickwinkel, sofern keine Ansicht angegeben ist. Lehnt ab, wenn es nicht im Modell ist.

fit() · reset()void

Aktives Modell aus dem aktuellen Blickwinkel mit Rand einpassen / Kamera zurücksetzen.

setCamera(position, direction)void

Positioniert die Kamera an einer Position mit Blickrichtung.

getCamera()Promise<CameraState | null>

Wo die Kamera steht und wohin sie blickt — speichern und mit lookAt wiederherstellen.

lookAt(position, target, animate?)Promise<void>

Kamera an eine Position fliegen, Blick auf ein Ziel (Szenenmeter, Y oben).

setWalkMode(enabled, { speed? })Promise<WalkState>

Begehungsmodus in der Ich-Perspektive (WASD, Ziehen zum Umsehen, Esc zum Verlassen). Löst walk-changed aus.

getWalkState()Promise<WalkState>

Ob der Begehungsmodus aktiv ist und mit welcher Geschwindigkeit.

Sichtbarkeit

isolate(ifcType?)void

Eine Kategorie isolieren (z. B. "IfcWall"); ohne Wert zum Zurücksetzen.

showAll()void

Volle Sichtbarkeit wiederherstellen (Ausgeblendetes + Isolation aufheben).

hideElements(ids, modelId?) · showElements(ids, modelId?)void

Blendet eine Menge von Elementen per expressID aus / ein.

setModelVisible(modelId, visible)Promise<void>

Ein Modell einer föderierten Szene ein- oder ausblenden, ohne es zu entladen.

setModelOpacity(opacity, modelId?)Promise<void>

Ein Modell transparent machen (0,05–1) — z. B. die Architektur um die TGA.

isolateModel(modelId | null)Promise<void>

Nur dieses Modell zeigen; null zeigt wieder alle.

Aussehen & Präsentation

setBackground(background)Promise<BackgroundState>

Szenenhintergrund ändern: ein Preset ('white', 'paper', 'blueprint', 'sky', 'studio'), '#rrggbb', '#oben,#unten' oder { top, bottom }. Wird nicht als Präferenz des Besuchers gespeichert.

getBackground()Promise<BackgroundState>

Der aktuelle Szenenhintergrund.

setAccent(color)Promise<void>

Akzentfarbe der Oberfläche zur Laufzeit ändern (#rrggbb).

setClientMode(enabled)Promise<void>

Kundenansicht ein- oder ausschalten — die Ansicht für Stakeholder, wie ui: 'client'.

setRenderQuality(quality)Promise<void>

'quality' schaltet das aufwendigere Rendering für ein Titelbild ein; 'standard' für den Alltag.

Sonnenstudie

setSolar(opts?)Promise<SolarState>

Echte Schatten zu einem ortsüblichen Datum und einer Uhrzeit: { date: '06-21', time: '18:00' }. Der Standort kommt aus der IFC-Georeferenz; für ein Modell ohne sie location übergeben — nie stillschweigend eine Standardstadt.

getSolar()Promise<SolarState>

Datum, Uhrzeit und Zeitzone der Studie und wo der Standort liegt.

Kartenmodus

setSiteContext(opts?)Promise<SiteContextState>

Modell mit Gelände und OpenStreetMap-Umgebung auf die Karte setzen. Der Aufruf erklärt die Kachel-Einwilligung Ihrer Seite für ihre Besucher; zeigen Sie die Quellenangaben.

getSiteContext()Promise<SiteContextState>

Zustand des Kartenmodus, Platzierung und die anzuzeigenden Quellenangaben.

Szenen

openScene(url | SceneDocument)Promise<void>

Eine andere Szene öffnen: die URL einer .scene.json oder ein Szenendokument (es reist gepackt in der Adresse des Frames und muss in einen Link passen). Der Viewer lädt damit neu; wartende Aufrufe werden abgelehnt, ready feuert erneut.

exportScene({ title?, description?, camera? })Promise<SceneExport>

Die Szene auf dem Bildschirm als Szenendokument – Modelle per URL, Ebenen, Zwilling, Karte, Kamera – mit den zu nennenden Quellen und einem Link, der sie trägt.

packScene(doc)Promise<string | null>

Ein Szenendokument selbst für einen #scene=-Link packen (null, wenn es für einen Link zu groß ist).

Datenebenen und Zwilling

getLayerPresets()Promise<LayerPreset[]>

Der Katalog öffentlicher Live-Quellen, in der Sprache des Viewers benannt, mit dem, was jede im Browser braucht (Schlüssel, Proxy), und ob sie Daten nahe dem Standort hat.

addLayer({ preset } | { url, live? } | { geojson })Promise<DataLayerInfo>

Eine Ebene hinzufügen: eine Katalogquelle ({ preset }), GeoJSON oder einen Live-Feed unter einer URL ({ url, live }) oder vorhandenes GeoJSON ({ geojson }). Nur für die Sitzung: nie in den Ebenen des Besuchers gespeichert.

getLayers()Promise<DataLayerInfo[]>

Alle Datenebenen: Status, Objektanzahl, Ausdehnung, Aktualisierung und Quellenangabe.

setLayerVisible(id, visible)Promise<DataLayerInfo>

Eine Ebene ein- oder ausblenden.

frameLayer(id)Promise<void>

Die Kamera zu den Objekten einer Ebene führen.

removeLayer(id)Promise<void>

Eine Ebene entfernen.

getTwin()Promise<TwinState>

Der Betriebszwilling jetzt: Gerätequellen (Status, letzte Messung) und je Bindung die greifende Regel, ihre Farbe, der Beschriftungswert und ob sie alarmiert.

Schnitte

addSection({ axis?, offset?, level?, flip? })Promise<SectionsState & { id }>

Schnittebene hinzufügen. { level: 'EG' } ist ein Grundriss auf diesem Geschoss; { axis: 'x', offset: 4.5 } ein Schnitt bei 4,5 m.

updateSection(id, { offset?, enabled?, flipped? })Promise<SectionsState>

Ebene verschieben, ein-/ausschalten oder umkehren.

removeSection(id?)Promise<SectionsState>

Eine Ebene entfernen, oder alle Schnitte ohne id.

setSectionBox('model' | 'selection' | false)Promise<SectionsState>

Schnittbox um das Modell oder die Auswahl; false entfernt sie.

getSections()Promise<SectionsState>

Alle Ebenen, die Box und die Geschosse für Ebenenschnitte.

Touren

startTour(template?, { autoplay?, title? })Promise<TourState>

Eine vordefinierte Tour starten: 'social', 'client-walkthrough' oder 'technical-review' (geht die Validierungsbefunde durch). Abgespielt von der Tour-Leiste des Viewers.

playTour({ title?, steps }, { startAt?, autoplay? })Promise<TourState>

Eine eigene Tour abspielen: Kamerastopps mit Text, Hervorhebungen und isolierten Klassen. autoplay: true oder ms pro Stopp.

nextTourStep() · prevTourStep() · goToTourStep(i)Promise<TourState>

Zwischen Stopps wechseln.

setTourAutoplay(autoplay)Promise<TourState>

Automatisches Weiterschalten der laufenden Tour ein- oder ausschalten.

stopTour()Promise<TourState>

Tour beenden und die Kamera zurückgeben.

getTour()Promise<TourState>

Die Tour und ihre Stopps in der Form von playTour() — speichern und später erneut abspielen.

Präsentations-Regie

getPresentationRecipes()Promise<PresentationRecipe[]>

Die eingebauten Regie-Rezepte (Meeting-Demo, Reel, LinkedIn-Teaser, Launch, Editorial-Looks…).

createPresentation(recipe?, options?)Promise<PresentationState>

Das Modell per Rezept in ein geschnittenes Video verwandeln: Einstellungen aus dem IFC geplant, Texte, Musik. Öffnet Clip Studio mit dem Ergebnis. Fortschritt über presentation-progress.

exportPresentation({ resolution?, music? })Promise<PresentationVideo>

Die Präsentation im Browser des Besuchers kodieren und die MP4-Bytes erhalten — hochladen, anhängen oder in einem <video> abspielen.

closePresentation()Promise<void>

Clip Studio schließen.

Cover-Studio

getCoverOptions()Promise<CoverCatalog>

Die Rezepte, Vorlagen, Formate und Paletten des Cover-Studios.

createCover({ recipe?, template?, format?, palette?, text? })Promise<CoverState>

Ein Cover erstellen: ein Rezept ausführen (es nimmt die nötigen Ansichten auf), dann Vorlage, Format, Palette und Texte setzen. Öffnet das Cover-Studio, weiter bearbeitbar.

getCover()Promise<CoverState | null>

Das Cover im aktuellen Stand, oder null, wenn das Studio geschlossen ist.

exportCover({ type?, slide? })Promise<CoverFile>

Exportieren: png / jpeg (eine Seite), pdf / pptx (das ganze Dokument), zip (alle Seiten). Liefert die Bytes.

closeCover()Promise<void>

Das Cover-Studio schließen.

Artikel-Kit

activate()void

Einen verzögerten Viewer jetzt starten (was der Poster-Button tut). Frühere Aufrufe warten in der Warteschlange.

bindSteps(steps, { rootMargin? })() => void

Scrollytelling: Während jeder Absatz die Bildschirmmitte kreuzt, wird eingepasst, isoliert, die Sonne bewegt oder Ihr Code ausgeführt. Liefert eine Funktion zum Lösen.

setTurntable(enabled | degPerSec)Promise<{ active, speed }>

Langsame Drehung im Leerlauf (Grad pro Sekunde; false stoppt). Stoppt bei der ersten Berührung, nie bei reduzierter Bewegung.

toggleFullscreen()Promise<void>

Die Abbildung auf Vollbild vergrößern oder zurück.

setPaused(paused)Promise<{ paused }>

Das Rendern anhalten oder fortsetzen. pauseOffscreen erledigt das für Sie.

Szenengruppen

getGroups()Promise<SceneGroupsState>

Alle Gruppen der Szene — aus dem IFC abgeleitet (Projekt, Grundstück, Standort) und von Nutzern angelegt.

createGroup(name, modelIds?)Promise<string>

Eine Gruppe anlegen, optional mit Modellen. Liefert ihre id.

renameGroup(id, name) · deleteGroup(id)Promise<void>

Eine Nutzergruppe umbenennen oder löschen. Automatische Gruppen sind nicht editierbar.

assignToGroup(itemId, groupId | null | 'loose')Promise<void>

Ein Modell oder eine Punktwolke in eine Gruppe verschieben; null gibt es der automatischen Gruppierung zurück, 'loose' lässt es ohne Gruppe.

setGroupVisible(id, visible) · isolateGroup(id | null)Promise<void>

Eine ganze Gruppe ein- oder ausblenden, oder nur eine zeigen.

frameGroup(id)Promise<void>

Die Kamera auf eine Gruppe ausrichten — ausgeblendete Mitglieder eingeschlossen.

Messungen

setMeasureTool(tool)Promise<void>

Messwerkzeug für den Besucher aktivieren (öffnet das Mess-Panel) oder 'none'. Ergebnisse kommen über measurements-changed.

getMeasurements()Promise<MeasurementsState>

Alle Messungen auf dem Bildschirm. Werte in SI — Meter, m², Grad — unabhängig von der Anzeige.

clearMeasurements(id?)Promise<MeasurementsState>

Eine Messung entfernen, oder alle.

Abfragen

getModels()Promise<ModelSummary[]>

Listet die geladenen Modelle. Gibt ein Promise zurück.

findElements({ ifcClass?, globalId?, name?, modelId?, limit? })Promise<ElementSummary[]>

Elemente nach IFC-Klasse, GlobalId und/oder Name in den geladenen Modellen finden. Jeder Treffer enthält, was getElement(), select() und frame() erwarten.

getElement(expressId | globalId, modelId?)Promise<IfcElementData | null>

Per expressID oder GlobalId. Die IFC-Daten eines Elements: Attribute mit GlobalId, seine Eigenschafts- und Mengensätze und die seines Typs — typeName, typeProperties — mit Einheiten. effectivePropertySets führt beide zusammen, der eigene Wert des Elements gewinnt.

validate(modelId?, { force? })Promise<ValidationRunResult>

Ein Modell jetzt validieren (standardmäßig das aktive) und mit Health Score und Anzahl der Befunde auflösen. Lehnt mit dem Grund ab.

getValidation()Promise<ValidationSummary | null>

Das angezeigte Prüfergebnis, oder null, bevor ein Lauf eines erzeugt hat. Siehe „Ablauf der Validierung“.

getValidationStatus()Promise<ValidationStatus>

Wo die Validierung gerade steht: idle, running (mit Fortschritt), done oder error.

getStats()Promise<StatsResult>

Elementanzahl je Kategorie und Modell — für Dashboard-Diagramme. Gibt ein Promise zurück.

getIssues({ severity?, limit?, modelId? })Promise<IssuesResult>

Validierungsmeldungen für eine Tabelle (Filter nach Schweregrad / Limit). Gibt ein Promise zurück.

screenshot()Promise<string>

Erfasst die aktuelle 3D-Ansicht als PNG-Data-URL. Gibt ein Promise zurück.

compare({ base, head, baseLabel?, headLabel? })Promise<{ changes }>

Vergleicht zwei Lieferungen per URL (über die GlobalId) und öffnet die Vergleichsansicht mit dem Ergebnis.

Panels

openPanel(panel | null) · closePanel()void

Öffnet ein Werkzeug-Panel, oder null, um das geöffnete zu schließen. Ein nicht verfügbares Panel — vom Chrome ausgeblendet oder ohne geladene Daten — bleibt wirkungslos und ist kein Fehler.

getPanels()Promise<PanelsResult>

Welches Panel offen ist und welche gerade angeboten werden. Ein Werkzeug, das in `available` fehlt, lässt sich nicht öffnen; es ist nicht bloß deaktiviert.

setPanels(panels)void

Beschränkt die Leiste zur Laufzeit auf diese Panels. Gleiches Vokabular wie der URL-Parameter `panels=` und hat Vorrang davor. Schränkt das Angebot ein und erweitert es nie; ein leeres Array bedeutet keine Leiste.

Punktwolken

addPointCloud(fileName, bytes)Promise<string>

Lädt einen Scan aus Bytes — LAS, LAZ, COPC, PLY, PCD oder Text. Der Puffer wird übertragen, nicht kopiert. Liefert die Cloud-ID.

addPointCloudFromUrl(url, fileName?)Promise<string>

Lädt einen Scan, den der Viewer selbst abruft. Die URL muss CORS erlauben.

listPointClouds()Promise<PointCloudInfo[]>

Alle geladenen Scans. `pointCount` ist das Residente, `declaredCount` das, was die Datei enthält — sie unterscheiden sich, wenn das Budget den Parse abgeschnitten hat.

removePointCloud(cloudId) · clearPointClouds()Promise<void>

Entlädt einen Scan und gibt seine GPU-Puffer frei, oder entlädt alle.

setPointCloudVisible(cloudId, visible)Promise<void>

Blendet einen Scan ein oder aus, ohne ihn zu entladen.

fitPointCloud(cloudId?)Promise<void>

Rahmt die Kamera auf einen Scan, oder auf den zuerst geladenen.

setPointCloudDisplay(display, renderBudget?)Promise<void>

Punktgröße, Deckkraft, Farbmodus, Dichte, Konfidenzschwelle — für alle Scans gemeinsam. Jedes ist ein Shader-Uniform und damit auch bei 20 Millionen Punkten sofort wirksam.

inspectPointCloud(enabled?)Promise<void>

Aktiviert Klick-zum-Auslesen. Ein Klick auf einen Punkt sendet dann `pointcloud-picked` mit den Koordinaten AUS DER DATEI neben denen der Szene.

setPointCloudPlacement(placement, cloudId?)Promise<void>

Verschiebt einen Scan von Hand: Position, Gierung, Nivellierung, Maßstab. Partiell und begrenzt; wirkt auf die ermittelte Ausrichtung, ohne sie zu ersetzen.

setPointCloudUpAxis(axis, cloudId?)Promise<void>

Korrigiert, welche Achse der Scan als oben behandelt. PLY, PCD und Text geben keine Orientierung an, der Viewer leitet sie ab — prüfen Sie `upAxisSource`.

Imported 3D models

addMesh(files)Promise<string>

Importiert ein Modell aus Bytes. Erwartet eine LISTE: eine .gltf braucht ihre .bin und Texturen, eine .obj ihre .mtl — allein ergibt die Eingabedatei graue Geometrie.

addMeshFromUrl(urls)Promise<string>

Importiert ein Modell, das der Viewer abruft. Übergeben Sie alle nötigen URLs; sie werden parallel geladen und müssen alle CORS erlauben.

listMeshes()Promise<MeshInfo[]>

Alle importierten Modelle mit Dreiecks- und Texturzahlen. Lesen Sie `unitSource` und `upAxisSource`, bevor Sie den Werten daneben trauen.

removeMesh(meshId?) · clearMeshes()Promise<void>

Entfernt einen Import und gibt Geometrie, Materialien und Texturen frei, oder entfernt alle.

setMeshVisible(visible, meshId?)Promise<void>

Blendet einen Import ein oder aus, ohne ihn zu entladen.

fitMesh(meshId?)Promise<void>

Rahmt die Kamera auf einen Import, oder auf alle.

setMeshPlacement(placement, meshId?)Promise<void>

Platziert einen Import von Hand: Position, Gierung, Nivellierung, Maßstab. Partiell und begrenzt. Importe starten mittig über dem IFC, auf dessen Boden.

setMeshUpAxis(axis, meshId?)Promise<void>

Korrigiert die Hochachse der Quelle. Nur bei OBJ sinnvoll — die glTF-Spezifikation schreibt Y oben vor, daher meldet sie `upAxisSource: 'declared'`.

setMeshUnit(unitScale, meshId?)Promise<void>

Korrigiert die Quelleinheit: 1 Meter, 0,01 Zentimeter, 0,001 Millimeter, 0,3048 Fuß. Keines dieser Formate hält sie fest, der Viewer leitet sie aus der Modellgröße ab.

IDS- und EIR-Konformität

checkIds(idsXml)Promise<IdsResult>

Prüft das Modell gegen ein buildingSMART-IDS (.ids-XML). Läuft in einem Worker. Liefert bestanden/nicht bestanden je Spezifikation.

checkEir(profile)Promise<IdsResult>

Prüft das Modell gegen ein EIR-/BIM-Validierungsprofil — ein Objekt, sein JSON (auch die Kurzform) oder die Id eines eingebauten Profils wie 'builtin-en14351-1'. Wird zu IDS kompiliert und läuft auf derselben Engine: dieselbe IdsResult-Form wie checkIds.

Sprachen

setLanguage(lang)void

Die UI-Sprache zur Laufzeit ändern.

getLanguages()string[]

Unterstützte Sprachcodes auflisten (Labels via IfcViewer.LANGUAGES).

Lebenszyklus & Events

whenReady()Promise<void>

Löst auf, sobald der Viewer Befehle annehmen kann.

isReadyboolean

Getter — true, sobald der Viewer seine Bereitschaft gemeldet hat.

on(event, cb)() => void

Ein Event abonnieren; gibt eine Abmelde-Funktion zurück.

off(event, cb)void

Entfernt einen zuvor hinzugefügten Event-Listener.

dispose()void

Den Viewer abbauen und das iframe entfernen.

Gleichzeitige Aufrufe von add() / addFromUrl() werden intern serialisiert, und jedes Promise ist seinem eigenen Ladevorgang zugeordnet — ein von der App ausgelöster Ladevorgang (URL-Parameter, Upload im iframe) löst niemals dein add()-Promise auf.

Konstruktor-Optionen

OptionTypStandardBeschreibung
ui'minimal' | 'full' | 'kiosk' | 'client' | 'article' | 'embed''minimal'UI-Preset. 'embed': für eine Host-App, die die Datei liefert — 3D, Eigenschaften bei Auswahl, eine kompakte Leiste mit Prüfen und Messen; ohne Öffnen, Teilen, Konto oder Sprache.
toolbarbooleanpresetDie Werkzeugleiste zeigen (Standard: die des Presets). false lässt 3D-Ansicht und Panels.
tools('validate' | 'measure')[]['validate', 'measure']Werkzeuge der kompakten Leiste von ui: 'embed' — 'validate', 'measure'. [] für keine.
autoFramebooleantrueNach jedem abgeschlossenen Laden die ganze Szene iso mit Rand einpassen. false überlässt Ihnen die Kamera.
validatebooleantrueValidierung beim Laden ausführen (speist den Health Score).
panelbooleanfalseValidierungspanel automatisch öffnen.
panelsPanelName[]—Beschränkt die Werkzeugleiste ab dem ersten Frame auf diese Panels — `['scene','map']`, oder `[]` für keine Leiste. Gleiche Namen wie setPanels und der URL-Parameter `panels=`. Besser als ein setPanels nach dem Laden, das erst die volle Leiste zeigt und dann Werkzeuge entfernt.
langstringautoUI-Sprache erzwingen (z. B. en, es, ja).
accent#rrggbbbrandDen Viewer farblich an dein Dashboard angleichen.
modelstring—Diese öffentliche IFC-URL laden, sobald der Viewer bereit ist.
backgroundBackgroundSpec—Szenenhintergrund ab dem ersten Frame — ein Preset, '#rrggbb' oder '#oben,#unten'.
mapboolean | ('terrain' | 'buildings' | 'showcase')[]—Modell nach dem Laden auf die Karte setzen: true oder Ebenen ['terrain','buildings','showcase'].
solar · moon'MM-DDTHH:MM' · boolean—Sonnenstudie zu einer Ortszeit öffnen: '06-21T18:00'.
scansstring[]—Punktwolken-URLs, die mit dem Modell geladen werden.
layersstring—Zu öffnende Datenebenen-Einrichtung: URL eines aus dem Datenebenen-Panel exportierten JSON (Live-Quellen, Stile, Alarme). Seit 1.16.
scenestring—Zu öffnende Szene: URL eines Szenendokuments (Modelle, Datenebenen, Live-Geräte, Karte, Kamera). Seit 1.17.
view · fillCameraView · number—Sobald alle Modelle geladen sind, aus dieser Ansicht eng einpassen. ui: 'article' setzt 'iso'.
wheel'always' | 'ctrl''always''ctrl': Das Mausrad scrollt Ihre Seite und zoomt nur mit gedrückter Strg/⌘ — wie eine eingebettete Karte. ui: 'article' setzt es.
lazyboolean | 'visible'falseNichts laden, bis es gebraucht wird: true zeigt ein Poster mit Button, 'visible' startet, wenn die Abbildung in Sichtweite kommt.
poster · posterTitle · posterText · launchLabelstring—Posterbild, Titel, Text und Button-Beschriftung, bis der Viewer bereit ist.
aspectRatiostring ('16/10')—Größe per Seitenverhältnis ('16/10'): Poster und Viewer teilen die Box, nichts verschiebt die Seite.
turntableboolean | numberfalseLangsame Drehung nach dem Laden (true = 6°/s, oder Grad pro Sekunde).
pauseOffscreenbooleanui === 'article'Außerhalb des Bildschirms nicht rendern. Standard true mit ui: 'article'.
fullscreenButtonbooleanfalseEin kleiner Vergrößern-Button in der Ecke.
height · widthnumber | string'100%'iframe-Größe (Zahl → px).
baseUrlstringautoBasis-URL der App. Wird aus der Skript-URL abgeleitet.
loadTimeoutnumber120000add()/addFromUrl() nach N ms ablehnen (0 deaktiviert das).
className · titlestring—Zusätzliche Klasse / iframe-title.
on* callbacksfunction—Bequeme Callbacks — dasselbe wie .on(...).

Events

EventPayloadBeschreibung
ready{ languages }Viewer eingehängt und bereit.
model-progress{ percent, phase }Ladefortschritt (Download → Parsen → Rendern).
model-loaded{ modelId, fileName, elementCount, fromCache }Ein Modell wurde geladen.
validation-started{ modelId }Eine Validierung hat an einem Modell begonnen — nach dem Laden (validate: true) oder per validate().
validation-completed{ modelId, qualityScore, errors, warnings, info, total }Validierung fertig: Health Score und Anzahlen, und das Modell, auf das sie sich beziehen (null für das föderierte Gesamtergebnis).
validation-failed{ modelId, message }Eine Validierung konnte nicht laufen oder wurde nicht fertig — mit dem Grund.
model-error{ message, url?, name? }Ein Laden ist fehlgeschlagen.
element-selected{ expressId, modelId, ifcType, name, globalId }Der Nutzer hat ein Element gewählt — mit GlobalId, passend zu Ihren eigenen Datensätzen.
pointcloud-picked{ cloudId, position, sourcePosition, classification, intensity, distance }Ein Punkt wurde aus einem Scan gelesen — in den Koordinaten der Datei, nicht der Szene.
map-feature-picked{ id, name?, label?, featureKind, heightM?, heightEstimated }Ein Gebäude der OpenStreetMap-Umgebung wurde angeklickt. Kontext, kein Modell.
walk-changed{ active, speed }Begehungsmodus ein- oder ausgeschaltet — vom Besucher oder vom Host.
measurements-changed{ tool, units, items }Eine Messung wurde hinzugefügt, entfernt oder umbenannt. Enthält die ganze Liste.
tour-started{ title, total, template }Eine Tour hat begonnen.
tour-step{ index, total, caption }Die Tour ist zu einem anderen Stopp gewechselt.
tour-ended{ completed }Die Tour wurde beendet; completed, wenn der letzte Stopp erreicht war.
presentation-progress{ stage, label?, progress }Die Regie erzeugt oder exportiert eine Präsentation.
layer-feature-picked{ layerId, layer, featureId, geometry, lonLat, properties }Ein Objekt einer Datenebene wurde angeklickt: Ebene, Eigenschaften und ein Punkt zum Markieren.
alert{ kind, from, id, name, rule, count, sample }Eine Regel einer Datenebene oder des Zwillings hat zu alarmieren begonnen oder aufgehört.

Statische Member

IfcViewer.LANGUAGES ({ code, label }[], native Namen) und IfcViewer.SUPPORTED_LANGUAGES (Codes) — für eine Sprachauswahl, bevor der Viewer bereit ist.

Web Component

Null JavaScript — Tag in eine beliebige Seite oder ein Dashboard setzen und Attribute vergeben.

Attribute: modeluilangaccentvalidatepanelbase-urltoolbartoolsauto-frame

Events werden als DOM-CustomEvents mit dem Namen ifcviewer:<type> erneut ausgelöst (detail = Payload). Der zugrunde liegende IfcViewer liegt auf .viewer des Elements; getStats / getIssues / screenshot werden durchgereicht.

JavaScript
const el = document.querySelector("ifc-viewer");
el.addEventListener("ifcviewer:validation-completed", (e) => {
  updateScore(e.detail.qualityScore);
});
const stats = await el.getStats();

Anleitungen

Rezepte

Copy-Paste-Muster für das, was Teams tatsächlich bauen.

Element-Inspektor

Im 3D klicken und die IFC-Property-Sets in dein eigenes Panel lesen.

JavaScript
viewer.on("element-selected", async (e) => {
  const data = await viewer.getElement(e.expressId, e.modelId);
  renderPanel(data.name, data.globalId, data.propertySets);
});

Health-Score-Widget

Qualitätswert und Anzahl der Befunde des Modells in deinem Dashboard zeigen.

JavaScript
viewer.on("validation-completed", (v) => {
  setScore(v.qualityScore);                 // 0–100, or null
  setCounts(v.errors, v.warnings, v.info);
});

IDS-Konformitätsprüfung

Gegen ein buildingSMART-IDS validieren und pro Spezifikation bestanden / nicht bestanden auflisten.

JavaScript
const ids = await fetch("/specs/project.ids").then(r => r.text());
const res = await viewer.checkIds(ids);     // runs in a worker

res.specs.forEach((spec) => {
  row(spec.name, spec.status, spec.passedCount + "/" + spec.applicableCount);
  spec.failures.forEach((f) => onClick(() => viewer.select(f.expressId, f.modelId)));
});

EIR- / BIM-Validierung

Ein editierbares EIR-Profil ausführen (im Stil von ISO 19650) — ohne .ids-Datei. Fehlschläge tragen die GlobalId des Elements.

JavaScript
// An editable EIR profile — object, JSON, or the compact shorthand below.
const profile = {
  name: "Door QA",
  rules: [
    { type: "requiredProperty", entity: "IfcDoor", property: "FireRating", severity: "error" },
    { type: "allowedValues", entity: "IfcDoor", property: "FireRating",
      values: ["EI30", "EI60", "EI90"], severity: "warning" },
  ],
};
const res = await viewer.checkEir(profile);   // same IdsResult as checkIds
res.specs.forEach((spec) => {
  spec.failures.forEach((f) => row(spec.name, f.globalId, f.reasons.join(" · ")));
});

Eine Szene für einen Blogartikel

Weißer Hintergrund, das Modell an seinem Standort und der Abendschatten der Sommersonnenwende — vorab deklariert, ohne Klicks.

JavaScript
// Declared up front: the iframe boots with all of it, no clicks, no flash.
const viewer = await IfcViewer.create("#viewer", {
  model: "https://example.com/house.ifc",
  ui: "client",
  background: "white",
  map: ["terrain", "buildings"],   // your page declares tile consent
  solar: "06-21T19:30",            // summer solstice, site-local
});

// …or change the story as the reader scrolls
await viewer.setSolar({ date: "12-21", time: "09:30" });
const { attributions } = await viewer.getSiteContext(); // show these

Grundriss und Messungen

Einen Grundriss auf einem benannten Geschoss schneiden, den Leser messen lassen und die Ergebnisse in SI-Einheiten auslesen.

JavaScript
const { levels } = await viewer.getSections();
await viewer.addSection({ level: levels[0].name });   // floor plan, 1.2 m up
viewer.setView("top");

await viewer.setMeasureTool("distance");
viewer.on("measurements-changed", ({ items }) => {
  // value is SI — metres, m², degrees — whatever the viewer displays
  render(items.map((m) => m.kind + ": " + m.value?.toFixed(2)));
});

Eine geführte Tour im Artikel

Die Stopps einmal mit getCamera() festlegen und die Tour neben dem Text selbst laufen lassen.

JavaScript
// 1. Once, while writing the post: frame each view and copy the camera.
console.log(JSON.stringify(await viewer.getCamera()));

// 2. In the page: play the stops, self-running, next to your text.
await viewer.playTour({
  title: "Casa Poblenou",
  steps: [
    { position: { x: 52, y: 29, z: 24 }, target: { x: 18, y: 7, z: -11 }, caption: "The site" },
    { position: { x: 18, y: 40, z: 11 }, target: { x: 18, y: 0, z: 10 },
      caption: "Structure", isolate: ["IfcColumn", "IfcSlab"] },
  ],
}, { autoplay: 6000 });
viewer.on("tour-step", ({ index, caption }) => highlightParagraph(index));

Ein Video des Modells, von Ihrer Seite

Eine Präsentation per Rezept erzeugen und das MP4 zurückbekommen — ohne Bildschirmaufnahme, ohne Upload.

JavaScript
viewer.on("presentation-progress", ({ stage, progress }) => bar.value = progress ?? 0);
await viewer.createPresentation("linkedin-teaser", { title: "Casa Poblenou", targetSec: 20 });

const { bytes, mimeType } = await viewer.exportPresentation({ resolution: 1080 });
video.src = URL.createObjectURL(new Blob([bytes], { type: mimeType }));

Ein Cover für Ihren Beitrag

Einen Pinterest-Pin oder eine LinkedIn-Karte des Modells mit Ihrem Titel erzeugen und das PNG zurückbekommen.

JavaScript
await viewer.createCover({
  recipe: "pinterest",
  text: { title: "Casa Poblenou", location: "Barcelona", website: "https://example.com" },
});
const { bytes, mimeType } = await viewer.exportCover({ type: "png" });
img.src = URL.createObjectURL(new Blob([bytes], { type: mimeType }));

Ein Modell in einem Artikel

ui: 'article' ist nur die Leinwand, so eingepasst, dass das Modell sie füllt, mit einem Mausrad, das Lesende weiterscrollen lässt. Den Winkel wählt frame().

JavaScript
const viewer = new IfcViewer("#figure", {
  ui: "article",            // canvas only, tight iso framing, wheel scrolls the page
  model: "https://example.com/pavilion.ifc",
  lazy: true,               // nothing loads until the reader asks
  poster: "/img/pavilion.jpg",
  posterTitle: "The pavilion, live",
  aspectRatio: "16/10",     // no layout shift from poster to viewer
  background: "auto",       // paper on a light page, studio on a dark one
  turntable: true,          // a slow turn until the reader takes over
  fullscreenButton: true,
  validate: false,
});

Eine Geschichte, die mit dem Text läuft

Den Viewer fixieren und jeden Absatz die Einstellung wählen lassen: Wände isolieren, herumschwenken, die Abendsonne einblenden.

JavaScript
// <div id="figure" style="position:sticky;top:1rem"></div>
// <p id="s1">…</p> <p id="s2">…</p> <p id="s3">…</p>
const viewer = new IfcViewer("#figure", { ui: "article", aspectRatio: "16/10", model: url });
viewer.bindSteps([
  { el: "#s1", frame: { view: "iso" } },
  { el: "#s2", isolate: "IfcWall", frame: { azimuth: 225, elevation: 20 } },
  { el: "#s3", isolate: null, solar: { active: true, date: "06-21", time: "19:30" } },
]);

Ein Live-Stadtzwilling auf Ihrer Seite

Eine veröffentlichte Szene öffnen, auf ihre Alarme und Klicks reagieren, eine eigene Live-Quelle daneben hinzufügen und einen Link zum Ergebnis weitergeben.

JavaScript
const viewer = new IfcViewer("#twin", {
  ui: "client",
  scene: "https://www.ifcvieweronline.eu/scenes/barcelona-placa-catalunya.scene.json",
});
viewer.on("alert", (a) => { if (a.kind === "start") notify(a.name + ": " + a.rule) });
viewer.on("layer-feature-picked", (f) => showCard(f.layer, f.properties));

// Your own live source next to the scene's (GeoJSON with CORS, every 60 s)
await viewer.addLayer({ url: "https://example.org/sensors.geojson", live: 60 });
const { link, sources } = await viewer.exportScene({ title: "Our twin" });

Ein Produktdatenblatt in Ihrer App

Version fixieren, die Datei übergeben und zeigen, was der Hersteller in den Typ geschrieben hat: U-Wert, Windlastklasse, Hersteller.

JavaScript
import { IfcViewer } from "https://www.ifcvieweronline.eu/sdk/1.18.0/ifc-viewer.es.js";

const viewer = await IfcViewer.create("#product-3d", {
  ui: "embed",               // 3D + properties, Validate and Measure only
  panels: ["properties"],
  lang: "es",
});
const bytes = await fetch(product.ifcUrl).then(r => r.arrayBuffer());
await viewer.add("V-70-PR.ifc", bytes);                      // framed for you

// The product, by class (or by its GlobalId) — no expressIDs to know
const [win] = await viewer.findElements({ ifcClass: "IfcWindow" });

// What the manufacturer put in the type (IfcWindowType → HasPropertySets)
const el = await viewer.getElement(win.globalId);
const pset = (name) => el.effectivePropertySets.find(s => s.name === name);
const uw = pset("Pset_WindowCommon")?.properties.find(p => p.name === "ThermalTransmittance");
console.log(el.typeName, el.globalId, uw?.value, uw?.unit);   // "Ventana V-70 practicable" … 1.2 "W/(m²·K)"

const { qualityScore } = await viewer.validate();             // Health Score, on demand

// Declared performance per EN 14351-1: wind, water, acoustics, Uw, g / τv, DoP
const en = await viewer.checkEir("builtin-en14351-1");
const missing = en.specs.filter(s => s.status === "fail").map(s => s.name);

An deine Marke anpassen

Den Viewer mit einer einzigen Akzentfarbe an dein Produkt angleichen.

JavaScript
new IfcViewer("#viewer", { accent: "#3fa866" });

// …or on the web component:
// <ifc-viewer accent="#3fa866" model="…"></ifc-viewer>

Sprachauswahl

Eine Auswahl aus den mitgelieferten Sprachen des Viewers bauen.

JavaScript
// build a <select> from the bundled languages
IfcViewer.LANGUAGES.forEach(({ code, label }) => addOption(code, label));

// switch at runtime
viewer.setLanguage("ja");

Health Score

Ablauf der Validierung

validate: true validiert jedes Modell, sobald es geladen ist; validate() startet sie auf Anforderung und löst mit dem Ergebnis auf. Was getValidation() wann liefert:

WanngetValidation() liefert
Vor jeder Validierungnull — getValidationStatus() meldet idle.
Während des ersten Laufsnull — getValidationStatus() meldet running mit Fortschritt; validation-started wurde gesendet.
Nach einem Lauf{ qualityScore, errors, warnings, info, total, status: 'done', modelId }. Bei mehreren Modellen das Gesamtergebnis (modelId: null).
Während eines neueren LaufsDie vorherigen Zahlen, mit status: 'running'.
Nach einem FehlschlagDie vorherigen Zahlen mit status: 'error' und error — oder null, wenn es keine gab. validation-failed wurde gesendet, validate() hat abgelehnt.

Versionen

Eine Version fixieren

Ab 1.18.0 wird jede Version zusätzlich unter einem Pfad veröffentlicht, der sich nie ändert. In Produktion fixieren; der bewegliche Pfad folgt der neuesten Version.

HTML
<script type="module">
  import { IfcViewer } from "https://www.ifcvieweronline.eu/sdk/1.18.0/ifc-viewer.es.js";
</script>
PfadCachingEinsatz
/sdk/ifc-viewer.es.jsbei jedem Laden neu validiertZum Ausprobieren — immer die neueste.
/sdk/1.18.0/ifc-viewer.es.jsunveränderlich, ein Jahr im CacheProduktion — der getestete Code ist der Code, der läuft.

Welchen Viewer öffnet ein fixiertes SDK?

Der iframe ist der Live-Viewer derselben Origin, keine eingefrorene Kopie: Ein fixiertes SDK behält seine API und sein Verhalten, während der Viewer darin besser wird. Der Viewer beantwortet jeden Befehl jedes veröffentlichten SDK — der Build prüft das —, also funktioniert auch eine alte Fixierung weiter.

Auch den Inhalt fixieren

versions.json neben dem SDK listet den Subresource-Integrity-Hash jeder Version:

HTML
<script type="module" src="https://www.ifcvieweronline.eu/sdk/1.18.0/ifc-viewer.es.js"
        integrity="sha384-WsT4d0DS1oqva4rLWCGBDrx50uZVA3B95IDWbfxaFt8lnjs6NgOrjKNcWQL57/0z" crossorigin="anonymous"></script>

Änderungsprotokoll

1.18.0 — Katalogobjekte in einer Host-App. getElement() liefert die GlobalId und die Daten des Typs (typeName, typeProperties mit Einheiten, effectivePropertySets; IFC4-Typen und IFC2x3-Styles). validate(), getValidationStatus(), validation-started / validation-failed, und validate: true validiert nach jedem Laden wirklich. Automatisches Einpassen nach dem Laden, fit() und frame() mit Rand für kleine Objekte, frame(elementId), und setView() bewegt die Kamera wieder. ui: 'embed' mit toolbar und tools. Fixierte Builds unter /sdk/1.18.0/. findElements(), GlobalIds für getElement() / select() / element-selected, Rahmen- und Flügelsätze von Fenstern und Türen und die Materialien des Typs; in ui: 'embed' hält das Eigenschaftspanel das gewählte Objekt im Blick. checkEir('builtin-en14351-1') prüft die erklärten Leistungen von Fenstern und Außentüren nach EN 14351-1 — Windlast, Schlagregendichtheit, Schallschutz, Wärmedurchgangskoeffizient, g und τv, Hersteller und Produktcode — in Standard-IFC-Property-Sets; EIR-Regeln erhalten where (nur Elemente mit einem Eigenschaftswert) und optional.

Hilfe

Fehlerbehebung

Die wenigen Dinge, über die man stolpert.

Es wird nichts gerendert

Prüfe der Reihe nach: ob der Viewer ready erreicht hat, ob das Modell geladen wurde (model-loaded statt model-error), ob der Container eine Höhe ungleich null hat und ob die Byte-Quelle gültiges IFC ist. Die Meldung von model-error nennt die Ursache.

Beim Laden eines Modells kommt ein CORS-Fehler

CORS betrifft nur addFromUrl(url). Wenn du die Bytes kontrollierst, lade sie selbst und rufe add(name, bytes) auf — CORS greift nicht, weil du die Daten direkt übergibst.

Das iframe bleibt leer oder lädt nicht

Die App muss einbettbar sein — kein X-Frame-Options: DENY und keine restriktive frame-ancestors-CSP auf dem Host. Unsere gehostete App erlaubt das Einbetten.

Mein ArrayBuffer ist nach add() leer

add() transferiert den Buffer für eine Übergabe ohne Kopie, wodurch er in deinem Code detached wird. Übergib eine Kopie (bytes.slice(0)), wenn du die Bytes danach noch brauchst.

Ladevorgänge oder Abfragen laufen in einen Timeout

add()/addFromUrl() werden nach loadTimeout abgelehnt (Standard 120 s; 0 deaktiviert). Abfragen nach 30 s, checkIds nach 120 s. Große Modelle auf langsamen Geräten brauchen eventuell ein höheres loadTimeout.

Welche Browser werden unterstützt?

Jeder moderne Evergreen-Browser mit WebAssembly und ES-Modulen — Chrome, Edge, Firefox, Safari. Kein Internet Explorer.

Auf meinem lokalen Dev-Server kommt ein 404

Ein SPA-Dev-Server kann /sdk/ mit seinem HTML-Fallback abfangen. Teste gegen einen echten Build oder ein statisches Hosting, oder importiere das Modul /sdk/ifc-viewer.es.js direkt.