IFC Viewer SDK v1.18.0 Ouvrir le visualiseur
Français

IFC Viewer SDK · v1.18.0

Intégrez le visualiseur IFC dans votre propre produit

Insérez le même visualiseur navigateur dans votre CDE, jumeau numérique ou outils internes de projet. Chargez des données IFC depuis votre app, chaque modèle étant analysé côté client.

Trois lignes jusqu’au premier rendu

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

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

Mise en place

Démarrage rapide

Choisissez votre stack. Copiez, collez, affichez — sans étape de build, sans clé d’API.

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>

Hébergé par nous ou par vous

Les extraits importent depuis notre CDN, qui fonctionne sur n’importe quelle origine. Pour l’héberger vous-même, servez ifc-viewer.es.js depuis votre propre domaine — le SDK découvre l’URL de l’application relativement au script. L’application est ailleurs ? Utilisez l’option baseUrl.

Pas encore de paquet npm : importez le module par URL (ci-dessus) ou intégrez ifc-viewer.es.js à votre application.

Démonstration

Démo en direct

Cette page exécute le SDK. Cliquez un contrôle pour charger un IFC d’exemple et piloter le visualiseur — chaque bouton affiche l’appel qu’il effectue.

inactif
Dernier appel —

Architecture

Comment ça marche

Un wrapper minuscule dans votre page, le visualiseur complet dans un iframe isolé, vos octets transmis entre les deux — et analysés là où ils se trouvent déjà.

Navigateur du visiteur — rien n’est téléverséVotre applicationSDK · ~6 Koiframe isoléthree.js · web-ifc · WASMOctets IFCpostMessage

Votre application

Un module ES de ~6 Ko qui crée un iframe et une API JS typée. Rien du poids 3D ni de l’analyse ne touche votre bundle.

Pont postMessage

Les octets IFC sont transférés à l’iframe sous forme d’ArrayBuffer (sans copie). Les commandes et les requêtes sont des messages requête/réponse corrélés.

Le visualiseur

three.js + web-ifc compilé en WebAssembly analysent et affichent le modèle dans l’iframe — sur la machine du visiteur.

Pourquoi c’est privé

Les modèles n’atteignent jamais un serveur. Aucun pipeline de téléversement à sécuriser, aucune question de résidence des données, aucune file d’attente liée à la taille des fichiers.

Pourquoi ça passe à l’échelle

Le calcul s’exécute sur l’appareil de chaque visiteur. Servir un modèle de 200 Mo coûte autant qu’un de 2 Mo — c’est un fichier statique.

Concepts

Concepts essentiels

Quatre choses à savoir avant de construire.

Montage et disponibilité

new IfcViewer(target) monte immédiatement et met les commandes en file d’attente jusqu’à ce que le visualiseur soit prêt. await IfcViewer.create(target) (ou whenReady()) vous donne une instance utilisable tout de suite.

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");

Octets ou URL

add(name, bytes) transmet des octets que vous avez déjà — pas de CORS, rien de téléversé ; le buffer est transféré (détaché), passez donc une copie si vous en avez encore besoin. addFromUrl(url) récupère plutôt une URL publique avec 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");

Événements

Abonnez-vous avec on(event, cb), qui renvoie une fonction de désabonnement. Vous disposez de ready, model-progress, model-loaded, validation-completed, model-error et element-selected.

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

Requêtes

Récupérez les données à la demande : getModels, getElement, getValidation, getStats, getIssues, checkIds, checkEir, screenshot. Chacune est en requête/réponse et échoue après un délai (30 s ; IDS / EIR jusqu’à 120 s).

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

Référence

Référence de l’API

Toutes les méthodes, regroupées — avec signatures et types de retour. Suivent les options du constructeur, les événements et le web component <ifc-viewer>.

Constructeur

new IfcViewer(target, options?)IfcViewer

Monter dans un sélecteur CSS ou un élément. Voir les options ci-dessous.

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

Crée un visualiseur et se résout dès qu’il peut accepter des commandes.

Chargement des modèles

add(name, bytes)Promise<ModelLoadedEvent>

Charger des octets IFC (ArrayBuffer/Uint8Array) depuis votre app. Le buffer est transféré pour un passage sans copie.

addFromUrl(url, name?)Promise<ModelLoadedEvent>

Charger une URL IFC publique compatible CORS.

removeModel(modelId)void

Décharge un modèle par id.

clear()void

