Skip to content

Property Editing

IFClite supports editing IFC properties in-place with full change tracking, undo/redo, and export. The @ifc-lite/mutations package provides the mutation infrastructure, while the viewer integrates it with a property editor UI.

How It Works

Mutations are tracked through a MutablePropertyView that wraps the original read-only property table. When you edit a property:

  1. The original value is preserved
  2. The new value is stored in an overlay
  3. Reads return the mutated value transparently
  4. All changes are tracked as a Mutation with old/new values
  5. Changes can be exported, applied to other models, and shared via change sets

Quick Start

Editing Properties

import { MutablePropertyView } from '@ifc-lite/mutations';

// Create a mutable view over the property table
// Parameters: (baseTable: PropertyTable | null, modelId: string)
const view = new MutablePropertyView(propertyTable, 'my-model');

// Set a property value
const mutation = view.setProperty(
  entityId,             // Express ID of the entity
  'Pset_WallCommon',    // Property set name
  'FireRating',         // Property name
  'REI 120',            // New value
);

console.log(`Changed from "${mutation.oldValue}" to "${mutation.newValue}"`);

// Read the mutated value
const value = view.getPropertyValue(entityId, 'Pset_WallCommon', 'FireRating');
// Returns 'REI 120'

Mutation History

// Get all mutations applied to this view
const mutations = view.getMutations();

// Check if an entity has changes
const hasChanges = view.hasChanges(entityId);

// Get count of modified entities
const count = view.getModifiedEntityCount();

// Clear all mutations (reset to original state)
view.clear();

Note: Undo/redo is handled by the viewer's store (mutationSlice), not directly on MutablePropertyView. In the viewer, use Ctrl+Z / Ctrl+Shift+Z.

Change Sets

Change sets group related mutations for export and sharing:

import { ChangeSetManager } from '@ifc-lite/mutations';

const manager = new ChangeSetManager();

// Create a change set (becomes the active change set)
const changeSet = manager.createChangeSet('Fire Safety Updates');

// Add mutations to the active change set
manager.addMutation(mutation1);
manager.addMutation(mutation2);

// Export as JSON
const json = manager.exportChangeSet(changeSet.id);

// Import on another instance
const imported = manager.importChangeSet(json);

Bulk Operations

For updating many entities at once, use the BulkQueryEngine:

import { BulkQueryEngine } from '@ifc-lite/mutations';
import { PropertyValueType } from '@ifc-lite/data';

// Constructor requires EntityTable and MutablePropertyView
const engine = new BulkQueryEngine(entityTable, mutationView);

// Define a bulk query - which entities to update and how
const query = {
  select: {
    entityTypes: [10],    // Type enum values (e.g., IfcWall)
    propertyFilters: [{
      psetName: 'Pset_WallCommon',
      propName: 'IsExternal',
      operator: '=' as const,
      value: true,
    }],
  },
  action: {
    type: 'SET_PROPERTY' as const,
    psetName: 'Pset_WallCommon',
    propName: 'ThermalTransmittance',
    value: 0.18,
    valueType: PropertyValueType.Real,
  },
};

// Preview changes before applying
const preview = engine.preview(query);
console.log(`Will update ${preview.matchedCount} entities`);

// Apply
const result = engine.execute(query);
console.log(`Updated ${result.affectedEntityCount} properties`);

CSV Import

Import property updates from spreadsheets:

import { CsvConnector } from '@ifc-lite/mutations';
import { PropertyValueType } from '@ifc-lite/data';

// Constructor requires EntityTable and MutablePropertyView
const connector = new CsvConnector(entityTable, mutationView);

// Parse CSV (returns CsvRow[])
const rows = connector.parse(csvString, {
  delimiter: ',',
  hasHeader: true,
});

// Define mapping from CSV columns to IFC properties
const mapping = {
  matchStrategy: { type: 'globalId' as const, column: 'GlobalId' },
  propertyMappings: [
    { sourceColumn: 'Fire Rating', targetPset: 'Pset_WallCommon', targetProperty: 'FireRating', valueType: PropertyValueType.String },
    { sourceColumn: 'U-Value', targetPset: 'Pset_WallCommon', targetProperty: 'ThermalTransmittance', valueType: PropertyValueType.Real },
  ],
};

// Import (takes CSV string directly, not pre-parsed rows)
const stats = connector.import(csvString, mapping);
console.log(`Matched: ${stats.matchedRows}, Updated: ${stats.mutationsCreated}, Skipped: ${stats.unmatchedRows}`);

Viewer Integration

In the IFClite viewer:

  1. Select an entity in 3D or the hierarchy panel
  2. Open Properties panel - Edit properties directly in the panel
  3. Bulk edit - Use the Property Editor to update multiple entities
  4. Track changes - Modified properties are highlighted
  5. Undo/Redo - Ctrl+Z / Ctrl+Shift+Z to undo/redo edits
  6. Export - Save modified IFC with changes applied

Mutation State

State Description
Modified entities Count of entities with property changes
Dirty models Models with unsaved mutations
Undo stack Per-model undo history
Redo stack Per-model redo history
Change sets Named groups of mutations for export

Key Types

Type Description
MutablePropertyView Wraps property table with mutation overlay
Mutation A single property change with old/new values
ChangeSet Named collection of mutations
ChangeSetManager Manages multiple change sets
BulkQueryEngine Query and update entities in bulk
CsvConnector Import property data from CSV files