Specialized components
World editor
Editor panels and UI structure
27 min
overview the editor panels and ui structure component is a fundamental element of the ir engine's world editor that organizes the user interface into specialized, interactive panels it provides a flexible framework for arranging and managing the various tools and views needed for 3d world creation by implementing a dockable panel system, this component enables users to customize their workspace while maintaining a consistent and intuitive editing experience this chapter explores the implementation, organization, and customization of the editor's user interface core concepts panel architecture the editor interface is built on a panel based architecture modular design each panel serves a specific function and can operate independently dockable framework panels can be arranged, resized, and grouped according to user preference tab system related panels can be grouped as tabs within a single container consistent styling all panels follow the same visual language and interaction patterns responsive layout the interface adapts to different screen sizes and configurations this architecture creates a flexible and customizable editing environment main panel types the editor includes several specialized panel types viewport panel displays the 3d scene and provides direct manipulation tools hierarchy panel shows the scene's object structure in a tree view properties panel displays and allows editing of the selected object's properties assets panel provides access to project resources like models and textures inspector panel shows detailed information about selected components materials panel enables creation and editing of material properties visual script panel provides a node based programming interface these panels cover the essential functions needed for world editing layout management the layout system manages panel arrangement and interaction default layout provides a standard arrangement for new users layout persistence saves and restores user customized layouts drag and drop rearrangement allows intuitive reorganization of panels split views supports horizontal and vertical splitting of panel areas collapsible regions enables panels to be minimized when not in use this system enables users to optimize their workspace for specific tasks implementation editorcontainer component the editorcontainer serves as the main ui framework // simplified from src/components/editorcontainer tsx import react, { useeffect } from 'react'; import { docklayout } from 'rc dock'; import { usehookstate } from '@hookstate/core'; import { editorstate } from ' /services/editorservices'; import { viewportpaneltab } from ' /panels/viewport'; import { hierarchypaneltab } from ' /panels/hierarchy'; import { propertiespaneltab } from ' /panels/properties'; import { assetspaneltab } from ' /panels/assets'; import { toolbar } from ' /toolbar/toolbar'; import ' /editorcontainer css'; / main container for the editor ui @returns editor container component / export const editorcontainer react fc = () => { // get editor state const editorstate = usehookstate(editorstate state); // define default layout const defaultlayout = { dockbox { mode 'horizontal', children \[ { mode 'vertical', size 800, children \[ { tabs \[{ viewportpaneltab }] }, { tabs \[{ assetspaneltab }] } ] }, { mode 'vertical', size 300, children \[ { tabs \[{ hierarchypaneltab }] }, { tabs \[{ propertiespaneltab }] } ] } ] } }; // handle layout changes const handlelayoutchange = (newlayout) => { // save layout to persistent storage localstorage setitem('editorlayout', json stringify(newlayout)); }; // load saved layout on component mount useeffect(() => { const savedlayout = localstorage getitem('editorlayout'); if (savedlayout) { try { const parsedlayout = json parse(savedlayout); // apply saved layout // implementation details omitted for brevity } catch (e) { console error('failed to parse saved layout', e); } } }, \[]); return ( \<div classname="editor container"> \<toolbar /> \<div classname="editor main"> \<docklayout defaultlayout={defaultlayout} style={{ position 'absolute', left 0, top 0, right 0, bottom 0 }} onlayoutchange={handlelayoutchange} /> \</div> \</div> ); }; this component imports panel definitions from various panel modules defines a default layout structure for the panels handles saving and loading of custom layouts renders the main editor interface with toolbar and dock layout panel definition each panel is defined as a tab configuration // simplified from src/panels/viewport/index tsx import react from 'react'; import { viewportcontent } from ' /viewportcontent'; / viewport panel tab configuration / export const viewportpaneltab = { id 'viewport', title 'viewport', content \<viewportcontent />, closable false, group 'main' }; this definition specifies a unique id for the panel sets the display title shown in the tab provides the react component to render as content configures whether the panel can be closed assigns the panel to a group for organization viewport panel the viewport panel displays the 3d scene // simplified from src/panels/viewport/index tsx import react, { useeffect, useref } from 'react'; import { usehookstate } from '@hookstate/core'; import { engine } from '@ir engine/core'; import { editorstate } from ' / /services/editorservices'; import { transformgizmotool } from ' /tools/transformgizmotool'; import { cameragizmotool } from ' /tools/cameragizmotool'; import { gridtool } from ' /tools/gridtool'; / viewport panel content @returns viewport component / export const viewportcontent react fc = () => { // reference to the canvas element const canvasref = useref\<htmlcanvaselement>(null); // get editor state const editorstate = usehookstate(editorstate state); // initialize engine and scene useeffect(() => { if (!canvasref current) return; // initialize engine with canvas const engine = new engine(canvasref current); // store engine reference in editor state editorstate engine set(engine); // set up scene and camera // implementation details omitted for brevity // clean up on unmount return () => { engine dispose(); }; }, \[canvasref]); return ( \<div classname="viewport container"> \<canvas ref={canvasref} classname="viewport canvas" /> \<div classname="viewport tools"> \<transformgizmotool /> \<cameragizmotool /> \<gridtool /> \</div> \</div> ); }; this component creates a canvas element for rendering the 3d scene initializes the rendering engine with the canvas sets up the scene and camera renders viewport tools for scene manipulation handles cleanup when the component is unmounted hierarchy panel the hierarchy panel displays the scene structure // simplified from src/panels/hierarchy/index tsx import react from 'react'; import { usehookstate } from '@hookstate/core'; import { editorstate } from ' / /services/editorservices'; import { hierarchytree } from ' /hierarchytree'; import { hierarchycontextmenu } from ' /contextmenu'; / hierarchy panel tab configuration / export const hierarchypaneltab = { id 'hierarchy', title 'hierarchy', content \<hierarchycontent />, closable false, group 'scene' }; / hierarchy panel content @returns hierarchy component / const hierarchycontent react fc = () => { // get editor state const editorstate = usehookstate(editorstate state); // handle node selection const handlenodeselect = (nodeid string) => { // update selection in editor state editorstate selectedentityid set(nodeid); }; return ( \<div classname="hierarchy container"> \<div classname="hierarchy toolbar"> \<button onclick={() => editorstate createentity()}>add entity\</button> \<button onclick={() => editorstate deleteselectedentity()}>delete\</button> \</div> \<hierarchytree rootnodes={editorstate scene entities value} onnodeselect={handlenodeselect} selectednodeid={editorstate selectedentityid value} /> \<hierarchycontextmenu /> \</div> ); }; this component renders a toolbar with common hierarchy operations displays a tree view of entities in the scene handles selection of entities in the hierarchy provides a context menu for additional operations synchronizes with the editor's selection state properties panel the properties panel displays and edits object properties // simplified from src/panels/properties/index tsx import react from 'react'; import { usehookstate } from '@hookstate/core'; import { editorstate } from ' / /services/editorservices'; import { propertyeditor } from ' /propertyeditor'; import { materialeditor } from ' /materialeditor'; / properties panel tab configuration / export const propertiespaneltab = { id 'properties', title 'properties', content \<propertiescontent />, closable false, group 'inspector' }; / properties panel content @returns properties component / const propertiescontent react fc = () => { // get editor state const editorstate = usehookstate(editorstate state); const selectedid = editorstate selectedentityid value; // get selected entity const selectedentity = selectedid ? editorstate scene entities value find(e => e id === selectedid) null; if (!selectedentity) { return \<div classname="properties empty">no entity selected\</div>; } return ( \<div classname="properties container"> \<h3>{selectedentity name}\</h3> \<section classname="properties section"> \<h4>transform\</h4> \<propertyeditor entity={selectedentity} component="transform" /> \</section> {selectedentity components material && ( \<section classname="properties section"> \<h4>material\</h4> \<materialeditor entity={selectedentity} /> \</section> )} {/ additional component editors /} \</div> ); }; this component retrieves the currently selected entity from editor state displays the entity's name and basic information renders property editors for each component on the entity shows specialized editors for specific component types handles updates to component properties panel workflow the complete panel interaction workflow follows this sequence sequencediagram participant user participant editorcontainer participant docklayout participant viewportpanel participant hierarchypanel participant propertiespanel participant editorstate user >>editorcontainer open editor editorcontainer >>docklayout initialize with default layout docklayout >>viewportpanel render in main area docklayout >>hierarchypanel render in side panel docklayout >>propertiespanel render in side panel user >>viewportpanel select object in 3d view viewportpanel >>editorstate update selection editorstate >>hierarchypanel notify of selection change hierarchypanel >>hierarchypanel highlight selected node editorstate >>propertiespanel notify of selection change propertiespanel >>propertiespanel display object properties user >>hierarchypanel select different object hierarchypanel >>editorstate update selection editorstate >>viewportpanel notify of selection change viewportpanel >>viewportpanel highlight selected object editorstate >>propertiespanel notify of selection change propertiespanel >>propertiespanel display new object properties user >>propertiespanel modify property value propertiespanel >>editorstate update object property editorstate >>viewportpanel notify of property change viewportpanel >>viewportpanel update visual representation user >>docklayout drag panel to new position docklayout >>docklayout recalculate layout docklayout >>editorcontainer notify of layout change editorcontainer >>editorcontainer save custom layout this diagram illustrates the editor initializes with a default panel layout panels communicate through the shared editor state selection in one panel updates the view in other panels property changes affect the visual representation users can customize the layout by dragging panels layout customization the editor supports various layout customizations panel docking panels can be docked in different positions // example of programmatic docking const dockpanel = (panelid, position) => { // get the dock layout instance const docklayout = docklayoutref current; // get the panel to dock const panel = docklayout find(panelid); // dock the panel at the specified position docklayout dockmove(panel, position, 'middle'); }; // dock the hierarchy panel to the right dockpanel('hierarchy', 'right'); this functionality allows panels to be moved to different sides of the editor supports docking relative to other panels enables creation of complex layouts persists across editor sessions can be triggered programmatically or through user interaction tab grouping related panels can be grouped as tabs // example of programmatic tab grouping const grouppanelsastabs = (panelids, groupid) => { // get the dock layout instance const docklayout = docklayoutref current; // get the panels to group const panels = panelids map(id => docklayout find(id)); // group the panels as tabs docklayout dockmove(panels\[0], panels\[1], 'middle'); // set the group id for the tab group const tabgroup = docklayout gettabgroup(panels\[0]); tabgroup group = groupid; }; // group properties and inspector panels grouppanelsastabs(\['properties', 'inspector'], 'details'); this functionality combines multiple panels in a single container allows switching between panels using tabs saves screen space for related functionality enables logical grouping of panels supports drag and drop reorganization layout persistence user layouts are saved and restored // example of layout persistence // save layout const savelayout = (layout) => { localstorage setitem('editorlayout', json stringify(layout)); }; // load layout const loadlayout = () => { const savedlayout = localstorage getitem('editorlayout'); if (savedlayout) { return json parse(savedlayout); } return defaultlayout; }; // reset to default layout const resetlayout = () => { localstorage removeitem('editorlayout'); return defaultlayout; }; this functionality saves user customizations to local storage restores layouts when the editor is reopened provides options to reset to default layouts handles invalid or outdated layouts gracefully enables sharing layouts between projects integration with other components the panel system integrates with several other components of the world editor editor state panels interact with the central editor state // example of editor state integration import { usehookstate } from '@hookstate/core'; import { editorstate } from ' / /services/editorservices'; // inside a panel component const panel = () => { // subscribe to editor state const editorstate = usehookstate(editorstate state); // get current selection const selectedentityid = editorstate selectedentityid value; // update selection const handleselect = (entityid) => { editorstate selectedentityid set(entityid); }; // panel rendering }; this integration provides reactive updates when state changes ensures consistency across panels centralizes editor data management enables undo/redo functionality supports persistence of editor state gizmo system panels interact with the gizmo system for visual manipulation // example of gizmo integration in viewport panel import { transformgizmosystem } from ' / /systems/transformgizmosystem'; // inside viewport panel const viewportpanel = () => { // initialize transform gizmo useeffect(() => { // create transform gizmo system const gizmosystem = new transformgizmosystem(scene, camera); // configure gizmo based on editor state gizmosystem setmode(editorstate transformmode value); gizmosystem setspace(editorstate transformspace value); // clean up on unmount return () => { gizmosystem dispose(); }; }, \[scene, camera]); // viewport rendering }; this integration displays manipulation gizmos in the viewport updates gizmo state based on editor settings handles user interaction with gizmos provides visual feedback for transformations supports different transformation modes asset system panels interact with the asset system for resource management // example of asset system integration in assets panel import { usehookstate } from '@hookstate/core'; import { filesstate } from ' / /services/filesstate'; // inside assets panel const assetspanel = () => { // subscribe to files state const filesstate = usehookstate(filesstate state); // get current directory and files const currentdir = filesstate currentdirectory value; const files = filesstate files value; // handle file selection const handlefileselect = (file) => { filesstate selectfile(file id); }; // assets panel rendering }; this integration displays available assets in the assets panel handles navigation of asset directories supports asset selection and preview enables drag and drop of assets into the scene provides asset import and management functionality benefits of the panel system the editor panels and ui structure component provides several key advantages flexibility enables users to customize their workspace for different tasks organization groups related functionality into logical panels consistency provides a uniform interface across different editor functions efficiency allows users to optimize their workflow through layout customization extensibility supports addition of new panels for specialized functionality responsiveness adapts to different screen sizes and window configurations familiarity follows conventions from other professional editing tools these benefits create an intuitive and efficient editing environment for world creation next steps with an understanding of the editor's panel structure, the next chapter explores how assets are managed and processed within the world editor next asset handling and pipeline docid\ jeqmbwfdvdv8ap1i9ya5f