Supprimer tous les modèles chargés.

Caméra et sélection

select(expressId | globalId, modelId?)void

Sélectionner et cadrer un élément — par son expressID IFC ou par son GlobalId (qui trouve aussi son modèle).

setView(view)void

Voler vers une vue nommée de la scène — iso, front, back, left, right, top, bottom — avec toute la scène dans le cadre. Sans réponse (de 1.14 à 1.17 la visionneuse l’ignorait).

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

Cadrage de présentation : le modèle occupe `fill` du cadre (0,2–0,98, 0,85 par défaut), ajusté à ses coins plutôt qu’à sa sphère englobante. azimuth / elevation choisissent l’angle.

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

Cadrer un élément (expressID) : depuis l’angle actuel sauf si une vue est donnée. Rejette s’il n’est pas dans le modèle.

fit() · reset()void

Cadrer le modèle actif depuis l’angle actuel, avec une marge / réinitialiser la caméra.

setCamera(position, direction)void

Place la caméra à une position regardant dans une direction.

getCamera()Promise<CameraState | null>

Où est la caméra et ce qu’elle regarde — enregistrez-le, restaurez-le avec lookAt.

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

Amène la caméra à une position, regardant une cible (mètres de scène, Y vers le haut).

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

Mode visite à la première personne (WASD, glisser pour regarder, Échap pour sortir). Émet walk-changed.

getWalkState()Promise<WalkState>

Si le mode visite est actif, et à quelle vitesse.

Visibilité

isolate(ifcType?)void

Isoler une catégorie (p. ex. "IfcWall") ; omettre pour réinitialiser.

showAll()void

Restaurer toute la visibilité (annuler masquage + isolation).

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

Masque / affiche un ensemble d’éléments par expressID.

setModelVisible(modelId, visible)Promise<void>

Affiche ou masque un modèle d'une scène fédérée sans le décharger.

setModelOpacity(opacity, modelId?)Promise<void>

Rend un modèle translucide (0,05–1) — p. ex. l’architecture autour des lots techniques.

isolateModel(modelId | null)Promise<void>

N’affiche que ce modèle ; null les réaffiche tous.

Apparence et présentation

setBackground(background)Promise<BackgroundState>

Change le fond de la scène : un préréglage ('white', 'paper', 'blueprint', 'sky', 'studio'), '#rrggbb', '#haut,#bas' ou { top, bottom }. Non enregistré comme préférence du visiteur.

getBackground()Promise<BackgroundState>

Le fond actuel de la scène.

setAccent(color)Promise<void>

Change la couleur d'accent de l'interface à l'exécution (#rrggbb).

setClientMode(enabled)Promise<void>

Active ou désactive la vue client — celle des parties prenantes, comme ui: 'client'.

setRenderQuality(quality)Promise<void>

'quality' active le rendu plus lourd pour une image phare ; 'standard' au quotidien.

Étude solaire

setSolar(opts?)Promise<SolarState>

Ombres réelles à une date et une heure locales du site : { date: '06-21', time: '18:00' }. Le site vient du géoréférencement IFC ; passez location pour un modèle qui n’en a pas — jamais une ville par défaut en silence.

getSolar()Promise<SolarState>

Date, heure et fuseau de l'étude, et où se trouve le site.

Mode carte

setSiteContext(opts?)Promise<SiteContextState>

Place le modèle sur la carte avec le relief et les environs OpenStreetMap. L’appeler, c’est votre page qui déclare le consentement aux tuiles pour ses visiteurs ; affichez les attributions.

getSiteContext()Promise<SiteContextState>

État du mode carte, le placement et les attributions à afficher.

Scènes

openScene(url | SceneDocument)Promise<void>

Ouvrir une autre scène : l’URL d’un .scene.json, ou un document de scène (il voyage compressé dans l’adresse du cadre et doit tenir dans un lien). La visionneuse se recharge ; les appels en attente sont rejetés et ready se déclenche de nouveau.

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

La scène à l’écran comme document de scène — modèles par URL, couches, jumeau, carte, caméra — avec les sources à créditer et un lien qui la contient.

packScene(doc)Promise<string | null>

Compresser soi-même un document de scène pour un lien #scene= (null s’il est trop gros pour un lien).

Couches de données et jumeau

getLayerPresets()Promise<LayerPreset[]>

