web-ifc Engine: Direct WASM IFC Parser
Overview
web-ifc is the WASM-powered IFC parsing engine beneath the ThatOpen component stack. It reads and writes IFC files at native speed in browser and Node.js environments. The central class is IfcAPI.
When using ThatOpen components (@thatopen/components), you rarely call web-ifc directly — the IfcLoader component wraps it. Use this skill when you need low-level IFC access, custom geometry extraction, or bulk property queries outside the component framework.
Critical Warnings
- ALWAYS call
Init() before any other method (except SetWasmPath). Every method silently fails or throws without WASM initialization.
- ALWAYS call
CloseModel(modelID) when done — each open model holds significant WASM heap memory. Forgetting this causes memory leaks that crash browser tabs.
- ALWAYS use
.size() and .get(i) for Vector<T> access — NEVER use array indexing ([]). WASM vectors are not JavaScript arrays.
- ALWAYS call
Dispose() when the IfcAPI instance is no longer needed — this releases the entire WASM module.
- NEVER create multiple
IfcAPI instances — one instance handles multiple models. Extra instances waste memory by loading duplicate WASM modules.
- Vertex format is 6 floats per vertex:
[x, y, z, nx, ny, nz] — position followed by normal. ALWAYS account for this interleaved layout when extracting geometry.
- All 4x4 matrices are column-major (16 floats) — directly compatible with
THREE.Matrix4.fromArray().
Quick Start
import * as WebIFC from "web-ifc";
const ifcApi = new WebIFC.IfcAPI();
ifcApi.SetWasmPath("/wasm/"); // MUST be called before Init()
await ifcApi.Init();
const data = new Uint8Array(buffer); // from fetch or fs.readFile
const modelID = ifcApi.OpenModel(data);
// Query walls
const wallIDs = ifcApi.GetLineIDsWithType(modelID, WebIFC.IFCWALL);
for (let i = 0; i < wallIDs.size(); i++) {
const wall = ifcApi.GetLine(modelID, wallIDs.get(i));
console.log(wall.Name?.value);
}
// Get geometry
const mesh = ifcApi.GetFlatMesh(modelID, wallIDs.get(0));
// Get coordination matrix
const matrix = ifcApi.GetCoordinationMatrix(modelID);
ifcApi.CloseModel(modelID); // ALWAYS free memory
Initialization
SetWasmPath(path: string, absolute?: boolean): void
Sets the directory containing WASM files. MUST be called before Init(). The directory MUST contain web-ifc.wasm (and web-ifc-mt.wasm for multi-threaded mode).
ifcApi.SetWasmPath("/static/wasm/"); // relative
ifcApi.SetWasmPath("https://cdn.example.com/wasm/", true); // absolute URL
NEVER hardcode a version in the WASM path — ALWAYS match the installed web-ifc npm version.
Init(customLocateFileHandler?, forceSingleThread?): Promise<void>
Initializes the WASM module. MUST be awaited before calling any other API method.
await ifcApi.Init(); // default (auto-detect threading)
await ifcApi.Init(undefined, true); // force single-threaded
await ifcApi.Init((path, prefix) => "/custom/" + path); // custom file locator
Dispose(): void
Releases the entire WASM module and all resources. Call when the IfcAPI instance is no longer needed.
Model Lifecycle
| Method |
Signature |
Purpose |
OpenModel |
(data: Uint8Array, settings?: LoaderSettings) => number |
Load IFC from buffer, returns modelID |
OpenModels |
(dataSets: Uint8Array[], settings?) => number[] |
Load multiple IFC files at once |
OpenModelFromCallback |
(callback: ModelLoadCallback, settings?) => number |
Stream-load without full buffer in memory |
CreateModel |
(model: NewIfcModel, settings?) => number |
Create empty IFC model |
SaveModel |
(modelID: number) => Uint8Array |
Serialize model to IFC bytes |
CloseModel |
(modelID: number) => void |
Free all WASM memory for this model |
IsModelOpen |
(modelID: number) => boolean |
Check if model is open |
LoaderSettings
interface LoaderSettings {
COORDINATE_TO_ORIGIN?: boolean; // translate model to origin (recommended)
USE_FAST_BOOLS?: boolean; // faster but less accurate boolean ops
CIRCLE_SEGMENTS_LOW?: number; // tessellation for small curves
CIRCLE_SEGMENTS_MEDIUM?: number; // tessellation for medium curves
CIRCLE_SEGMENTS_HIGH?: number; // tessellation for large curves
BOOL_ABORT_THRESHOLD?: number; // timeout (ms) for boolean operations
MEMORY_LIMIT?: number; // WASM memory limit in bytes
}
ALWAYS use COORDINATE_TO_ORIGIN: true for models with large world coordinates — prevents floating-point precision issues in rendering.
Data Queries
Core Query Methods
| Method |
Returns |
Purpose |
GetAllLines(modelID) |
Vector<number> |
All expressIDs in the model |
GetLineIDsWithType(modelID, type, includeInherited?) |
Vector<number> |
ExpressIDs by IFC type |
GetLine(modelID, expressID, flatten?, inverse?, inversePropKey?) |
any |
Single entity by expressID |
GetLines(modelID, expressIDs, flatten?, inverse?, inversePropKey?) |
any[] |
Batch entity retrieval |
GetRawLineData(modelID, expressID) |
RawLineData |
Raw unparsed data (faster) |
GetLineType(modelID, expressID) |
number |
IFC type code only |
GetMaxExpressID(modelID) |
number |
Highest expressID |
GetNextExpressID(modelID, expressID) |
number |
Next valid expressID |
GetLine Parameters
| Parameter |
Type |
Default |
Description |
flatten |
boolean |
false |
Recursively resolve all references inline |
inverse |
boolean |
false |
Include inverse relationships |
inversePropKey |
string? |
null |
Filter inverse props to specific key |
NEVER use flatten: true on large models without limiting scope — it recursively resolves every reference and causes severe performance degradation.
Schema & Type Information
| Method |
Returns |
Purpose |
GetModelSchema(modelID) |
string |
Schema version ("IFC2X3", "IFC4", "IFC4X3") |
GetAllTypesOfModel(modelID) |
IfcType[] |
All IFC types present in model |
GetHeaderLine(modelID, headerType) |
any |
IFC header info |
Geometry Extraction
Single-Element Geometry
const flatMesh = ifcApi.GetFlatMesh(modelID, expressID);
for (let i = 0; i < flatMesh.geometries.size(); i++) {
const pg = flatMesh.geometries.get(i);
const geom = ifcApi.GetGeometry(modelID, pg.geometryExpressID);
const verts = ifcApi.GetVertexArray(geom.GetVertexData(), geom.GetVertexDataSize());
const indices = ifcApi.GetIndexArray(geom.GetIndexData(), geom.GetIndexDataSize());
// verts: Float32Array — 6 floats per vertex [x, y, z, nx, ny, nz]
// indices: Uint32Array — triangle indices
// pg.color: { x, y, z, w } — RGBA (w = alpha)
// pg.flatTransformation: number[] — 4x4 column-major transform matrix
}
Geometry Streaming (Memory-Efficient)
ALWAYS prefer streaming over LoadAllGeometry for models with more than a few hundred elements.
| Method |
Purpose |
StreamAllMeshes(modelID, callback) |
Stream ALL meshable entities |
StreamAllMeshesWithTypes(modelID, types[], callback) |
Stream filtered by IFC types |
StreamMeshes(modelID, expressIDs[], callback) |
Stream specific elements |
LoadAllGeometry(modelID) |
Load all at once (AVOID for large models) |
Callback signature: (mesh: FlatMesh, index: number, total: number) => void
Coordination & Transforms
| Method |
Purpose |
GetCoordinationMatrix(modelID) |
4x4 matrix for multi-model alignment |
SetGeometryTransformation(modelID, matrix) |
Apply global transform to all geometry output |
GetWorldTransformMatrix(modelID, placementExpressId) |
Transform for specific placement |
Properties Helper
The ifcApi.properties object provides high-level async methods for property queries.
| Method |
Returns |
Purpose |
getItemProperties(modelID, id, recursive?, inverse?) |
Promise<any> |
All properties for an element |
getPropertySets(modelID, elementID?, recursive?) |
Promise<any[]> |
Property sets (Psets) |
getTypeProperties(modelID, elementID?, recursive?) |
Promise<any[]> |
Type object properties |
getMaterialsProperties(modelID, elementID?, recursive?) |
Promise<any[]> |
Material definitions |
getSpatialStructure(modelID, includeProperties?) |
Promise<Node> |
Full spatial hierarchy tree |
The spatial structure returns a tree: { expressID, type, children: [...] }.
GUID Utilities
| Method |
Purpose |
GetExpressIdFromGuid(modelID, guid) |
Convert IFC GUID string to expressID |
GetGuidFromExpressId(modelID, expressID) |
Convert expressID to IFC GUID string |
CreateIfcGuidToExpressIdMapping(modelID) |
Pre-build mapping for faster lookups |
ALWAYS call CreateIfcGuidToExpressIdMapping first if performing many GUID lookups — it builds an index that makes subsequent calls faster.
Writing Data
| Method |
Purpose |
WriteLine(modelID, lineObject) |
Write or update a single entity |
WriteLines(modelID, lineObjects[]) |
Batch write |
DeleteLine(modelID, expressID) |
Remove entity from model |
CreateIfcEntity(modelID, type, ...args) |
Create new IFC entity |
After modifications, use SaveModel(modelID) to serialize back to IFC format.
Logging
import { LogLevel } from "web-ifc";
ifcApi.SetLogLevel(LogLevel.LOG_LEVEL_OFF); // silent (recommended for production)
ifcApi.SetLogLevel(LogLevel.LOG_LEVEL_ERROR); // errors only
ifcApi.SetLogLevel(LogLevel.LOG_LEVEL_DEBUG); // verbose debugging
Key Types
See references/methods.md for complete type definitions.
| Type |
Description |
FlatMesh |
Triangulated geometry result: { expressID, geometries: Vector<PlacedGeometry> } |
PlacedGeometry |
Single geometry piece: color (RGBA), transform (4x4), geometryExpressID |
IfcGeometry |
Raw WASM geometry: GetVertexData/Size(), GetIndexData/Size() |
Vector<T> |
WASM vector: access via .size() and .get(i) ONLY |
RawLineData |
Unparsed entity: { ID, type, arguments } |
LoaderSettings |
Model loading configuration |
IfcType |
Type descriptor: { typeID, typeName } |
Common IFC Type Constants
import {
// Structural
IFCWALL, IFCWALLSTANDARDCASE, IFCSLAB, IFCBEAM, IFCCOLUMN,
// Openings
IFCDOOR, IFCWINDOW, IFCOPENINGELEMENT,
// Building elements
IFCROOF, IFCSTAIR, IFCFURNISHINGELEMENT,
// Spatial hierarchy
IFCPROJECT, IFCSITE, IFCBUILDING, IFCBUILDINGSTOREY, IFCSPACE,
// Properties & relations
IFCPROPERTYSET, IFCPROPERTYSINGLEVALUE,
IFCRELDEFINESBYPROPERTIES, IFCRELCONTAINEDINSPATIALSTRUCTURE,
IFCRELAGGREGATES, IFCRELVOIDSELEMENT,
} from "web-ifc";
References
references/methods.md — Complete IfcAPI method signatures and type definitions
references/examples.md — Full working examples: init, load, query, geometry, properties
references/anti-patterns.md — Common failures: WASM init, memory leaks, Vector access
Sources
1---2name: thatopen-core-web-ifc3description: Use when working with web-ifc directly for IFC parsing, querying IFC entities, extracting geometry, or understanding the WASM engine beneath ThatOpen components. Prevents WASM initialization failures and memory leaks from unclosed models. Covers IfcAPI, SetWasmPath, Init, OpenModel, GetLine, GetFlatMesh, StreamAllMeshes, properties helper, LoaderSettings, schema detection. Keywords: web-ifc, wasm, ifc, parser, ifcapi, geometry, properties, spatial structure, express id, flatmesh, parse IFC in browser, read IFC JavaScript, IFC web.4license: MIT5---67# web-ifc Engine: Direct WASM IFC Parser89## Overview1011web-ifc is the WASM-powered IFC parsing engine beneath the ThatOpen component stack. It reads and writes IFC files at native speed in browser and Node.js environments. The central class is `IfcAPI`.1213- **Package**: `web-ifc` (npm)14- **Source**: https://github.com/ThatOpen/engine_web-ifc15- **Environments**: Browser, Node.js (single-threaded and multi-threaded WASM)16- **License**: MPL-2.01718> When using ThatOpen components (`@thatopen/components`), you rarely call web-ifc directly — the `IfcLoader` component wraps it. Use this skill when you need low-level IFC access, custom geometry extraction, or bulk property queries outside the component framework.1920---2122## Critical Warnings23241. **ALWAYS call `Init()` before any other method** (except `SetWasmPath`). Every method silently fails or throws without WASM initialization.252. **ALWAYS call `CloseModel(modelID)` when done** — each open model holds significant WASM heap memory. Forgetting this causes memory leaks that crash browser tabs.263. **ALWAYS use `.size()` and `.get(i)` for `Vector<T>` access** — NEVER use array indexing (`[]`). WASM vectors are not JavaScript arrays.274. **ALWAYS call `Dispose()` when the IfcAPI instance is no longer needed** — this releases the entire WASM module.285. **NEVER create multiple `IfcAPI` instances** — one instance handles multiple models. Extra instances waste memory by loading duplicate WASM modules.296. **Vertex format is 6 floats per vertex**: `[x, y, z, nx, ny, nz]` — position followed by normal. ALWAYS account for this interleaved layout when extracting geometry.307. **All 4x4 matrices are column-major** (16 floats) — directly compatible with `THREE.Matrix4.fromArray()`.3132---3334## Quick Start3536```typescript37import * as WebIFC from "web-ifc";3839const ifcApi = new WebIFC.IfcAPI();40ifcApi.SetWasmPath("/wasm/"); // MUST be called before Init()41await ifcApi.Init();4243const data = new Uint8Array(buffer); // from fetch or fs.readFile44const modelID = ifcApi.OpenModel(data);4546// Query walls47const wallIDs = ifcApi.GetLineIDsWithType(modelID, WebIFC.IFCWALL);48for (let i = 0; i < wallIDs.size(); i++) {49 const wall = ifcApi.GetLine(modelID, wallIDs.get(i));50 console.log(wall.Name?.value);51}5253// Get geometry54const mesh = ifcApi.GetFlatMesh(modelID, wallIDs.get(0));5556// Get coordination matrix57const matrix = ifcApi.GetCoordinationMatrix(modelID);5859ifcApi.CloseModel(modelID); // ALWAYS free memory60```6162---6364## Initialization6566### `SetWasmPath(path: string, absolute?: boolean): void`6768Sets the directory containing WASM files. MUST be called **before** `Init()`. The directory MUST contain `web-ifc.wasm` (and `web-ifc-mt.wasm` for multi-threaded mode).6970```typescript71ifcApi.SetWasmPath("/static/wasm/"); // relative72ifcApi.SetWasmPath("https://cdn.example.com/wasm/", true); // absolute URL73```7475NEVER hardcode a version in the WASM path — ALWAYS match the installed `web-ifc` npm version.7677### `Init(customLocateFileHandler?, forceSingleThread?): Promise<void>`7879Initializes the WASM module. MUST be awaited before calling any other API method.8081```typescript82await ifcApi.Init(); // default (auto-detect threading)83await ifcApi.Init(undefined, true); // force single-threaded84await ifcApi.Init((path, prefix) => "/custom/" + path); // custom file locator85```8687### `Dispose(): void`8889Releases the entire WASM module and all resources. Call when the IfcAPI instance is no longer needed.9091---9293## Model Lifecycle9495| Method | Signature | Purpose |96|---|---|---|97| `OpenModel` | `(data: Uint8Array, settings?: LoaderSettings) => number` | Load IFC from buffer, returns modelID |98| `OpenModels` | `(dataSets: Uint8Array[], settings?) => number[]` | Load multiple IFC files at once |99| `OpenModelFromCallback` | `(callback: ModelLoadCallback, settings?) => number` | Stream-load without full buffer in memory |100| `CreateModel` | `(model: NewIfcModel, settings?) => number` | Create empty IFC model |101| `SaveModel` | `(modelID: number) => Uint8Array` | Serialize model to IFC bytes |102| `CloseModel` | `(modelID: number) => void` | Free all WASM memory for this model |103| `IsModelOpen` | `(modelID: number) => boolean` | Check if model is open |104105### LoaderSettings106107```typescript108interface LoaderSettings {109 COORDINATE_TO_ORIGIN?: boolean; // translate model to origin (recommended)110 USE_FAST_BOOLS?: boolean; // faster but less accurate boolean ops111 CIRCLE_SEGMENTS_LOW?: number; // tessellation for small curves112 CIRCLE_SEGMENTS_MEDIUM?: number; // tessellation for medium curves113 CIRCLE_SEGMENTS_HIGH?: number; // tessellation for large curves114 BOOL_ABORT_THRESHOLD?: number; // timeout (ms) for boolean operations115 MEMORY_LIMIT?: number; // WASM memory limit in bytes116}117```118119ALWAYS use `COORDINATE_TO_ORIGIN: true` for models with large world coordinates — prevents floating-point precision issues in rendering.120121---122123## Data Queries124125### Core Query Methods126127| Method | Returns | Purpose |128|---|---|---|129| `GetAllLines(modelID)` | `Vector<number>` | All expressIDs in the model |130| `GetLineIDsWithType(modelID, type, includeInherited?)` | `Vector<number>` | ExpressIDs by IFC type |131| `GetLine(modelID, expressID, flatten?, inverse?, inversePropKey?)` | `any` | Single entity by expressID |132| `GetLines(modelID, expressIDs, flatten?, inverse?, inversePropKey?)` | `any[]` | Batch entity retrieval |133| `GetRawLineData(modelID, expressID)` | `RawLineData` | Raw unparsed data (faster) |134| `GetLineType(modelID, expressID)` | `number` | IFC type code only |135| `GetMaxExpressID(modelID)` | `number` | Highest expressID |136| `GetNextExpressID(modelID, expressID)` | `number` | Next valid expressID |137138### `GetLine` Parameters139140| Parameter | Type | Default | Description |141|---|---|---|---|142| `flatten` | `boolean` | `false` | Recursively resolve all references inline |143| `inverse` | `boolean` | `false` | Include inverse relationships |144| `inversePropKey` | `string?` | `null` | Filter inverse props to specific key |145146NEVER use `flatten: true` on large models without limiting scope — it recursively resolves every reference and causes severe performance degradation.147148### Schema & Type Information149150| Method | Returns | Purpose |151|---|---|---|152| `GetModelSchema(modelID)` | `string` | Schema version ("IFC2X3", "IFC4", "IFC4X3") |153| `GetAllTypesOfModel(modelID)` | `IfcType[]` | All IFC types present in model |154| `GetHeaderLine(modelID, headerType)` | `any` | IFC header info |155156---157158## Geometry Extraction159160### Single-Element Geometry161162```typescript163const flatMesh = ifcApi.GetFlatMesh(modelID, expressID);164165for (let i = 0; i < flatMesh.geometries.size(); i++) {166 const pg = flatMesh.geometries.get(i);167 const geom = ifcApi.GetGeometry(modelID, pg.geometryExpressID);168 const verts = ifcApi.GetVertexArray(geom.GetVertexData(), geom.GetVertexDataSize());169 const indices = ifcApi.GetIndexArray(geom.GetIndexData(), geom.GetIndexDataSize());170171 // verts: Float32Array — 6 floats per vertex [x, y, z, nx, ny, nz]172 // indices: Uint32Array — triangle indices173 // pg.color: { x, y, z, w } — RGBA (w = alpha)174 // pg.flatTransformation: number[] — 4x4 column-major transform matrix175}176```177178### Geometry Streaming (Memory-Efficient)179180ALWAYS prefer streaming over `LoadAllGeometry` for models with more than a few hundred elements.181182| Method | Purpose |183|---|---|184| `StreamAllMeshes(modelID, callback)` | Stream ALL meshable entities |185| `StreamAllMeshesWithTypes(modelID, types[], callback)` | Stream filtered by IFC types |186| `StreamMeshes(modelID, expressIDs[], callback)` | Stream specific elements |187| `LoadAllGeometry(modelID)` | Load all at once (AVOID for large models) |188189Callback signature: `(mesh: FlatMesh, index: number, total: number) => void`190191### Coordination & Transforms192193| Method | Purpose |194|---|---|195| `GetCoordinationMatrix(modelID)` | 4x4 matrix for multi-model alignment |196| `SetGeometryTransformation(modelID, matrix)` | Apply global transform to all geometry output |197| `GetWorldTransformMatrix(modelID, placementExpressId)` | Transform for specific placement |198199---200201## Properties Helper202203The `ifcApi.properties` object provides high-level async methods for property queries.204205| Method | Returns | Purpose |206|---|---|---|207| `getItemProperties(modelID, id, recursive?, inverse?)` | `Promise<any>` | All properties for an element |208| `getPropertySets(modelID, elementID?, recursive?)` | `Promise<any[]>` | Property sets (Psets) |209| `getTypeProperties(modelID, elementID?, recursive?)` | `Promise<any[]>` | Type object properties |210| `getMaterialsProperties(modelID, elementID?, recursive?)` | `Promise<any[]>` | Material definitions |211| `getSpatialStructure(modelID, includeProperties?)` | `Promise<Node>` | Full spatial hierarchy tree |212213The spatial structure returns a tree: `{ expressID, type, children: [...] }`.214215---216217## GUID Utilities218219| Method | Purpose |220|---|---|221| `GetExpressIdFromGuid(modelID, guid)` | Convert IFC GUID string to expressID |222| `GetGuidFromExpressId(modelID, expressID)` | Convert expressID to IFC GUID string |223| `CreateIfcGuidToExpressIdMapping(modelID)` | Pre-build mapping for faster lookups |224225ALWAYS call `CreateIfcGuidToExpressIdMapping` first if performing many GUID lookups — it builds an index that makes subsequent calls faster.226227---228229## Writing Data230231| Method | Purpose |232|---|---|233| `WriteLine(modelID, lineObject)` | Write or update a single entity |234| `WriteLines(modelID, lineObjects[])` | Batch write |235| `DeleteLine(modelID, expressID)` | Remove entity from model |236| `CreateIfcEntity(modelID, type, ...args)` | Create new IFC entity |237238After modifications, use `SaveModel(modelID)` to serialize back to IFC format.239240---241242## Logging243244```typescript245import { LogLevel } from "web-ifc";246ifcApi.SetLogLevel(LogLevel.LOG_LEVEL_OFF); // silent (recommended for production)247ifcApi.SetLogLevel(LogLevel.LOG_LEVEL_ERROR); // errors only248ifcApi.SetLogLevel(LogLevel.LOG_LEVEL_DEBUG); // verbose debugging249```250251---252253## Key Types254255See `references/methods.md` for complete type definitions.256257| Type | Description |258|---|---|259| `FlatMesh` | Triangulated geometry result: `{ expressID, geometries: Vector<PlacedGeometry> }` |260| `PlacedGeometry` | Single geometry piece: color (RGBA), transform (4x4), geometryExpressID |261| `IfcGeometry` | Raw WASM geometry: `GetVertexData/Size()`, `GetIndexData/Size()` |262| `Vector<T>` | WASM vector: access via `.size()` and `.get(i)` ONLY |263| `RawLineData` | Unparsed entity: `{ ID, type, arguments }` |264| `LoaderSettings` | Model loading configuration |265| `IfcType` | Type descriptor: `{ typeID, typeName }` |266267---268269## Common IFC Type Constants270271```typescript272import {273 // Structural274 IFCWALL, IFCWALLSTANDARDCASE, IFCSLAB, IFCBEAM, IFCCOLUMN,275 // Openings276 IFCDOOR, IFCWINDOW, IFCOPENINGELEMENT,277 // Building elements278 IFCROOF, IFCSTAIR, IFCFURNISHINGELEMENT,279 // Spatial hierarchy280 IFCPROJECT, IFCSITE, IFCBUILDING, IFCBUILDINGSTOREY, IFCSPACE,281 // Properties & relations282 IFCPROPERTYSET, IFCPROPERTYSINGLEVALUE,283 IFCRELDEFINESBYPROPERTIES, IFCRELCONTAINEDINSPATIALSTRUCTURE,284 IFCRELAGGREGATES, IFCRELVOIDSELEMENT,285} from "web-ifc";286```287288---289290## References291292- `references/methods.md` — Complete IfcAPI method signatures and type definitions293- `references/examples.md` — Full working examples: init, load, query, geometry, properties294- `references/anti-patterns.md` — Common failures: WASM init, memory leaks, Vector access295296## Sources297298- GitHub: https://github.com/ThatOpen/engine_web-ifc299- Docs: https://thatopen.github.io/engine_web-ifc/docs/300- npm: https://www.npmjs.com/package/web-ifc