Getting Started
Do you want to get to use Teleport.js quickly with a simple example that walks you through its basic features?
Here is a guide on how to code a fully functional HTML page that uses teleport.js to display your capture and navigate around it in a 3D world.
Teleport.js most current version is 0.0.2 and it's available as a minimized ESM module on our CDN at this url:
1. Configuring the Dependencies#
Before loading the module, the browser needs an Import Map to map clean, semantic module specifiers (like "three" or "teleport") to their exact network URLs or local file paths.
Place this block in the <head> of your main HTML file. Teleport.js needs THREE.js and its addons (min v0.180.0).
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.180.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.180.0/examples/jsm/",
"teleport": "https://d1ziouw89q7sp5.cloudfront.net/teleport-js/0.0.2/teleport.module.js"
}
}
</script>
2. Initialization#
Create a single instance of the TELEPORT.Manager by passing the application context.
import * as THREE from "three";
import * as TELEPORT from "teleport";
// Basic THREE.js setup
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: false, logarithmicDepthBuffer: true });
// Instantiate the Teleport.js SDK
const teleportManager = new TELEPORT.Manager({
renderer: renderer,
scene: scene,
camera: camera,
baseApiUrl: "http://localhost:8000" // Points to production by default if omitted
});
3. Loading Captures and Specific Segments/Models#
To load a capture with the default segment/model, call TELEPORT.Manager loadCapture() with its Share ID (sid). To load specific segments/models, specify the segmentEid property inside the initialization options block.
// Example A: Loading a capture
const capture = await teleportManager.loadCapture("524ee89f293a4a2e907009191ba7b9f4");
// Example B: Loading a specific segment/model
const segmentCapture = await teleportManager.loadCapture("70946191310344d9bfc8f33edc4ac6bd", {
segmentEid: "bebdaf1u5rum",
position: [0, 1.5, 0] // Adjust spatial offsets
});
4. Position the Camera#
The TELEPORT.Capture has a startingCamera attribute that can directly applied to a THREE.Camera to setup the initial camera position.
5. Loading and Rendering Camera Poses#
Every Capture contains the positional data of its Camera Poses. They can be rendered with THREE.js in the scene. Retrieve them calling TELEPORT.Capture loadCameras().
const cameras = await capture.loadCameras();
const totalCameraCount = cameras.length;
if (totalCameraCount > 0) {
const geometry = new THREE.TetrahedronGeometry(0.15);
const material = new THREE.MeshStandardMaterial({ roughness: 0.2, flatShading: true });
const instancedMesh = new THREE.InstancedMesh(geometry, material, totalCameraCount);
const dummyMatrix = new THREE.Matrix4();
const dummyScale = new THREE.Vector3(1, 1, 1);
const colorTool = new THREE.Color();
cameras.forEach((cam, index) => {
// Generate a rainbow gradient path tracking chronologically over time
colorTool.setHSL(index / totalCameraCount * 0.7, 1.0, 0.5);
instancedMesh.setColorAt(index, colorTool);
// Apply translation transforms from coordinates
const quat = new THREE.Quaternion().setFromEuler(cam.rotation);
dummyMatrix.compose(cam.position, quat, dummyScale);
instancedMesh.setMatrixAt(index, dummyMatrix);
});
instancedMesh.instanceMatrix.needsUpdate = true;
instancedMesh.instanceColor.needsUpdate = true;
scene.add(instancedMesh);
}
7. Complete Example#
⚠️ All the code above is collected together in the following html page, with the addition of a simple navigation controller provided by THREE.js OrbitControls
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<title>Teleport.js Demo</title>
<style>
body { margin: 0; overflow: hidden; background: #222; }
canvas { display: block; width: 100vw; height: 100vh; }
</style>
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.180.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.180.0/examples/jsm/",
"teleport": "https://d1ziouw89q7sp5.cloudfront.net/teleport-js/0.0.2/teleport.module.js"
}
}
</script>
</head>
<body>
<script type="module">
import * as THREE from "three";
import * as TELEPORT from "teleport";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
// Basic THREE.js setup
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 10000);
const renderer = new THREE.WebGLRenderer({ antialias: false, logarithmicDepthBuffer: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.body.appendChild(renderer.domElement);
// Use THREE.js OrbitControls to add navigation in the scene
const orbitControls = new OrbitControls(camera, renderer.domElement);
orbitControls.enableDamping = false;
orbitControls.minPolarAngle = 0.01;
orbitControls.maxPolarAngle = Math.PI / 2;
// Add lighting so shaded materials are visible
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(5, 10, 7);
scene.add(directionalLight);
// Instantiate the Teleport.js SDK
const teleportManager = new TELEPORT.Manager({
renderer: renderer,
scene: scene,
camera: camera
});
// Loading a capture
const capture = await teleportManager.loadCapture("524ee89f293a4a2e907009191ba7b9f4");
// Setup Initial Camera Positioning via embedded starting viewpoints
if (capture.startingCamera) {
capture.startingCamera.applyTo(camera);
}
// Load and display all the cameras as geometry in the scene
const cameras = await capture.loadCameras();
const totalCameraCount = cameras.length;
if (totalCameraCount > 0) {
const geometry = new THREE.TetrahedronGeometry(0.15);
const material = new THREE.MeshStandardMaterial({ roughness: 0.2, flatShading: true });
const instancedMesh = new THREE.InstancedMesh(geometry, material, totalCameraCount);
const dummyMatrix = new THREE.Matrix4();
const dummyScale = new THREE.Vector3(5, 5, 5);
const colorTool = new THREE.Color();
cameras.forEach((cam, index) => {
// Generate a rainbow gradient path tracking chronologically over time
colorTool.setHSL(index / totalCameraCount * 0.7, 1.0, 0.5);
instancedMesh.setColorAt(index, colorTool);
// Apply translation transforms from coordinates
const quat = new THREE.Quaternion().setFromEuler(cam.rotation);
dummyMatrix.compose(cam.position, quat, dummyScale);
instancedMesh.setMatrixAt(index, dummyMatrix);
});
instancedMesh.instanceMatrix.needsUpdate = true;
instancedMesh.instanceColor.needsUpdate = true;
scene.add(instancedMesh);
}
// Mouse Click places a red ball at the intersection with the splat mesh
let mouseStart = { x: 0, y: 0 };
// How many pixel to differentiate a click from a drag
const CLICK_MAX_DELTA = 4;
window.addEventListener("mousedown", (e) => {
mouseStart.x = e.clientX;
mouseStart.y = e.clientY;
});
window.addEventListener("mouseup", (e) => {
if (Math.abs(e.clientX - mouseStart.x) > CLICK_MAX_DELTA ||
Math.abs(e.clientY - mouseStart.y) > CLICK_MAX_DELTA) {
return; // Drag operation detected, ignore action
}
// Query intersection space against Gaussian points
const hit = teleportManager.raycast(e.clientX, e.clientY, camera);
if (hit) {
console.log(`Hit splat inside capture: ${hit.capture.name}`);
// Spawn a marker at world target position
const marker = new THREE.Mesh(new THREE.SphereGeometry(0.05), new THREE.MeshBasicMaterial({ color: 0xff0000 }));
marker.position.copy(hit.point);
scene.add(marker);
}
});
// Necessary listener to update the renderer after resizing the browser window
window.addEventListener("resize", () => {
const width = window.innerWidth;
const height = window.innerHeight;
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize(width, height);
});
// Animation loop
renderer.setAnimationLoop(() => {
orbitControls.update();
renderer.render(scene, camera);
});
</script>
</body>
</html>