Le catalogue des sources publiques en direct, nommées dans la langue de la visionneuse, avec ce qu’il faut à chacune dans un navigateur (une clé, un proxy) et si elle a des données près du site.

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

Ajouter une couche : une source du catalogue ({ preset }), du GeoJSON ou un flux en direct à une URL ({ url, live }), ou du GeoJSON que vous avez déjà ({ geojson }). Pour la session seulement : jamais enregistrée dans les couches du visiteur.

getLayers()Promise<DataLayerInfo[]>

Toutes les couches de données : état, nombre d’entités, emprise, rafraîchissement et attribution.

setLayerVisible(id, visible)Promise<DataLayerInfo>

Afficher ou masquer une couche.

frameLayer(id)Promise<void>

Amener la caméra sur les entités d’une couche.

removeLayer(id)Promise<void>

Retirer une couche.

getTwin()Promise<TwinState>

Le jumeau opérationnel maintenant : sources d’appareils (état, dernière lecture) et, par liaison, la règle vérifiée, sa couleur, la valeur de l’étiquette et si elle est en alerte.

Coupes

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

Ajoute un plan de coupe. { level: 'RDC' } est un plan à cet étage ; { axis: 'x', offset: 4.5 } une coupe à 4,5 m.

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

Déplace, active/désactive ou inverse un plan.

removeSection(id?)Promise<SectionsState>

Retire un plan, ou toutes les coupes sans id.

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

Une boîte de coupe autour du modèle ou de la sélection ; false la retire.

getSections()Promise<SectionsState>

Tous les plans, la boîte et les niveaux disponibles pour les coupes par étage.

Visites

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

Lance une visite prédéfinie : 'social', 'client-walkthrough' ou 'technical-review' (parcourt les anomalies de validation). Jouée par la barre de visite du visualiseur.

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

Joue une visite que vous avez écrite : arrêts de caméra avec légende, surlignages et classes isolées. autoplay : true ou ms par arrêt.

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

Passer d’un arrêt à l’autre.

setTourAutoplay(autoplay)Promise<TourState>

Active ou désactive l’avance automatique de la visite en cours.

stopTour()Promise<TourState>

Arrête la visite et rend la caméra.

getTour()Promise<TourState>

La visite et ses arrêts, au format de playTour() — enregistrez-la, rejouez-la plus tard.

Réalisateur de présentations

getPresentationRecipes()Promise<PresentationRecipe[]>

Les recettes intégrées du réalisateur (démo de réunion, reel, teaser LinkedIn, lancement, looks éditoriaux…).

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

Transforme le modèle en vidéo montée à partir d’une recette : plans tirés de l’IFC, légendes, musique. Ouvre Clip Studio avec le résultat. Suivez presentation-progress.

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

Encode la présentation dans le navigateur du visiteur et renvoie les octets du MP4 — à téléverser, joindre ou lire dans une <video>.

closePresentation()Promise<void>

Ferme Clip Studio.

Studio de couvertures

getCoverOptions()Promise<CoverCatalog>

Les recettes, modèles, formats et palettes du studio de couvertures.

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

Créer une couverture : lancer une recette (elle capture les vues nécessaires), puis fixer modèle, format, palette et textes. Ouvre le studio, toujours modifiable.

getCover()Promise<CoverState | null>

La couverture en l’état, ou null si le studio est fermé.

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

L’exporter : png / jpeg (une page), pdf / pptx (tout le document), zip (toutes les pages). Renvoie les octets.

closeCover()Promise<void>

Ferme le studio de couvertures.

Kit article

activate()void

Démarrer maintenant une visionneuse différée (ce que fait le bouton de l’affiche). Les appels précédents attendaient.

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

Scrollytelling : quand chaque paragraphe passe au milieu de l’écran, cadrer, isoler, déplacer le soleil ou lancer votre code. Renvoie une fonction de détachement.

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

Une lente rotation au repos (degrés par seconde ; false l’arrête). S’arrête au premier contact, jamais en mouvement réduit.

toggleFullscreen()Promise<void>

Passer la figure en plein écran, ou revenir.

setPaused(paused)Promise<{ paused }>

Suspendre ou reprendre le rendu. pauseOffscreen le fait pour vous.

Groupes de scène

getGroups()Promise<SceneGroupsState>

Tous les groupes de la scène — déduits de l’IFC (projet, site, localisation) et créés par les utilisateurs.

createGroup(name, modelIds?)Promise<string>

Crée un groupe, éventuellement avec des modèles. Renvoie son id.

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

