Interactive System

Aug 12, 2026

Interactive House Configurators

A real time 3D house configurator made in Unreal that allows users to customize architectural elements, materials, finishes and furniture while instantly visualizing their choices in the web app.

orb

Interactive House Configurator

A scalable real-time house configuration built in Unreal Engine, designed around a robust and modular architecture that separates configuration logic, application behavior, networking, and presentation. The system was built to support complex interactive scenes while remaining extensible across multiple houses and configurations.

Technical Architecture

Engine & Manager Architecture

At the core of the configurator is a central Engine layer responsible for coordinating a collection of specialized managers. Each manager owns a specific area of functionality, keeping the overall system modular and reducing dependencies between unrelated systems.

This architecture allowed new behaviors to be introduced as independent systems rather than continuously expanding and bloating a single monolithic controller.

Separation of Layers

The system follows a clear separation between different application layers:

Network -> Commands -> Allocations -> Action -> Unreal Systems

This separation keeps UI and external requests independent from the underlying implementation and makes individual systems easier to test, maintain, and replace.


class Engine
{
  PreStart()
  {
    Create Manager: Logging
    Create Manager: Commands
    Create Manager: Assets
    Create Manager: Network
    Create Manager: Scene
    Create Manager: Rendering
    Managers = [ Logging, Commands, Assets, Network, Scene, Rendering]
  }

  Start()
  {
      for each Manager in Managers
      {
          if (Manager.CanRunInCurrentEnvironment())
          {
            Manager.Create()
          }
      }
      IsStarted = true
   } 
}
class Engine
{
  PreStart()
  {
    Create Manager: Logging
    Create Manager: Commands
    Create Manager: Assets
    Create Manager: Network
    Create Manager: Scene
    Create Manager: Rendering
    Managers = [ Logging, Commands, Assets, Network, Scene, Rendering]
  }

  Start()
  {
      for each Manager in Managers
      {
          if (Manager.CanRunInCurrentEnvironment())
          {
            Manager.Create()
          }
      }
      IsStarted = true
   } 
}
class Engine
{
  PreStart()
  {
    Create Manager: Logging
    Create Manager: Commands
    Create Manager: Assets
    Create Manager: Network
    Create Manager: Scene
    Create Manager: Rendering
    Managers = [ Logging, Commands, Assets, Network, Scene, Rendering]
  }

  Start()
  {
      for each Manager in Managers
      {
          if (Manager.CanRunInCurrentEnvironment())
          {
            Manager.Create()
          }
      }
      IsStarted = true
   } 
}


Network Manager

A dedicated Network Manager provides a single interface for communication between the configurator and external services.

Instead of allowing individual systems to communicate directly with APIs, requests are routed through a common networking layer. This centralizes communication, simplifies error handling, and prevents API-specific logic from spreading throughout the application.

Hashed Command System

User actions are represented as commands and identified using hashed command data.

This provides a lightweight way of tracking configuration operations and enables efficient Undo / Redo functionality. Rather than storing complete scene states, the system can record and replay the operations that produced those states.

This approach also provides a consistent abstraction for both user-driven and programmatic changes.

Command Queue

A Command Queue allows multiple commands to be grouped and executed as a sequence.

This is particularly useful for complex configuration operations where a single user action may require several changes to happen in a specific order.

Command sequences can also be reused, making it possible to represent repeatable workflows as a series of instructions rather than duplicating implementation logic.

(This system allowed better test integrations as well)


class CommandManager
{
  Enqueue(Command, Queue)
  {
    Queue.PushByPriority(Command)
  }

  Dequeue(Queue)
  {
      return Queue.PopByPriority()
  }

  Tick()
  {
      if (CurrentCommand.IsExecuting())
      {
          return;
      }
  
      while (Command = Dequeue(CommandQueue))
      {
          Execute(Command)
          .OnDone(PostCommandOperation)
          .Timeout(CommandTimeout)
      }
  }

  Execute(Command)
  {
      Command.Do()
      Enqueue(Command, UndoQueue)
  }
}
class CommandManager
{
  Enqueue(Command, Queue)
  {
    Queue.PushByPriority(Command)
  }

  Dequeue(Queue)
  {
      return Queue.PopByPriority()
  }

  Tick()
  {
      if (CurrentCommand.IsExecuting())
      {
          return;
      }
  
      while (Command = Dequeue(CommandQueue))
      {
          Execute(Command)
          .OnDone(PostCommandOperation)
          .Timeout(CommandTimeout)
      }
  }

