Core components
Core engine
Engine module system
23 min
overview the engine module system provides the organizational structure for the ir engine, defining how different functional components are grouped, loaded, and initialized it serves as the blueprint that ensures all engine subsystems are properly integrated and available when an application starts by using a modular approach, the engine achieves better maintainability, extensibility, and clarity in its architecture this chapter explores the concepts, structure, and implementation of the engine module system within the ir engine core concepts engine modules an engine module is a self contained package of related functionality that encapsulates a specific aspect of the engine definition a module groups together related components, systems, and state definitions scope each module focuses on a specific domain (e g , assets, avatars, rendering) independence modules can function with minimal dependencies on other modules integration modules connect to the core engine through standardized interfaces examples of engine modules include assetmodule manages loading and caching of assets avatarmodule handles character representation and animation scenemodule controls 3d scene structure and rendering interactionmodule manages object interactions and user input visualscriptmodule provides visual programming capabilities module initialization modules are initialized through javascript/typescript's import mechanism // when this file is imported, all its top level code executes // simplified concept from a module file like src/avatar/avatarmodule ts import { definesystem, definecomponent } from '@ir engine/ecs'; import { avatarsystemlogic } from ' /systems/avatarsystemlogic'; import { avatarcomponentdefinition } from ' /components/avatarcomponentdefinition'; // this code runs immediately when the module is imported export const avatarcomponent = definecomponent(avatarcomponentdefinition); export const avatarsystem = definesystem(avatarsystemlogic); // additional initialization code can be placed here console log("avatar module initialized"); key aspects of module initialization top level code in a module file executes when the file is imported component and system definitions register with the ecs state definitions register with hyperflux initialization happens automatically without explicit function calls central module registry the enginemodule ts file serves as the central registry for all core engine modules // from core engine/src/enginemodule ts // import foundational spatial and ecs utilities import '@ir engine/spatial'; // import and initialize all core modules export from ' /assets/assetmodule'; export from ' /audio/mediamodule'; export from ' /avatar/avatarmodule'; export from ' /grabbable/grabbablesystem'; export from ' /interaction/systems/interactablesystem'; export from ' /mocap/mocapmodule'; export from ' /postprocessing/populateeffectregistry'; export from ' /scene/scenemodule'; export from ' /visualscript/visualscriptmodule'; this file imports all core engine modules executes their initialization code re exports their public interfaces establishes the complete engine functionality module structure a typical engine module follows a consistent structure components each module defines its domain specific components // simplified concept from src/avatar/components/avatarcomponent ts import { definecomponent, s } from '@ir engine/ecs'; export const avatarcomponent = definecomponent({ name 'avatarcomponent', schema s object({ avatarheight s number({ default 1 8 }), // other avatar properties }) }); these components store domain specific data follow the ecs pattern described in chapter 1 use schema definitions for type safety and validation are exported for use by systems within and outside the module systems each module defines systems that operate on its components // simplified concept from src/avatar/systems/avataranimationsystem tsx import { definesystem, definequery } from '@ir engine/ecs'; import { avatarcomponent } from ' /components/avatarcomponent'; import { animationcomponent } from ' /components/animationcomponent'; const avataranimationquery = definequery(\[avatarcomponent, animationcomponent]); export const avataranimationsystem = definesystem({ uuid 'ir engine avataranimationsystem', execute () => { const entities = avataranimationquery(); for (const entity of entities) { // animation logic } } }); these systems implement the module's behavior query for entities with specific component combinations process data and update component values are registered with the ecs when the module is imported state many modules define hyperflux state for global data // simplified concept from src/avatar/state/avatarsettingsstate ts import { definestate } from '@ir engine/hyperflux'; export const avatarsettingsstate = definestate({ name 'avatarsettingsstate', initial { walkspeed 2 0, runspeed 5 0, jumpheight 1 0 } }); this state stores configuration and runtime data is accessible throughout the engine follows the hyperflux pattern described in chapter 1 provides a central point for module settings module file each module has a main file that imports and exports its components // simplified concept from src/avatar/avatarmodule ts // import and re export components export from ' /components/avatarcomponent'; export from ' /components/avatarrigcomponent'; export from ' /components/avataranimationcomponent'; // import and re export systems export from ' /systems/avataranimationsystem'; export from ' /systems/avatarmovementsystem'; export from ' /systems/avatariksystem'; // import and re export state export from ' /state/avatarsettingsstate'; // any additional initialization code console log('avatar module initialized'); this file serves as the entry point for the module re exports all public interfaces performs any necessary initialization is imported by the central enginemodule ts initialization flow the process of initializing the engine follows this sequence sequencediagram participant app as application participant enginecore as engine core participant enginemodule as enginemodule ts participant assetmodule as assetmodule ts participant avatarmodule as avatarmodule ts participant ecs as ecs registry app >>enginecore initialize engine enginecore >>enginemodule import enginemodule ts enginemodule >>assetmodule import assetmodule ts assetmodule >>ecs register asset components assetmodule >>ecs register asset systems assetmodule >>enginemodule module initialized enginemodule >>avatarmodule import avatarmodule ts avatarmodule >>ecs register avatar components avatarmodule >>ecs register avatar systems avatarmodule >>enginemodule module initialized note over enginemodule continues for all modules enginemodule >>enginecore all modules initialized enginecore >>app engine ready this diagram illustrates the application initializes the engine core the engine core imports the central enginemodule ts enginemodule ts imports each module file each module file registers its components and systems once all modules are initialized, the engine is ready extending the engine developers can extend the engine with custom modules following the same pattern // custom game module src/game/vehiclemodule ts import { definecomponent, definesystem, s } from '@ir engine/ecs'; // define vehicle components export const vehiclecomponent = definecomponent({ name 'vehiclecomponent', schema s object({ maxspeed s number({ default 100 }), acceleration s number({ default 10 }), handling s number({ default 0 8 }) }) }); // define vehicle systems export const vehiclephysicssystem = definesystem({ uuid 'game vehiclephysicssystem', execute () => { // vehicle physics logic } }); // additional initialization console log('vehicle module initialized'); to use this custom module // in the main application file // initialize the ir engine core import '@ir engine/core'; // import custom game modules import ' /game/vehiclemodule'; import ' /game/racetrackmodule'; import ' /game/gameplaymodule'; // start the application startgame(); this approach follows the same pattern as core engine modules allows for clean organization of game specific features integrates seamlessly with the engine's ecs and hyperflux enables modular development of game systems implementation details module dependencies modules often depend on each other, requiring careful import ordering // simplified concept of module dependencies // in enginemodule ts, the import order matters import '@ir engine/spatial'; // foundational ecs must come first // core systems that others depend on export from ' /assets/assetmodule'; // asset system is needed by many others export from ' /scene/scenemodule'; // scene system builds on assets // systems that depend on the core export from ' /avatar/avatarmodule'; // avatars need assets and scene export from ' /interaction/systems/interactablesystem'; // interactions need scene // higher level systems export from ' /visualscript/visualscriptmodule'; // visual scripting can use all other systems the import order ensures that foundational systems are initialized first dependencies are available when needed circular dependencies are avoided the engine builds up from low level to high level features lazy loading some modules support lazy loading for better performance // simplified concept of lazy loading // instead of immediate initialization // export from ' /heavyfeature/heavyfeaturemodule'; // use a function to load on demand export function loadheavyfeature() { return import(' /heavyfeature/heavyfeaturemodule') then(module => { console log('heavy feature loaded'); return module; }); } this approach delays loading until the feature is needed reduces initial startup time conserves memory for unused features allows for more efficient resource usage benefits of the module system the engine module system provides several key benefits organization groups related functionality into logical units maintainability makes the codebase easier to understand and update extensibility provides a clear pattern for adding new features encapsulation isolates implementation details within modules initialization ensures proper setup sequence for all engine features reusability allows modules to be shared across different projects scalability supports growing the engine with minimal refactoring these benefits make the engine module system a critical architectural component that enables the ir engine to remain flexible and powerful as it evolves conclusion the engine module system serves as the organizational backbone of the ir engine, providing a structured approach to grouping, loading, and initializing the engine's many subsystems by using javascript/typescript's import mechanism for automatic initialization and a central registry in enginemodule ts , the system ensures that all components of the engine are properly integrated and ready for use throughout this documentation, we've explored the core systems that make up the ir engine ecs and state management with hyperflux (chapter 1) asset management for loading resources (chapter 2) scene graph and rendering for visualization (chapter 3) avatar system for character representation (chapter 4) interaction system for object manipulation (chapter 5) visual scripting for accessible programming (chapter 6) engine module system for organization (chapter 7) with this understanding of the ir engine's architecture and systems, you're now equipped to build upon this foundation to create rich, interactive experiences