Renomme ou supprime un groupe utilisateur. Les groupes automatiques ne sont pas modifiables.

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

Place un modèle ou un nuage de points dans un groupe ; null le rend au regroupement automatique, 'loose' le laisse sans groupe.

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

Affiche ou masque un groupe entier, ou n’en affiche qu’un.

frameGroup(id)Promise<void>

Cadre la caméra sur un groupe, membres masqués compris.

Mesures

setMeasureTool(tool)Promise<void>

Arme un outil de mesure pour le visiteur (ouvre le panneau Mesurer), ou 'none'. Les résultats arrivent sur measurements-changed.

getMeasurements()Promise<MeasurementsState>

Toutes les mesures à l'écran. Valeurs en SI — mètres, m², degrés — quel que soit l'affichage.

clearMeasurements(id?)Promise<MeasurementsState>

Retire une mesure, ou toutes.

Requêtes

getModels()Promise<ModelSummary[]>

Liste les modèles chargés. Renvoie une promesse.

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

Trouver des éléments par classe IFC, GlobalId et/ou nom dans les modèles chargés. Chaque résultat contient ce qu’attendent getElement(), select() et frame().

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

Par expressID ou GlobalId. Les données IFC d’un élément : attributs avec le GlobalId, ses jeux de propriétés et quantités, et ceux de son type — typeName, typeProperties — avec unités. effectivePropertySets fusionne les deux, la valeur propre de l’élément l’emporte.

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

Valider un modèle maintenant (par défaut l’actif) et résoudre avec son Health Score et le nombre d’anomalies. Rejette avec la raison.

getValidation()Promise<ValidationSummary | null>

Le résultat de validation affiché, ou null avant qu’une exécution en ait produit un. Voir « Cycle de la validation ».

getValidationStatus()Promise<ValidationStatus>

Où en est la validation : idle, running (avec progression), done ou error.

getStats()Promise<StatsResult>

Nombre d’éléments par catégorie et par modèle — pour les graphiques. Renvoie une promesse.

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

Anomalies de validation pour un tableau (filtre par sévérité / limite). Renvoie une promesse.

screenshot()Promise<string>

Capture la vue 3D actuelle en data URL PNG. Renvoie une promesse.

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

Compare deux livraisons par URL (par GlobalId) et ouvre l’espace de comparaison sur le résultat.

Panneaux

openPanel(panel | null) · closePanel()void

Ouvre un panneau d'outil, ou null pour fermer celui qui est ouvert. Un panneau indisponible — masqué par le chrome, ou sans contenu sur lequel agir — ne fait rien et n'est pas une erreur.

getPanels()Promise<PanelsResult>

Quel panneau est ouvert et lesquels sont proposés à cet instant. Un outil absent de `available` ne peut pas être ouvert ; il n'est pas simplement désactivé.

setPanels(panels)void

Limite la barre à ces panneaux, à l'exécution. Même vocabulaire que le paramètre d'URL `panels=`, et il prime sur lui. Restreint ce que le visualiseur propose et n'ajoute jamais ; un tableau vide signifie aucune barre.

Nuages de points

addPointCloud(fileName, bytes)Promise<string>

Charge un relevé depuis des octets — LAS, LAZ, COPC, PLY, PCD ou texte. Le tampon est transféré, pas copié. Résout avec l'identifiant du nuage.

addPointCloudFromUrl(url, fileName?)Promise<string>

Charge un relevé que le visualiseur récupère lui-même. L'URL doit autoriser CORS.

listPointClouds()Promise<PointCloudInfo[]>

Tous les relevés chargés. `pointCount` est ce qui réside en mémoire, `declaredCount` ce que contient le fichier — ils diffèrent quand le budget a tronqué l'analyse.

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

Décharge un relevé et libère ses tampons GPU, ou décharge-les tous.

setPointCloudVisible(cloudId, visible)Promise<void>

Affiche ou masque un relevé sans le décharger.

fitPointCloud(cloudId?)Promise<void>

Cadre la caméra sur un relevé, ou sur le premier chargé.

setPointCloudDisplay(display, renderBudget?)Promise<void>

Taille des points, opacité, mode de couleur, densité, seuil de confiance — partagés par tous les relevés. Chacun est un uniform de shader, donc instantané sur 20 millions de points.

inspectPointCloud(enabled?)Promise<void>

