### Start Development Server (npm) Source: https://context7.com/lukehollis/sphr/llms.txt Starts the development server for local testing and development. This command typically watches for file changes and enables hot-reloading. ```shell npm run start ``` -------------------------------- ### Install Project Dependencies (npm) Source: https://context7.com/lukehollis/sphr/llms.txt Installs all necessary dependencies for the project using npm. Ensure Node.js and npm are installed globally. ```shell npm install ``` -------------------------------- ### Configure SPHR Tour with JSON Source: https://context7.com/lukehollis/sphr/llms.txt Defines the interactive tour elements and scene graph for a SPHR experience using JSON. It specifies audio sources, tourpoints with associated text and sounds, and 3D models to be loaded into the scene. This configuration enables guided navigation and enriched scene interactions. ```json { "audio": { "default": { "url": "https://static.mused.org/sounds/default_oud_96k.mp3", "options": { "loop": true, "volume": 0.1, "autoplay": false } }, "navigate": { "url": "https://static.mused.org/sounds/bassdrum_64k.mp3", "options": { "loop": false, "volume": 0.1, "autoplay": false } } }, "spaces": [ { "id": "2", "type": "spaces", "title": "The Tomb of Nefertari", "tourpoints": [ { "text": "Welcome to the tomb of Nefertari", "zoom": 0, "models": [], "sounds": ["default"], "nodeUUID": "IMG_20231104_065739_00_094", "rotation": { "polar": -2, "azimuth": 46 }, "viewMode": "FPV", "targetType": "NODE", "textPosition": "center" } ] } ], "sceneGraph": [ { "id": "qau_beadnet_dress", "file": "https://static.mused.org/beadnet_dress3.glb", "type": "model", "scale": [1, 1, 1], "position": [0, 0, 0], "rotation": [0, 0, 0], "fileType": "glb" } ], "autoplay": false, "defaultShowText": true } ``` -------------------------------- ### Cursor Component for 3D Interaction - JavaScript Source: https://github.com/lukehollis/sphr/blob/main/README.md The Cursor component renders a visual indicator on the 3D mesh of the virtual space, appearing on top of the 360 images. This component is crucial for providing a photorealistic 3D experience where users interact with the mesh while viewing the images. The current implementation serves as a functional starting point for custom cursors. ```javascript import { Raycaster, Vector2 } from 'three'; export default class Cursor { constructor(camera, scene, domElement) { this.camera = camera; this.scene = scene; this.domElement = domElement; this.raycaster = new Raycaster(); this.mouse = new Vector2(); this.intersectedObject = null; this.domElement.addEventListener('mousemove', this.onMouseMove.bind(this), false); } onMouseMove(event) { // calculate mouse position in normalized device coordinates (-1 to +1) for both components this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1; this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; } update() { this.raycaster.setFromCamera(this.mouse, this.camera); const intersects = this.raycaster.intersectObjects(this.scene.children); if (intersects.length > 0) { if (this.intersectedObject !== intersects[0].object) { // New object intersected if (this.intersectedObject) { // Optionally remove previous cursor effect } this.intersectedObject = intersects[0].object; // Optionally add new cursor effect console.log('Intersected:', this.intersectedObject.name); } } else { if (this.intersectedObject) { // No object intersected now this.intersectedObject = null; // Optionally remove cursor effect } } } } ``` -------------------------------- ### Initialize and Run Application Controller Source: https://context7.com/lukehollis/sphr/llms.txt Initializes and runs the main application controller for the Sphr project. It manages application lifecycle, initializes space components, preloads textures, handles node loading and navigation, and includes an update loop for rendering. ```javascript // App.js - Initialize and run the application import App from './components/App'; const app = new App(); // Initialize space components (EnvCube, Dollhouse, Nodes, Cursor) app.initSpaceComponents(); // Preload initial node textures app.preload(); // Load a specific node's textures app.loadNode(node, () => { console.log('Node loaded:', node.uuid); }); // Navigate to a node with face loading check app.ensureFacesLoadedThenNavigate(targetNode); // Preload nearest nodes for smoother navigation app.preloadNearestNodes(currentNode); // Toggle autoplay for guided tours app.handleToggleAutoplay(); // Update loop (call in animation frame) function animate() { app.update(); requestAnimationFrame(animate); } animate(); ``` -------------------------------- ### Build Project for Production (npm) Source: https://context7.com/lukehollis/sphr/llms.txt Builds the project for production, optimizing assets and code. Supports internationalization by setting the LANG environment variable. ```shell LANG=en npm run build ``` ```shell LANG=ar npm run build ``` ```shell LANG=es npm run build ``` ```shell for lang in en ar es fr de it pt ru ja ko zh-hans tr id hi bn el; do LANG=$lang npm run build done ``` -------------------------------- ### Handle 3D Mesh Navigation with Dollhouse Source: https://context7.com/lukehollis/sphr/llms.txt Manages a low-poly 3D model for cursor interactions and orbit view. It supports showing/hiding the dollhouse, special display during navigation, material restoration, transparency updates, adding/removing occluders, and attaching/detaching transform controls for debugging. ```javascript // Dollhouse.js - Load and manage dollhouse mesh import Dollhouse from './components/Dollhouse'; const dollhouse = new Dollhouse(); // Show/hide dollhouse dollhouse.show(); dollhouse.hide(); // Show during navigation with CubeRenderTarget effect dollhouse.showForNavigation(); // Restore default materials after navigation dollhouse.restoreDefaultMaterials(); // Update transparency based on view mode dollhouse.updateTransparency(); // Add occluders for proper depth rendering in FPV mode dollhouse.addOccluders(); dollhouse.hideOccluders(); dollhouse.showOccluders(); // Transform controls for editing (debug mode) dollhouse.attachToTransformControls(); dollhouse.detachFromTransformControls(); // Update in render loop dollhouse.update(); ``` -------------------------------- ### Configure SPHR Space with JSON Source: https://context7.com/lukehollis/sphr/llms.txt Defines the structure of a virtual space in SPHR using a JSON configuration. It includes details for 360° viewpoint nodes, initial camera settings, and scene adjustments for both general nodes and the dollhouse navigation model. This JSON serves as the primary input for initializing a space. ```json { "nodes": [ { "uuid": "IMG_20231101_074927_00_479", "image": "spaceshare/IMG_20231101_074927_00_479.jpg", "index": 0, "position": { "x": 64.41, "y": 11.99, "z": 3.75 }, "rotation": { "x": -0.467, "y": -1.569, "z": -2.694 }, "resolution": "4096", "floorPosition": { "x": 64.41, "y": 6.67, "z": 3.75 } } ], "initialNode": "IMG_20231104_065739_00_094", "sceneSettings": { "nodes": { "scale": 0.26, "offsetPosition": { "x": 0, "y": 0, "z": 0 }, "offsetRotation": { "x": 0, "y": 0, "z": 0 } }, "dollhouse": { "scale": 1.1, "offsetPosition": { "x": 8.83, "y": 2.16, "z": 2.26 }, "offsetRotation": { "x": 0, "y": -0.22, "z": 0 } } }, "initialRotation": { "polar": -19.4, "azimuth": 44.86 } } ``` -------------------------------- ### Manage 360° Image Rendering with EnvCube Source: https://context7.com/lukehollis/sphr/llms.txt Manages 360° equirectangular images on cube faces with progressive loading. It handles initialization, crossfade navigation between nodes, updating cube faces, progressive loading to full resolution, fade effects, and an update loop. ```javascript // EnvCube.js - Create and manage environment cubes import EnvCube from './components/EnvCube'; // Initialize environment cube manager const envCubeManager = new EnvCube(); // Access main and outgoing cubes const mainCube = envCubeManager.envCube; const outgoingCube = envCubeManager.envCubeOutgoing; // Navigate between nodes with crossfade envCubeManager.crossfade(); // Smoothly transitions between nodes // Update faces for a new node mainCube.node = newNode; mainCube.updateFaces(); // Progressive loading: upgrade visible faces to full resolution const visibleFaces = mainCube.getVisibleFaces(); mainCube.updateFacesFullRes(visibleFaces); // Fade effects envCubeManager.fadeOut(() => { console.log('Fade out complete'); }); envCubeManager.fadeIn(() => { console.log('Fade in complete'); }); // Update in render loop envCubeManager.update(); ``` -------------------------------- ### Manage SPHR State with JavaScript Store Source: https://context7.com/lukehollis/sphr/llms.txt Implements global state management for SPHR using a JavaScript Store pattern with an observer mechanism. It allows for retrieving the current application state, updating it, and subscribing to state changes to react to modifications in navigation, current nodes, or viewing modes. Dependencies include the Three.js library for camera and scene initialization. ```javascript // Store.js - Initialize and manage application state import Store from './Store'; // Get current state const { space, camera, scene, currentNode } = Store.getState(); // Update state and notify listeners Store.setState({ isNavigating: true, currentNode: newNode, viewMode: "FPV" }); // Listen to state changes Store.listen((newState) => { console.log('Navigation status:', newState.isNavigating); console.log('Current node:', newState.currentNode.uuid); }); // Example: Initial store structure const initialStore = { space: spaceConfig.space, camera: new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight), scene: new THREE.Scene(), viewMode: "FPV", currentNode: initialNode, isNavigating: false, zoomLvl: 20, fov: 90, tourGuidedMode: true, materialCache: {}, textures: {} }; ``` -------------------------------- ### Transition Between 360 Images using WebGLCubeRenderTarget - JavaScript Source: https://github.com/lukehollis/sphr/blob/main/README.md This implementation details a complex interaction for transitioning between two 360-degree images using Three.js. It involves the main camera lerping between positions and utilizing a WebGLCubeRenderTarget to render the transition onto the environment map of the Dollhouse. This technique simulates movement between points and is an atypical use of envMap with MeshBasicMaterial, though it is currently memory inefficient and requires further shader development. ```javascript import { WebGLCubeRenderTarget, RGBFormat, LinearMipmapLinearFilter } from 'three'; // Assuming 'scene' and 'camera' are available in the scope // Assuming 'transitionDuration' is defined let currentCubeRenderTarget = null; let nextCubeRenderTarget = null; let transitionStartTime = null; function setupTransition(startImageUrl, endImageUrl, scene, camera, transitionDuration) { // Create Cube Render Targets for the start and end images const size = 512; // Example size, adjust as needed currentCubeRenderTarget = new WebGLCubeRenderTarget(size, { format: RGBFormat, magFilter: LinearMipmapLinearFilter, }); nextCubeRenderTarget = new WebGLCubeRenderTarget(size, { format: RGBFormat, magFilter: LinearMipmapLinearFilter, }); // Load textures and set them to the render targets // This part would involve creating textures from the images and assigning them // For brevity, assuming 'loadTexture' function exists and returns a Texture object const startTexture = loadTexture(startImageUrl); // Placeholder const endTexture = loadTexture(endImageUrl); // Placeholder // Simplified assignment for demonstration. Actual CubeRenderTarget setup is more complex. // You'd typically render a scene from 6 cube camera directions for each. // For a simple envMap transition, you might apply the texture directly if applicable. // Example using a single texture for simplicity (not a true CubeRenderTarget setup): const material = new MeshBasicMaterial({ envMap: currentCubeRenderTarget.texture }); // ... apply this material to the dollhouse or relevant object transitionStartTime = Date.now(); } function updateTransition(deltaTime, dollhouseMesh, transitionDuration) { if (transitionStartTime === null) return; const elapsedTime = Date.now() - transitionStartTime; const progress = Math.min(elapsedTime / (transitionDuration * 1000), 1.0); // Update the envMap of the dollhouse mesh // This is a conceptual representation. Actual interpolation might be needed. if (dollhouseMesh && dollhouseMesh.material.envMap) { // Example: Lerping between two Cube Render Target textures (complex) // Or, if using a simpler approach, blending textures // For a true envMap transition, you'd need to interpolate the cube map faces. // This example simplifies by showing the progress. console.log(`Transition progress: ${progress * 100}%`); // A more accurate approach would involve custom shaders to blend the envMaps. // For MeshBasicMaterial, you might need to create a new texture dynamically or use shaders. if (progress === 1.0) { // Transition complete transitionStartTime = null; // Clean up render targets if necessary } } } // Helper function placeholder function loadTexture(url) { // Implementation to load texture, e.g., using THREE.TextureLoader return null; } ``` -------------------------------- ### Control Navigation and View Modes with CameraHandlers Source: https://context7.com/lukehollis/sphr/llms.txt Handles camera movement, view modes (FPV, ORBIT), and zoom functionality. It allows navigation to specific nodes with defined view parameters, toggling between view modes, setting a specific view mode, and managing zoom levels with smooth transitions. ```javascript // CameraHandlers.js - Navigate between viewpoints import CameraHandlers from './CameraHandlers'; const cameraHandlers = new CameraHandlers(); // Navigate to a node cameraHandlers.handleNavigation(targetNode, { viewMode: "FPV", rotation: { azimuth: 45, polar: -10 }, distance: 10, orbitTarget: new THREE.Vector3(0, 0, 0), position: null }); // Toggle between FPV and ORBIT view modes cameraHandlers.toggleViewMode(); // Set specific view mode cameraHandlers.setViewMode("ORBIT", { doLerp: true, noDollhouse: false }); // Handle zoom cameraHandlers.handleZoom(10); // Zoom in by 10 units // Smooth zoom transition cameraHandlers.lerpToZoom(50); // Lerp to zoom level 50 ``` -------------------------------- ### Webpack Common Configuration (JavaScript) Source: https://context7.com/lukehollis/sphr/llms.txt Common Webpack configuration file used for both development and production builds. It defines entry points, module rules for processing different file types (JS, CSS, assets), and plugins like HtmlWebpackPlugin and CopyWebpackPlugin. ```javascript const HtmlWebpackPlugin = require('html-webpack-plugin'); const CopyWebpackPlugin = require('copy-webpack-plugin'); module.exports = { entry: './src/index.js', module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: ['babel-loader'] }, { test: /\.css$/, use: ['style-loader', 'css-loader', 'postcss-loader'] }, { test: /\.(glb|gltf|jpg|png)$/, type: 'asset/resource' } ] }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }), new CopyWebpackPlugin({ patterns: [ { from: 'static', to: 'static' }, { from: 'data', to: 'data' } ] }) ] }; ``` -------------------------------- ### Render 3D Interactive Cursor Source: https://context7.com/lukehollis/sphr/llms.txt Renders an interactive 3D cursor on mesh surfaces for photorealistic interaction. It includes updating the cursor's position and rotation based on raycasting results and allows configuration of cursor parameters like radius and segments. Visibility is controlled via store state. ```javascript // Cursor.js - Create and update 3D cursor import Cursor from './components/Cursor'; const cursor = new Cursor(); // Update cursor position and rotation from Store // The cursor automatically follows raycasting results cursor.update(); // Cursor parameters cursor.innerRadius = 0.15; cursor.outerRadius = 0.19; cursor.thetaSegments = 64; // Visibility is controlled by cursor position in Store Store.setState({ cursor: { position: new THREE.Vector3(10, 5, 3), rotation: new THREE.Quaternion() }, cursorOpacity: 1 // 0 to 1 }); ``` -------------------------------- ### Manage 3D Models with SceneGraph Source: https://context7.com/lukehollis/sphr/llms.txt Loads and manages 3D models within the scene based on tour configuration. It provides functionality to show/hide models by ID, retrieve model references, hide all models simultaneously, update models in the render loop, and add debug helpers like grids and axes. ```javascript // SceneGraph.js - Manage 3D models from tour configuration import SceneGraph from './components/SceneGraph'; const sceneGraph = new SceneGraph(); // Show/hide models by ID sceneGraph.showModelById('qau_beadnet_dress'); sceneGraph.hideModelById('qau_beadnet_dress'); // Get model reference const model = sceneGraph.getModelById('nefertari_example_jewelry'); if (model) { model.show(); model.position.set(10, 5, 0); } // Hide all models at once sceneGraph.hideAllModels(); // Update all models in render loop sceneGraph.update(); // Add debug helpers (grid and axes) sceneGraph.addHelpers(); ``` -------------------------------- ### Dollhouse Component for Low-Resolution Preview - JavaScript Source: https://github.com/lukehollis/sphr/blob/main/README.md The Dollhouse component provides a low-resolution representation of the 3D captured space. It is primarily used for cursor interactions and the Orbit view mode. The aim is to keep the dollhouse under 50k vertices and 2MB in texture size for performance, though larger sizes are possible depending on project needs. ```javascript import { Mesh, BoxGeometry, MeshBasicMaterial } from 'three'; export default class Dollhouse extends Mesh { constructor(width, height, depth, color = 0x00ff00) { const geometry = new BoxGeometry(width, height, depth); const material = new MeshBasicMaterial({ color: color, wireframe: true }); super(geometry, material); this.name = 'dollhouse'; } // Add methods for updating geometry, material, or position as needed } ``` -------------------------------- ### EnvCube Component for 360 Imagery - JavaScript Source: https://github.com/lukehollis/sphr/blob/main/README.md The EnvCube component handles displaying 360-degree equirectangular images within the SPHR environment. It supports high-resolution images (greater than 8k recommended) and utilizes two EnvCube instances to manage transitions between images. The implementation uses a IIIF image server for progressive loading of textures, though this will be removed in future versions. ```javascript import { Mesh, SphereGeometry, MeshBasicMaterial, TextureLoader } from 'three'; export default class EnvCube extends Mesh { constructor(renderer, imageUrl) { const geometry = new SphereGeometry(500, 60, 40); // invert the geometry on the x-axis so that all faces point inward geometry.scale(-1, 1, 1); const material = new MeshBasicMaterial({ map: new TextureLoader().load(imageUrl) }); super(geometry, material); this.renderer = renderer; this.name = 'envCube'; } updateTexture(newImageUrl) { const loader = new TextureLoader(); this.material.map = loader.load(newImageUrl); this.material.needsUpdate = true; } } ``` -------------------------------- ### SceneGraph and AnnotationGraph for Customizable Scenes - JavaScript Source: https://github.com/lukehollis/sphr/blob/main/README.md SPHR allows for a fully customizable scene graph, differentiating it from other tour builder software. This enables dynamic changes between spaces and focused items. SceneGraph.js is used for managing 3D models, while AnnotationGraph.js handles 2D annotations like embedded images and videos within scenes. ```javascript import { Group } from 'three'; export class SceneGraph extends Group { constructor() { super(); this.name = 'SceneGraph'; } addModel(model, position, rotation, scale) { // Add a 3D model to the scene graph // model: THREE.Object3D or similar // position, rotation, scale: THREE.Vector3 or Euler or similar if (model) { model.position.set(position.x, position.y, position.z); model.rotation.set(rotation.x, rotation.y, rotation.z); model.scale.set(scale.x, scale.y, scale.z); this.add(model); } } removeModel(model) { // Remove a 3D model from the scene graph if (model && this.children.includes(model)) { this.remove(model); } } // Add methods for managing scene hierarchy, transformations, etc. } export class AnnotationGraph extends Group { constructor() { super(); this.name = 'AnnotationGraph'; } addAnnotation(annotation, position) { // Add a 2D annotation (e.g., image, video plane) to the scene // annotation: THREE.Object3D representing the annotation element // position: THREE.Vector3 if (annotation) { annotation.position.set(position.x, position.y, position.z); this.add(annotation); } } removeAnnotation(annotation) { // Remove a 2D annotation if (annotation && this.children.includes(annotation)) { this.remove(annotation); } } // Add methods for managing annotations, visibility, interaction, etc. } ``` -------------------------------- ### Parse SPHR Data from HTML with JavaScript Source: https://context7.com/lukehollis/sphr/llms.txt Provides a JavaScript class `Space.js` to parse SPHR configuration data (space and tour) directly from embedded JSON within HTML script tags. It facilitates the initialization of the SPHR application by extracting `space_data`, `tour_data`, and `ordered_spaces_data` from the DOM. This method simplifies the integration of SPHR into existing web pages. ```javascript // Space.js - Extract configuration from HTML elements import Space from './Space'; // Initialize space from HTML data elements const spaceConfig = new Space(); const space = spaceConfig.space; const tour = spaceConfig.tour; console.log("Loaded space:", space); console.log("Loaded tour:", tour); // HTML structure expected: // // // ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.