  Execute(Command)
  {
      Command.Do()
      Enqueue(Command, UndoQueue)
  }
}
class CommandManager
{
  Enqueue(Command, Queue)
  {
    Queue.PushByPriority(Command)
  }

  Dequeue(Queue)
  {
      return Queue.PopByPriority()
  }

  Tick()
  {
      if (CurrentCommand.IsExecuting())
      {
          return;
      }
  
      while (Command = Dequeue(CommandQueue))
      {
          Execute(Command)
          .OnDone(PostCommandOperation)
          .Timeout(CommandTimeout)
      }
  }

  Execute(Command)
  {
      Command.Do()
      Enqueue(Command, UndoQueue)
  }
}

Pixel Streaming Integration

The configurator was integrated with Unreal Pixel Streaming, allowing the real-time Unreal application to run remotely while users interact with it through a web-based interface.

The architecture was designed to accommodate communication between the web application, streaming layer, and Unreal runtime while keeping the configurator's core systems independent from the presentation client.

Asynchronous Scene Loading

Large architectural scenes can contain significant amounts of geometry, textures, materials, and other assets. To avoid blocking the application while these resources are being prepared, the configurator uses asynchronous scene loading.

This allows loading operations to occur without unnecessarily blocking the main execution flow and provides a smoother experience when transitioning between scenes or configurations.


class SceneManager
{
  LoadStreamingLevelsAsync(Package)
{
  
void LoadPackageAsync(Package)
}
    CurrentLevels = GetCurrentStreamingLevels()
    NewLevels = Package.GetStreamingLevels()

    for each Level in NewLevels
    {
        if (Level already exists in CurrentLevels)
        {
            Keep Existing Level
        }
        else
        {
            Create Streaming Level
            Add Level to Current World
        }
        LoadAsync(Level);
    }

    for each Level in CurrentLevels
    {
        if (Level is not required by new scene)
        {
            HideLevel(Level)
        }
    }

    SceneState = Loaded
}
class SceneManager
{
  LoadStreamingLevelsAsync(Package)
{
  
void LoadPackageAsync(Package)
}
    CurrentLevels = GetCurrentStreamingLevels()
    NewLevels = Package.GetStreamingLevels()

    for each Level in NewLevels
    {
        if (Level already exists in CurrentLevels)
        {
            Keep Existing Level
        }
        else
        {
            Create Streaming Level
            Add Level to Current World
        }
        LoadAsync(Level);
    }

    for each Level in CurrentLevels
    {
        if (Level is not required by new scene)
        {
            HideLevel(Level)
        }
    }

    SceneState = Loaded
}
class SceneManager
{
  LoadStreamingLevelsAsync(Package)
{
  
void LoadPackageAsync(Package)
}
    CurrentLevels = GetCurrentStreamingLevels()
    NewLevels = Package.GetStreamingLevels()

    for each Level in NewLevels
    {
        if (Level already exists in CurrentLevels)
        {
            Keep Existing Level
        }
        else
        {
            Create Streaming Level
            Add Level to Current World
        }
        LoadAsync(Level);
    }

    for each Level in CurrentLevels
    {
        if (Level is not required by new scene)
        {
            HideLevel(Level)
        }
    }

    SceneState = Loaded
}

Plug-able Scene Packages

Heavy house scenes were packaged into plug-able package files (.pak), allowing them to be loaded independently from the core application.

This created a modular content architecture where the main configurator engine does not need to contain every house and its assets. Individual projects or houses can be distributed as packages and mounted/loaded when required.

This approach reduces coupling between the framework and content while making it significantly easier to add and distribute new houses without rebuilding the entire system.

Engineering Principles

The overall architecture was designed around:

  • Modularity — independent managers with clearly defined responsibilities.

  • Separation of concerns — networking, commands, configuration, presentation, and scene management remain decoupled.

  • Command-based execution — actions can be queued, repeated, undone, and redone.

  • Extensibility — new managers, commands, and house packages can be introduced without restructuring the core engine.

  • Asynchronous execution — expensive scene operations are handled without unnecessarily blocking the application.

  • Content modularity — large house environments can be distributed as independently loadable packages.

  • Remote rendering — Pixel Streaming enables the Unreal application to function as a remotely hosted interactive visualization platform.


(Can't display the original asset set and web application in the video for NDA reasons)