Arme le clic-pour-lire. Une fois armé, cliquer un point émet `pointcloud-picked` avec les coordonnées DU FICHIER à côté de celles de la scène.

setPointCloudPlacement(placement, cloudId?)Promise<void>

Ajuste un relevé à la main : position, lacet, mise à niveau, échelle. Partiel et borné ; s'applique par-dessus l'alignement déduit sans le remplacer.

setPointCloudUpAxis(axis, cloudId?)Promise<void>

Corrige l'axe que le relevé considère comme vertical. PLY, PCD et texte ne déclarent aucune orientation, le visualiseur la déduit — vérifiez `upAxisSource`.

Imported 3D models

addMesh(files)Promise<string>

Importe un modèle depuis des octets. Prend une LISTE : un .gltf a besoin de son .bin et de ses textures, un .obj de son .mtl — seul, le fichier d'entrée donne de la géométrie grise.

addMeshFromUrl(urls)Promise<string>

Importe un modèle que le visualiseur récupère. Passez toutes les URL nécessaires ; elles sont récupérées en parallèle et doivent toutes autoriser CORS.

listMeshes()Promise<MeshInfo[]>

Tous les modèles importés, avec leurs nombres de triangles et de textures. Lisez `unitSource` et `upAxisSource` avant de faire confiance aux valeurs voisines.

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

Retire un import et libère sa géométrie, ses matériaux et ses textures, ou retire-les tous.

setMeshVisible(visible, meshId?)Promise<void>

Affiche ou masque un import sans le décharger.

fitMesh(meshId?)Promise<void>

Cadre la caméra sur un import, ou sur tous.

setMeshPlacement(placement, meshId?)Promise<void>

Place un import à la main : position, lacet, mise à niveau, échelle. Partiel et borné. Un import démarre centré sur l'IFC, posé sur son sol.

setMeshUpAxis(axis, meshId?)Promise<void>

Corrige l'axe vertical de la source. Utile seulement pour OBJ — la spécification glTF impose Y vers le haut, elle rapporte donc `upAxisSource: 'declared'`.

setMeshUnit(unitScale, meshId?)Promise<void>

Corrige l'unité source : 1 mètres, 0,01 centimètres, 0,001 millimètres, 0,3048 pieds. Aucun de ces formats ne l'enregistre, le visualiseur la déduit de la taille du modèle.

Conformité IDS et EIR

checkIds(idsXml)Promise<IdsResult>

Vérifie le modèle par rapport à un IDS buildingSMART (XML .ids). S’exécute dans un worker. Renvoie réussite/échec par spécification.

checkEir(profile)Promise<IdsResult>

Vérifie la maquette avec un profil de validation EIR / BIM — un objet, son JSON (y compris la forme compacte) ou l'id d'un profil intégré comme 'builtin-en14351-1'. Compilé en IDS et exécuté par le même moteur : même IdsResult que checkIds.

Langues

setLanguage(lang)void

Changer la langue de l'interface à l'exécution.

getLanguages()string[]

Lister les codes de langue pris en charge (libellés via IfcViewer.LANGUAGES).

Cycle de vie et événements

whenReady()Promise<void>

Se résout quand le visualiseur peut accepter des commandes.

isReadyboolean

Getter — true dès que le visualiseur a signalé qu’il est prêt.

on(event, cb)() => void

S’abonner à un événement ; renvoie une fonction de désabonnement.

off(event, cb)void

Supprime un écouteur d’événement ajouté précédemment.

dispose()void

Démonter le visualiseur et retirer l’iframe.

Les appels concurrents à add() / addFromUrl() sont sérialisés en interne et chaque promesse est corrélée à son propre chargement — un chargement initié par l’application (paramètre d’URL, téléversement dans l’iframe) ne résout jamais votre promesse add().

Options du constructeur

