npm package: @ifc-viewer/core
Description: Production-ready BIM viewer for web applications. Load, inspect, and interact with IFC files in the browser with measurements, clipping, AI visualization, and more.
Author: IFC Viewer Contributors
Latest version: 0.2.5

# @ifc-viewer/core
> **Professional IFC viewer library built with React and Three.js**

A production-ready, feature-rich BIM viewer that lets you load, inspect, and interact with Building Information Model (IFC) files directly in the browser. Built on top of Three.js and the That Open Company ecosystem with zero native installations required.

[![npm version](https://img.shields.io/npm/v/@ifc-viewer/core.svg)](https://www.npmjs.com/package/@ifc-viewer/core)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)

## ✨ Features

- 🏗️ **Full IFC Support** - Load and render IFC 2x3 and IFC4 files
- 📐 **Measurement Tools** - Volume, length, area, angle measurements
- 🗺️ **Interactive Minimap** - Real-time overhead navigation view
- ✂️ **Clipping Planes** - Section cuts with transform gizmos
- 🎨 **AI Visualizer** - Transform BIM views into photorealistic renders (powered by HuggingFace)
- 📸 **Screenshots** - Capture high-resolution images
- 🎯 **Element Selection** - Click to inspect IFC properties
- 🌳 **Relations Tree** - Navigate spatial structure (Sites → Buildings → Storeys)
- 🎮 **Multiple Navigation Modes** - Orbit, First-Person, Plan view
- 📱 **Mobile Friendly** - Touch-optimized controls
- 🎨 **Customizable** - Theme, appearance, and feature flags
- ⚡ **High Performance** - Optimized for large models with fragment streaming

## 📦 Installation

```bash
npm install @ifc-viewer/core
```

## 🚀 Quick Start

### Basic Usage

```javascript
import { createIFCViewer } from '@ifc-viewer/core';
import '@ifc-viewer/core/styles';

const viewer = createIFCViewer({
  container: document.getElementById('viewer-container'),
  onModelLoaded: (meta) => console.log('Model loaded!', meta),
  onError: (error) => console.error('Error:', error)
});
```

### HTML Setup

```html
<!DOCTYPE html>
<html>
<head>
  <style>
    body {
      margin: 0;
      padding: 0;
      overflow: hidden;
    }

    #viewer-container {
      width: 100vw;
      height: 100vh;
    }
  </style>
</head>
<body>
  <div id="viewer-container"></div>

  <script type="module">
    import { createIFCViewer } from '@ifc-viewer/core';
    import '@ifc-viewer/core/styles';

    const viewer = createIFCViewer({
      container: document.getElementById('viewer-container')
    });
  </script>
</body>
</html>
```

## 🎨 Configuration

### Full Configuration Example

```typescript
import { createIFCViewer } from '@ifc-viewer/core';
import '@ifc-viewer/core/styles';

const viewer = createIFCViewer({
  // Required: Container element
  container: document.getElementById('viewer-container'),

  // Optional: Customize appearance
  appearance: {
    world: {
      backgroundColor: '#050816',
      directionalLightColor: '#f1f5f9',
      directionalLightPosition: [20, 35, 10],
    },
    grid: {
      enabled: true,
      color: '#10b981',
      primarySize: 6,
      secondarySize: 1,
      distance: 250,
    },
  },

  // Optional: Load a model on startup
  initialModel: {
    url: '/models/demo-project.ifc',
    // OR use a File/Blob:
    // file: myIfcFileBlob
  },

  // Optional: Enable/disable features
  features: {
    minimap: true,
    measurement: true,
    clipping: true,
    floorplans: true,
    aiVisualizer: false,  // Requires HuggingFace API token
  },

  // Optional: Callbacks
  onModelLoaded: (meta) => {
    console.log('Model loaded:', meta);
  },
  onObjectSelected: (selection) => {
    console.log('Selected objects:', selection);
  },
  onError: (error) => {
    console.error('Viewer error:', error);
  },

  // Optional: Custom theme
  theme: {
    '--primary-color': '#667eea',
    '--background-color': '#1a1a1a',
  }
});
```

## 🎯 API Reference

### ViewerHandle

The `createIFCViewer` function returns a handle with the following methods:

#### `loadModelFromUrl(url: string): Promise<void>`

Load an IFC model from a URL:

```javascript
await viewer.loadModelFromUrl('/path/to/model.ifc');
```

#### `loadModelFromFile(file: File): Promise<void>`

Load an IFC model from a File object:

```javascript
const fileInput = document.getElementById('file-input');
fileInput.addEventListener('change', async (e) => {
  const file = e.target.files[0];
  await viewer.loadModelFromFile(file);
});
```

#### `captureScreenshot(): Promise<string>`

Capture a screenshot as a base64 data URL:

```javascript
const screenshot = await viewer.captureScreenshot();
// Use as image src or download
const img = document.createElement('img');
img.src = screenshot;
```

#### `getCameraState(): Promise<CameraState>`

Get current camera position and target:

```javascript
const cameraState = await viewer.getCameraState();
console.log('Position:', cameraState.position);
console.log('Target:', cameraState.target);
```

#### `setCameraState(state: CameraState): Promise<void>`

Set camera position and target:

```javascript
await viewer.setCameraState({
  position: { x: 10, y: 20, z: 30 },
  target: { x: 0, y: 0, z: 0 }
});
```

#### `unmount(): void`

Cleanup and unmount the viewer:

```javascript
viewer.unmount();
```

## 🎨 Embedding in Your Website

### Full-Page Viewer

```html
<style>
  body { margin: 0; padding: 0; overflow: hidden; }
  #viewer { width: 100vw; height: 100vh; }
</style>

<div id="viewer"></div>

<script type="module">
  import { createIFCViewer } from '@ifc-viewer/core';
  import '@ifc-viewer/core/styles';

  createIFCViewer({
    container: document.getElementById('viewer')
  });
</script>
```

### Embedded in Page Section

When embedding the viewer in a page section (not full-page), you need to override some default styles:

```html
<style>
  /* Wrapper with explicit height */
  .viewer-wrapper {
    width: 100%;
    height: 600px;
    position: relative;
    overflow: hidden;
  }

  /* Override viewport units to container units */
  #viewer-container .ifc-viewer-library-container.layout {
    height: 100% !important;
    width: 100% !important;
  }

  /* Contain sidebar to container */
  #viewer-container .sidebar-slot {
    position: absolute !important;
  }

  #viewer-container .sidebar-toggle {
    position: absolute !important;
  }
</style>

<div class="viewer-wrapper">
  <div id="viewer-container"></div>
</div>

<script type="module">
  import { createIFCViewer } from '@ifc-viewer/core';
  import '@ifc-viewer/core/styles';

  createIFCViewer({
    container: document.getElementById('viewer-container')
  });
</script>
```

### Modal/Popup Viewer

```html
<style>
  .modal-overlay {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.9);
    z-index: 10000;
    align-items: center;
    justify-content: center;
    padding: 40px;
  }

  .modal-overlay.active {
    display: flex;
  }

  .modal-content {
    width: 90vw;
    height: 80vh;
    max-width: 1400px;
    max-height: 900px;
    background: #1a1a1a;
    border-radius: 12px;
    position: relative;
    overflow: hidden;
  }

  #modal-viewer {
    width: 100%;
    height: 100%;
    position: relative;
  }

  /* Override for modal context */
  #modal-viewer .ifc-viewer-library-container.layout {
    height: 100% !important;
    width: 100% !important;
  }

  #modal-viewer .sidebar-slot,
  #modal-viewer .sidebar-toggle {
    position: absolute !important;
  }
</style>

<button onclick="openViewer()">Open Viewer</button>

<div class="modal-overlay" id="modal">
  <button onclick="closeViewer()" style="position: absolute; top: 20px; right: 20px;">×</button>
  <div class="modal-content">
    <div id="modal-viewer"></div>
  </div>
</div>

<script type="module">
  import { createIFCViewer } from '@ifc-viewer/core';
  import '@ifc-viewer/core/styles';

  let viewer = null;

  window.openViewer = function() {
    document.getElementById('modal').classList.add('active');

    if (!viewer) {
      viewer = createIFCViewer({
        container: document.getElementById('modal-viewer')
      });
    }
  };

  window.closeViewer = function() {
    document.getElementById('modal').classList.remove('active');
  };
</script>
```

## 🎯 Advanced Examples

### Load Model with Configuration

```javascript
const viewer = createIFCViewer({
  container: document.getElementById('viewer'),
  
  // Custom colors and lighting
  appearance: {
    world: {
      backgroundColor: '#0b1120',
      directionalLightColor: '#f8fafc',
      directionalLightPosition: [25, 40, 10],
    },
    grid: {
      color: '#22d3ee',
      enabled: true,
      primarySize: 8,
      secondarySize: 1,
    },
  },

  // Pre-load a model
  initialModel: {
    url: '/models/showroom.ifc',
  },

  // Minimal UI - disable some features
  features: {
    minimap: false,
    aiVisualizer: false,
    measurement: true,
    clipping: true,
  },

  // Handle events
  onModelLoaded: async (meta) => {
    console.log('Model loaded with metadata:', meta);
    
    // Capture initial view
    const screenshot = await viewer.captureScreenshot();
    console.log('Initial screenshot captured');
  },

  onObjectSelected: (selection) => {
    // selection is a Map: fragmentID -> Set<expressID>
    for (const [fragmentId, expressIds] of selection.entries()) {
      console.log(`Fragment ${fragmentId}: Selected ${expressIds.size} elements`);
    }
  },
});
```

### React Integration

```tsx
import { useEffect, useRef } from 'react';
import { createIFCViewer, ViewerHandle } from '@ifc-viewer/core';
import '@ifc-viewer/core/styles';

function IFCViewerComponent() {
  const containerRef = useRef<HTMLDivElement>(null);
  const viewerRef = useRef<ViewerHandle | null>(null);

  useEffect(() => {
    if (!containerRef.current) return;

    const viewer = createIFCViewer({
      container: containerRef.current,
      onModelLoaded: (meta) => {
        console.log('Model loaded:', meta);
      },
      features: {
        minimap: true,
        measurement: true,
      }
    });

    viewerRef.current = viewer;

    return () => {
      viewer.unmount();
    };
  }, []);

  const handleLoadModel = async () => {
    if (viewerRef.current) {
      await viewerRef.current.loadModelFromUrl('/model.ifc');
    }
  };

  return (
    <div style={{ width: '100%', height: '100vh' }}>
      <button onClick={handleLoadModel}>Load Model</button>
      <div ref={containerRef} style={{ width: '100%', height: '100%' }} />
    </div>
  );
}
```

### File Upload Integration

```html
<input type="file" id="file-input" accept=".ifc" />
<div id="viewer" style="width: 100vw; height: 100vh;"></div>

<script type="module">
  import { createIFCViewer } from '@ifc-viewer/core';
  import '@ifc-viewer/core/styles';

  const viewer = createIFCViewer({
    container: document.getElementById('viewer'),
    onModelLoaded: (meta) => {
      console.log('Model loaded successfully!');
    }
  });

  document.getElementById('file-input').addEventListener('change', async (e) => {
    const file = e.target.files[0];
    if (file && file.name.endsWith('.ifc')) {
      try {
        await viewer.loadModelFromFile(file);
      } catch (error) {
        console.error('Failed to load model:', error);
      }
    }
  });
</script>
```

## 🤖 AI Visualizer Setup (Optional)

The AI Visualizer feature transforms your BIM views into photorealistic architectural renders using HuggingFace models.

1. Get a free HuggingFace API token: https://huggingface.co/settings/tokens
2. Create a `.env` file in your project:
   ```
   VITE_HUGGINGFACE_TOKEN=your_token_here
   ```
3. Enable the feature:
   ```javascript
   createIFCViewer({
     container: document.getElementById('viewer'),
     features: {
       aiVisualizer: true
     }
   });
   ```

## 📋 Type Definitions

Full TypeScript support with exported types:

```typescript
import type {
  CreateViewerOptions,
  ViewerHandle,
  SelectionMap,
  ViewerFeatureFlags,
  ViewerAppearanceConfig,
  InitialModelConfig,
} from '@ifc-viewer/core';
```

## 🛠️ Browser Support

- ✅ Chrome/Edge 90+
- ✅ Firefox 88+
- ✅ Safari 14+
- ✅ Mobile browsers (iOS Safari, Chrome Android)

**Requirements:**
- WebGL 2.0
- ES2020 support
- WebAssembly support

## 📚 Common Issues

### Issue: Viewer appears full-screen instead of contained

**Solution:** When embedding in a page section, apply these CSS overrides:

```css
#your-container .ifc-viewer-library-container.layout {
  height: 100% !important;
  width: 100% !important;
}

#your-container .sidebar-slot,
#your-container .sidebar-toggle {
  position: absolute !important;
}
```

### Issue: Sidebar extends beyond container

**Solution:** The viewer uses `position: fixed` by default for full-page mode. Override to `absolute` for embedded mode (see example above).

### Issue: Model doesn't load

**Troubleshooting:**
1. Check browser console for errors
2. Verify IFC file is valid (not corrupted)
3. Ensure file is accessible (CORS headers if loading from URL)
4. Check file size - very large models (>100MB) may take time

### Issue: WASM not found

**Solution:** Ensure `web-ifc.wasm` is accessible. If serving from a subdirectory, set:

```javascript
import { Components } from '@thatopen/components';

Components.config.webIfcPath = '/path/to/web-ifc.wasm';
```

## 🎬 Examples

Check out our live examples:

- [Full-page viewer](https://github.com/yourusername/ifc-viewer-project/tree/main/examples/full-page)
- [Embedded viewer](https://github.com/yourusername/ifc-viewer-project/tree/main/examples/embedded)
- [React integration](https://github.com/yourusername/ifc-viewer-project/tree/main/examples/react)
- [Modal viewer](https://github.com/yourusername/ifc-viewer-project/tree/main/examples/modal)

## 📖 Documentation

- [Full Documentation](https://github.com/yourusername/ifc-viewer-project#readme)
- [Integration Guide](https://github.com/yourusername/ifc-viewer-project/blob/main/npm-package-test/INTEGRATION_GUIDE.md)
- [API Reference](https://github.com/yourusername/ifc-viewer-project/wiki/API-Reference)
- [Changelog](https://github.com/yourusername/ifc-viewer-project/blob/main/CHANGELOG.md)

## 🤝 Contributing

Contributions are welcome! Please read our [Contributing Guide](https://github.com/yourusername/ifc-viewer-project/blob/main/CONTRIBUTING.md).

## 📄 License

MIT © IFC Viewer Contributors

## 🙏 Acknowledgments

Built with:
- [Three.js](https://threejs.org/) - 3D rendering engine
- [That Open Company](https://thatopen.com/) - BIM components ecosystem
- [web-ifc](https://github.com/IFCjs/web-ifc) - IFC parser

---

**Questions?** [Open an issue](https://github.com/yourusername/ifc-viewer-project/issues) or [start a discussion](https://github.com/yourusername/ifc-viewer-project/discussions)

**Need help integrating?** Check out our [detailed integration guide](https://github.com/yourusername/ifc-viewer-project/blob/main/npm-package-test/INTEGRATION_GUIDE.md) with complete examples.