Space Component
The Space component is a core component that renders and manages an interactive 3D space viewer. It handles camera controls, model interactions, and various viewing modes.
Basic Usage
If you just want the base version of boundary explore, with all its features all you have to do is this:
<Space tourId="example-tour"/>You can also be more explicit with the features you want by overriding the html overlay and the 3d scene content. Each feature in boundary explore is a react component. So
import {Space, Overlay,Loading,FloorplanModal,TagModal,Toolbar,Tags,Hotspots,Measurements} from "@the-boundary/sdk"
//--- the rest of the app ---
<Space tourId="example-tour">
<Overlay>
<Loading/>
<FloorplanModal/>
<TagModal/>
<Toolbar/>
</Overlay>
<Scene>
<Tags />
<Hotspots/>
<Measurements />
{/*add any other fiber content here*/}
</Scene>
</Space>When using the Scene and Overlay components, it will override all default components. You’ll need to explicitly add back built in components you want to keep, like Tags, Hotspots, and Measurements etc.
You can now create any react component html or fiber and inject it into the sdk. This is quite a powerful feature. It allows you to place 3d objects into the tour.
Examples
Basic Tour
<Space
tourId="example-tour"
style={{ width: '100%', height: '500px' }}
onJumpEnd={(camera) => console.log('Camera jump completed', camera)}
/>Tour with Custom Overlay Design
<Space
tourId="cm3n04tge0000svl3086s6wuv"
style={{ width: '100%', height: '600px' }}
>
<Overlay>
<FloorplanModal
showCameras
title={"4 Bed Villa"}
subtitle={"Select a room"}
floorItemBuilder={(room,selected,onClick)=><button
onClick={onClick}
style={{
border:"none",
color:"white",
padding:"8px 10px",
fontSize:"18px",
textAlign:"left",
width:"100%",
cursor:"pointer",
pointerEvents:"all",
background: selected? "rgba(255,255,255,0.1)":"none",
borderLeft:selected ? "solid 4px rgb(0,100,255)":"solid 4px rgba(0,0,0,0)",
paddingLeft:"20px"
}}>
{room.name}
</button>}
roomItemBuilder={(room,selected,onClick)=><button
onClick={onClick}
style={{
border:"none",
color:"white",
padding:10,
width:"100%",
textAlign:"left",
background: selected? "rgba(255,255,255,0.2)":"none",
fontSize:"15px",
fontWeight:"300",
borderLeft:selected ? "solid 4px rgb(0,200,255)":"solid 4px rgba(0,0,0,0)",
paddingLeft:"20px"
}}>
{room.name}
</button>}
borderRadius={0}
sidebarProps={{
style:{
"background": "rgba(0,0,0,0.1)",
"borderRadius":"0px",
"padding":"0px",
"color":"white",
border:"none",
"backdropFilter": "blur(20px)",
}
}}
/>
<Toolbar
labelColor='white'
style={{
"background": "rgba(0,0,0,0.1)",
"borderRadius":"0px",
"padding":"10px",
border:"none",
"backdropFilter": "blur(20px)",
}}
variant={'right-center'} />
</Overlay>
</Space>Tour in slave mode
Master Tour
Slave Tour
import { Space } from '@viewform/sdk';
//Variables to sync between slave and master
const [slaveMeasurements,setSlaveMeasurements] = useState([])
const slaveRotation = useRef<Euler>(new Euler(0,0,0,"YXZ"))
const slaveZoom = useRef<number>(0)
const [slaveFloorplanState,setFloorplanState] = useState({
open:false,
floorId:undefined
})
const [slaveKeyframe,setSlaveKeyframe] = useState<Keyframe|undefined>()
//Function to update the slave state
const onRotationChange = useCallback((rotation)=>{
slaveRotation.current = rotation.clone()
},[])
const onFovChange = useCallback((fov)=>{
slaveZoom.current = fov
},[])
const onKeyframe = useCallback((keyframe)=>{
setSlaveKeyframe(keyframe)
},[])
const onFloorplanStateChange = useCallback((state)=>{
setFloorplanState(state)
},[])
const onMeasurements = useCallback((measurements)=>{
setSlaveMeasurements(measurements)
},[])
//SLAVE
<Space
tourId={"cm41fa65900001ycoxqbofdbp"}
slave={slave}
slaveRotation={slaveRotation} //pass a rotation ref to bypass all react updates and shoot it straight into the render loop at 120fps
slaveZoom={slaveZoom} //same as above
slaveState={slaveKeyframe}
>
<Overlay>
<FloorplanModal
floorId={slaveFloorplanState?.floorId}
open={slaveFloorplanState?.open}/>
<Loading/>
</Overlay>
<Scene>
<Measurements data={slaveMeasurements}/>
</Scene>
</Space>
//MASTER
<Space
tourId={"cm41fa65900001ycoxqbofdbp"}
onRotationChange={onRotationChange}
onZoomChange={ onFovChange}
onKeyframe={onJumpStart}
>
<Overlay>
<FloorplanModal onChange={onFloorplanStateChange}/>
<Toolbar/>
<Loading/>
</Overlay>
<Scene>
<Measurements onChange={onMeasurements}/>
</Scene>
</Space>
Props
Data Source Options
| Prop | Type | Default | Description |
|---|---|---|---|
tourId | string | - | Unique identifier to fetch tour data |
tour | IViewformTour | - | Direct tour data object |
path | string | - | Local path to load tour data |
Camera Settings
| Prop | Type | Default | Description |
|---|---|---|---|
resolution | Resolution | - | Forces maximum resolution for tour |
startVersionId | string | - | Initial version ID to load |
startCameraId | string | - | Initial camera position ID |
startCameraRotation | IEuler | - | Initial camera rotation |
startCameraFov | number | - | Initial field of view |
lockFov | boolean | - | Prevents FOV changes |
Slave Mode Settings
| Prop | Type | Default | Description |
|---|---|---|---|
slave | boolean | false | Enables slave mode |
slaveState | Keyframe | - | Current keyframe state in slave mode |
slaveRotation | MutableRefObject<Euler> | - | Rotation reference in slave mode |
slaveZoom | MutableRefObject<number> | - | Zoom reference in slave mode |
Camera Navigation Settings
| Prop | Type | Default | Description |
|---|---|---|---|
jumpMode | JumpMode | - | Camera transition mode |
enableCameraPitchRotation | boolean | false | Enables pitch rotation |
enableYawCorrection | boolean | false | Enables yaw correction |
enablePitchCorrection | boolean | false | Enables pitch correction |
requireCubemapToJump | boolean | false | Requires cubemap for jumps |
Model Settings
| Prop | Type | Default | Description |
|---|---|---|---|
materialOverride | Material | - | Override model materials |
modelViewType | ModelViewType | - | Model viewing mode |
Event Handlers
| Prop | Type | Description |
|---|---|---|
onModelClick | (e: any) => void | Triggered when model is clicked |
onModelPointerMove | (e: any) => void | Triggered when pointer moves over model |
onModelPointerEnter | (e: any) => void | Triggered when pointer enters model |
onModelPointerLeave | (e: any) => void | Triggered when pointer leaves model |
onZoomChange | (value: number) => void | Triggered on zoom changes |
onRotationChange | (value: Euler) => void | Triggered on rotation changes |
onRotationStart | (value: Euler) => void | Triggered when rotation starts |
onRotationEnd | (value: Euler) => void | Triggered when rotation ends |
onJumpStart | (current: ICameraDetails, next: ICameraDetails) => void | Triggered when camera jump starts |
onJumpEnd | (current: ICameraDetails) => void | Triggered when camera jump ends |
onKeyframe | (value: Keyframe) => void | Triggered on keyframe changes |
Styling
| Prop | Type | Description |
|---|---|---|
style | React.CSSProperties | Custom CSS styles |
className | string | Custom CSS class name |
Other Props
| Prop | Type | Default | Description |
|---|---|---|---|
debug | boolean | false | Enables debug mode |
editing | boolean | false | Enables CMS editing mode |
children | ReactNode | - | Child components |