OptionTypePar défautDescription
ui'minimal' | 'full' | 'kiosk' | 'client' | 'article' | 'embed''minimal'Preset de l’interface. 'embed' : pour une app hôte qui fournit le fichier — 3D, propriétés à la sélection, une barre compacte avec Valider et Mesurer ; sans Ouvrir, Partager, compte ni langue.
toolbarbooleanpresetAfficher la barre d’outils (par défaut, celle du preset). false laisse la vue 3D et les panneaux.
tools('validate' | 'measure')[]['validate', 'measure']Outils de la barre compacte de ui: 'embed' — 'validate', 'measure'. [] pour aucun.
autoFramebooleantrueCadrer toute la scène en iso, avec une marge, à chaque fin de chargement. false vous laisse la caméra.
validatebooleantrueLancer la validation au chargement (alimente le Health Score).
panelbooleanfalseOuvrir automatiquement le panneau de validation.
panelsPanelName[]—Limite la barre d'outils à ces panneaux, dès la première image — `['scene','map']`, ou `[]` pour aucune barre. Mêmes noms que setPanels et que le paramètre d'URL `panels=`. Préférable à un setPanels après chargement, qui affiche la barre complète puis retire des outils.
langstringautoForcer la langue de l’interface (ex. en, es, ja).
accent#rrggbbbrandTeinter le visualiseur aux couleurs de votre tableau de bord.
modelstring—Charger automatiquement cette URL IFC publique dès que possible.
backgroundBackgroundSpec—Fond de scène dès la première image — un préréglage, '#rrggbb' ou '#haut,#bas'.
mapboolean | ('terrain' | 'buildings' | 'showcase')[]—Place le modèle sur la carte au chargement : true, ou les couches ['terrain','buildings','showcase'].
solar · moon'MM-DDTHH:MM' · boolean—Ouvre l'étude solaire à une heure locale du site : '06-21T18:00'.
scansstring[]—URL de nuages de points à charger avec le modèle.
layersstring—Configuration de couches de données à ouvrir : l’URL d’un JSON exporté depuis le panneau Couches de données (sources en direct, styles, alertes). Depuis 1.16.
scenestring—Scène à ouvrir : l’URL d’un document de scène (modèles, couches de données, appareils en direct, carte, caméra). Depuis 1.17.
view · fillCameraView · number—Une fois tous les modèles chargés, les cadrer serré depuis cette vue. ui: 'article' implique 'iso'.
wheel'always' | 'ctrl''always''ctrl' : la molette fait défiler votre page et ne zoome qu’avec Ctrl/⌘, comme une carte intégrée. ui: 'article' l’implique.
lazyboolean | 'visible'falseNe rien charger avant d’en avoir besoin : true affiche une affiche avec bouton, 'visible' démarre à l’approche de l’écran.
poster · posterTitle · posterText · launchLabelstring—Image, titre, texte et libellé du bouton de l’affiche, jusqu’à ce que la visionneuse soit prête.
aspectRatiostring ('16/10')—Taille par proportion ('16/10') : affiche et visionneuse partagent la boîte, rien ne bouge sur la page.
turntableboolean | numberfalseLente rotation au repos après chargement (true = 6°/s, ou degrés par seconde).
pauseOffscreenbooleanui === 'article'Ne plus rendre hors écran. true par défaut avec ui: 'article'.
fullscreenButtonbooleanfalseUn petit bouton d’agrandissement dans le coin.
height · widthnumber | string'100%'Taille de l’iframe (nombre → px).
baseUrlstringautoURL de base de l’application. Déduite de l’URL du script.
loadTimeoutnumber120000Rejeter add()/addFromUrl() après N ms (0 désactive).
className · titlestring—Classe supplémentaire / title de l’iframe.
on* callbacksfunction—Callbacks pratiques — équivalents à .on(...).

Événements

ÉvénementPayloadDescription
ready{ languages }Visualiseur monté et prêt.
model-progress{ percent, phase }Progression du chargement (téléchargement → analyse → rendu).
model-loaded{ modelId, fileName, elementCount, fromCache }Un modèle a fini de charger.
validation-started{ modelId }Une validation a commencé sur un modèle — après un chargement (validate: true) ou via validate().
validation-completed{ modelId, qualityScore, errors, warnings, info, total }Validation terminée : le Health Score et les comptes, et le modèle concerné (null pour l’agrégat fédéré).
validation-failed{ modelId, message }Une validation n’a pas pu s’exécuter ou n’a pas abouti — avec la raison.
model-error{ message, url?, name? }Un chargement a échoué.
element-selected{ expressId, modelId, ifcType, name, globalId }L’utilisateur a choisi un élément — avec son GlobalId, pour le relier à vos propres données.
pointcloud-picked{ cloudId, position, sourcePosition, classification, intensity, distance }Un point a été lu sur un scan, dans les coordonnées du fichier et non de la scène.
map-feature-picked{ id, name?, label?, featureKind, heightM?, heightEstimated }Un bâtiment des environs OpenStreetMap a été cliqué. Du contexte, pas le modèle.
walk-changed{ active, speed }Le mode visite a été activé ou désactivé — par le visiteur ou par l’hôte.
measurements-changed{ tool, units, items }Une mesure a été ajoutée, retirée ou renommée. Contient la liste complète.
tour-started{ title, total, template }Une visite a commencé.
tour-step{ index, total, caption }La visite est passée à un autre arrêt.
tour-ended{ completed }La visite s’est arrêtée ; completed si le dernier arrêt était atteint.
presentation-progress{ stage, label?, progress }Le réalisateur génère ou exporte une présentation.
layer-feature-picked{ layerId, layer, featureId, geometry, lonLat, properties }Une entité d’une couche de données a été cliquée : sa couche, ses propriétés et un point à marquer.
alert{ kind, from, id, name, rule, count, sample }Une règle d’une couche de données ou du jumeau a commencé ou cessé d’alerter.

Membres statiques

IfcViewer.LANGUAGES ({ code, label }[], noms natifs) et IfcViewer.SUPPORTED_LANGUAGES (codes) — pour construire un sélecteur de langue avant que le visualiseur ne soit prêt.

Web component

Zéro JavaScript — placez la balise dans n’importe quelle page ou tableau de bord et définissez les attributs.

Attributs: modeluilangaccentvalidatepanelbase-urltoolbartoolsauto-frame

Les événements sont réémis en CustomEvents DOM nommés ifcviewer:<type> (detail = payload). L’IfcViewer sous-jacent est sur le .viewer de l’élément ; getStats / getIssues / screenshot y sont délégués.

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

Guides

Recettes

Des motifs à copier-coller pour ce que les équipes construisent vraiment.

Inspecteur d’éléments

Cliquez dans la 3D et versez les property sets IFC dans votre propre panneau.

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

Widget Health Score

Affichez le score de qualité du modèle et le nombre d’anomalies dans votre tableau de bord.

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

Contrôle de conformité IDS

Validez contre un IDS buildingSMART et listez réussite / échec par spécification.

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)));
});

Validation EIR / BIM

Exécutez un profil EIR modifiable (style ISO 19650) — sans fichier .ids. Les échecs portent le GlobalId de l’élément.

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(" · ")));
});

Une scène pour un article de blog

Fond blanc, le modèle sur son site et l’ombre du soir du solstice d’été — déclaré d’avance, sans clic.

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

Plan et mesures

Coupez un plan à un niveau nommé, laissez le lecteur mesurer, puis relisez les résultats en unités SI.

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)));
});

Une visite guidée dans un article

Définissez les arrêts une fois avec getCamera(), puis laissez la visite défiler seule à côté du texte.

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));

Une vidéo du modèle, depuis votre page

Générez une présentation avec une recette et récupérez le MP4 — sans capture d’écran, sans téléversement.

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 }));

Une couverture pour votre article

Générez une épingle Pinterest ou une carte LinkedIn du modèle avec votre titre et récupérez le PNG.

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 }));

Un modèle dans un article

ui: 'article', c’est le canevas seul, cadré pour que le modèle le remplisse, avec une molette qui laisse le lecteur continuer à défiler. L’angle se choisit avec 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,
});

Une histoire qui avance avec le texte

Épinglez la visionneuse et laissez chaque paragraphe choisir le plan : isoler les murs, tourner autour, faire venir le soleil du soir.

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" } },
]);

Un jumeau urbain en direct dans votre page

Ouvrir une scène publiée, réagir à ses alertes et à ses clics, ajouter votre propre source en direct à côté et partager un lien vers le résultat.

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" });

Une fiche produit dans votre app

Figez la version, transmettez le fichier et montrez ce que le fabricant a mis dans le type : coefficient U, classe de vent, fabricant.

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);

Aux couleurs de votre marque

Alignez le visualiseur sur votre produit avec une seule couleur d’accent.

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

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

Sélecteur de langue

Construisez un sélecteur à partir des langues livrées avec le visualiseur.

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

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

Health Score

Cycle de la validation

validate: true valide chaque modèle une fois chargé ; validate() la lance à la demande et résout avec le résultat. Ce que renvoie getValidation() à chaque moment :

QuandgetValidation() renvoie
Avant toute validationnull — getValidationStatus() indique idle.
Pendant la première exécutionnull — getValidationStatus() indique running, avec la progression ; validation-started a été émis.
Après une exécution{ qualityScore, errors, warnings, info, total, status: 'done', modelId }. Avec plusieurs modèles, l’agrégat (modelId: null).
Pendant une exécution plus récenteLes chiffres précédents, avec status: 'running'.
Après un échecLes chiffres précédents avec status: 'error' et error — ou null s’il n’y en avait pas. validation-failed a été émis et validate() a rejeté.

Versions

Figer une version

Depuis la 1.18.0, chaque version est aussi publiée à un chemin qui ne change jamais. Figez-la en production ; le chemin mobile suit la dernière version.

HTML
<script type="module">
  import { IfcViewer } from "https://www.ifcvieweronline.eu/sdk/1.18.0/ifc-viewer.es.js";
</script>
CheminCacheUsage
/sdk/ifc-viewer.es.jsrevalidé à chaque chargementPour essayer — toujours la dernière.
/sdk/1.18.0/ifc-viewer.es.jsimmuable, en cache un anProduction — le code testé est le code exécuté.

Quelle visionneuse ouvre un SDK figé ?

L’iframe est la visionneuse en direct de la même origine, pas une copie figée : un SDK figé garde son API et son comportement tandis que la visionneuse continue de s’améliorer. Elle répond à chaque commande de tout SDK publié — le build le vérifie —, donc une ancienne version figée continue de fonctionner.

Figer aussi le contenu

versions.json, à côté du SDK, liste le hash Subresource Integrity de chaque 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>

Journal des modifications

1.18.0 — objets de catalogue dans une app hôte. getElement() renvoie le GlobalId et les données du type (typeName, typeProperties avec unités, effectivePropertySets ; types IFC4 et styles IFC2x3). validate(), getValidationStatus(), validation-started / validation-failed, et validate: true valide vraiment après chaque chargement. Cadrage automatique après chargement, fit() et frame() avec marge pour les petits objets, frame(elementId), et setView() déplace de nouveau la caméra. ui: 'embed' avec toolbar et tools. Versions figées sous /sdk/1.18.0/. findElements(), GlobalIds pour getElement() / select() / element-selected, jeux de dormant et d’ouvrant des fenêtres et portes, et matériaux du type ; en ui: 'embed' le panneau de propriétés garde l’objet choisi visible. checkEir('builtin-en14351-1') vérifie les performances déclarées des fenêtres et portes extérieures selon l'EN 14351-1 — vent, étanchéité à l'eau, acoustique, transmission thermique, g et τv, fabricant et code produit — dans les property sets IFC standard ; les règles EIR gagnent where (seulement les éléments ayant une valeur de propriété) et optional.

Aide

Dépannage

Les quelques points sur lesquels on trébuche.

Rien ne s’affiche

Vérifiez, dans cet ordre : que le visualiseur a atteint ready, que le modèle s’est chargé (model-loaded plutôt que model-error), que le conteneur a une hauteur non nulle et que la source d’octets est bien de l’IFC valide. Le message de model-error nomme la cause.

J’obtiens une erreur CORS au chargement d’un modèle

CORS ne concerne que addFromUrl(url). Si vous maîtrisez les octets, récupérez-les vous-même et appelez add(name, bytes) — CORS ne s’applique pas puisque vous transmettez les données directement.

L’iframe reste blanc ou refuse de se charger

L’application doit être intégrable — pas de X-Frame-Options: DENY ni de CSP frame-ancestors restrictive sur l’hôte. Notre application hébergée autorise l’intégration.

Mon ArrayBuffer est vide après add()

add() transfère le buffer pour une remise sans copie, ce qui le détache dans votre code. Passez une copie (bytes.slice(0)) si vous avez encore besoin des octets ensuite.

Les chargements ou les requêtes expirent

add()/addFromUrl() échouent après loadTimeout (120 s par défaut ; 0 désactive). Les requêtes échouent après 30 s, checkIds après 120 s. De gros modèles sur des appareils lents peuvent nécessiter un loadTimeout plus élevé.

Quels navigateurs sont pris en charge ?

Tout navigateur moderne à mises à jour continues avec WebAssembly et modules ES — Chrome, Edge, Firefox, Safari. Pas Internet Explorer.

J’obtiens un 404 sur mon serveur de développement local

Un serveur de développement SPA peut intercepter /sdk/ avec son fallback HTML. Testez contre un vrai build ou un hébergement statique, ou importez directement le module /sdk/ifc-viewer.es.js.