npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

potree-viewer

v0.1.2

Published

Modern, framework-agnostic point cloud viewer built on potree-core and Three.js

Readme

PotreeViewer

Modern, framework-agnostic JavaScript library for visualizing large-scale point clouds in web browsers. Built on potree-core and Three.js.

Lion point cloud Tree measurement White background

Features

  • 🚀 Modern ESM architecture - Clean imports, no global variables
  • 🎯 Framework-agnostic - Works with vanilla JS, React, Vue, or any framework
  • 📏 5 measurement types - Distance, Height, Angle, Radius, and Volume measurements
  • 🎨 Modern UI Components - Toolbar with dropdown menus and Console for measurements
  • 🌈 Multiple color modes - RGB, Elevation, Classification, Intensity, and more
  • 🎥 Named camera views - Quick access to Top, Bottom, Left, Right, Front, Back views
  • Eye-Dome Lighting (EDL) - Enhanced depth perception with customizable shading effect
  • �📦 Lightweight - No jQuery or legacy dependencies
  • 🔧 Full API - Programmatic control over viewer, measurements, and camera
  • 🎬 Event-driven - Subscribe to viewer events for custom integrations

Quick Start

Installation

Local Development

This library is currently in development and not yet published to npm.

# Install dependencies
cd viewer-lib
npm install

Dependencies:

  • three - Three.js 3D library
  • potree-core - Core Potree point cloud rendering engine

Minimal Example

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>PotreeViewer Demo</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    #viewer {
      width: 100vw;
      height: 100vh;
    }
  </style>
</head>
<body>
  <div id="viewer"></div>

  <script type="module">
    import { PotreeViewer } from './viewer-lib/src/index.js';

    const viewer = new PotreeViewer({
      container: document.getElementById('viewer'),
      pointCloudUrl: 'path/to/metadata.json',
      pointCloudName: 'My Point Cloud',
      autoFitOnLoad: true,
    });
  </script>
</body>
</html>

Complete Example with UI

import { PotreeViewer, Toolbar, PotreeViewerConsole } from 'potree-viewer';

// Create viewer
const viewer = new PotreeViewer({
  container: document.getElementById('viewer'),
  pointCloudUrl: '/pointcloud/metadata.json',
  pointCloudName: 'Forest Scan',
  description: 'LiDAR scan of forest area',
  pointBudget: 1_000_000,
  fov: 80,
  initialView: 'right',
  material: {
    size: 0.6,
    minSize: 0.4,
    pointSizeType: 'FIXED',
    shape: 'SQUARE',
  },
  background: 'black',
  autoFitOnLoad: true,

  // Callbacks
  onReady: (viewerInstance) => {
    console.log('Viewer ready!', viewerInstance);
  },
  onPointCloudLoaded: (pointCloud) => {
    console.log('Point cloud loaded:', pointCloud);
  },
  onError: (error) => {
    console.error('Viewer error:', error);
  }
});

// Create toolbar with measurement and view controls
const toolbar = new Toolbar(viewer, {
  alignment: 'top-right'
});

// Create console for status messages and measurement results
const console = new PotreeViewerConsole(viewer, {
  position: 'bottom-left',
  width: '360px',
  collapsed: false,
  showTimestamp: true,
  visible: true
});

// Keyboard shortcut to toggle console (Ctrl+`)
window.addEventListener('keydown', (e) => {
  if (e.ctrlKey && e.key === '`') {
    console.toggleVisibility();
  }
});

// Clean up on page unload
window.addEventListener('beforeunload', () => {
  toolbar.dispose();
  console.dispose();
  viewer.dispose();
});

Configuration

PotreeViewer Options

const viewer = new PotreeViewer({
  // Required
  container: HTMLElement,              // DOM element to render into

  // Point cloud settings
  pointCloudUrl: string,               // Path to metadata.json
  pointCloudName: string,              // Display name (default: 'pointcloud')
  description: string,                 // Description text

  // Viewer settings
  pointBudget: number,                 // Max visible points (default: 1,000,000)
  fov: number,                         // Field of view in degrees (default: 80)

  // Eye-Dome Lighting (EDL) settings
  edl: {
    enabled: boolean,                  // Enable EDL (default: false)
    strength: number,                  // Shading intensity 0.0-2.0 (default: 0.4)
    radius: number,                    // Sampling radius 0.5-3.0 (default: 1.4)
    opacity: number,                   // Effect opacity 0.0-1.0 (default: 1.0)
    pointCloudLayer: number,           // Render layer (default: 1)
    neighbourCount: number,            // Neighbor samples (default: 8)
  },

  // Initial view
  initialView: 'top' | 'bottom' | 'front' | 'back' | 'left' | 'right' |
               { position: {x, y, z}, target: {x, y, z} },

  // Material settings
  material: {
    size: number,                      // Point size (default: 0.6)
    minSize: number,                   // Min point size (default: 0.4)
    pointSizeType: 'FIXED' | 'ATTENUATED' | 'ADAPTIVE',
    shape: 'SQUARE' | 'CIRCLE',
  },

  // Background
  background: 'black' | 'white' | 'gradient' | '#hexcolor',

  // Behavior
  autoFitOnLoad: boolean,              // Auto-fit camera to point cloud
  loadSettingsFromUrl: boolean,        // Load settings from URL params

  // Callbacks
  onReady: (viewer) => void,
  onPointCloudLoaded: (pointCloud) => void,
  onError: (error) => void,
});

Toolbar Options

const toolbar = new Toolbar(viewer, {
  alignment: 'top-right',  // Position of toolbar
  // Options: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' |
  //          'left' | 'right' | 'top' | 'bottom'

  buttons: [...],          // Custom button configuration (optional)
});

Default toolbar buttons:

  1. Fit to Screen - Automatically fits the point cloud to the viewport
  2. View & Appearance dropdown with:
    • Camera Views: Left, Right, Front, Back, Top, Bottom
    • Point Color Mode: RGB, Elevation, Classification, Intensity, Intensity Gradient, Return Number, Source ID, Normal, Level of Detail
    • Background: Black, White, Gradient, Skybox
  3. Measurements dropdown with:
    • Distance, Height, Angle, Radius, Volume
  4. Clear Measurements (X button) - Clears all measurements and exits measurement mode (disabled when no measurements exist)
  5. Settings dropdown with:
    • Eye-Dome Lighting (EDL) - Toggle and configure depth enhancement effect
      • Enable/Disable toggle
      • Strength slider (0.0 - 2.0) - Shading intensity
      • Radius slider (0.5 - 3.0) - Sampling radius
      • Opacity slider (0.0 - 1.0) - Effect opacity
    • Point Budget slider (100K - 10M points) - Controls maximum number of visible points
    • Field of View slider (20° - 100°) - Controls camera perspective
    • Point Size slider (0.1 - 5.0)
    • Point Shape (Square / Circle)
    • Point Size Type (Fixed / Attenuated / Adaptive)

PotreeViewerConsole Options

const console = new PotreeViewerConsole(viewer, {
  position: 'bottom-left', // Position of console
  // Options: 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right'

  width: '360px',          // Console width
  collapsed: false,        // Start collapsed
  showTimestamp: true,     // Show timestamp for each message
  visible: true,           // Initially visible
  maxMessages: 50,         // Maximum messages to keep

  // Log level filtering
  logLevel: 'info',        // 'debug' | 'info' | 'warning' | 'error' | 'none'
  // 'debug' - Show all messages including debug info
  // 'info' - Show info, warnings, and errors (default)
  // 'warning' - Show warnings and errors only
  // 'error' - Show errors only
  // 'none' - Disable all logging
});

Log Levels Explained:

  • debug - Detailed technical information useful for development and troubleshooting
  • info - General informational messages about viewer operations (default level)
  • warning - Warning messages that don't prevent operation but may indicate issues
  • error - Error messages for failures and critical problems

The viewer automatically logs important operations:

  • Point cloud loading and initialization
  • Camera view changes
  • Measurement operations (adding points, completing measurements)
  • Point budget and FOV changes
  • Color mode switches

Examples:

// Set log level at creation
const console = new PotreeViewerConsole(viewer, { logLevel: 'debug' });

// Change log level dynamically
console.setLogLevel('warning'); // Only show warnings and errors
console.setLogLevel('debug');   // Show all messages

// Get current log level
const level = console.getLogLevel(); // returns 'debug', 'info', 'warning', 'error', or 'none'

API Reference

Complete Method Reference

Below is a complete list of all public methods available on the PotreeViewer instance:

Camera & View

  • setView(position, target) - Set camera position and target
  • setNamedView(viewName) - Set predefined view ('top', 'bottom', 'front', 'back', 'left', 'right')
  • getNamedView() - Get current named view or 'custom'
  • setFov(fov) - Set camera field of view in degrees (30 - 120)
  • fitToScreen() - Fit point cloud to viewport

Point Cloud Management

  • loadPointCloud(url, name) - Load a point cloud (returns Promise)
  • setPointBudget(budget) - Set maximum visible points (default: 1,000,000)
  • setBackground(background) - Set background ('black', 'white', 'gradient', 'skybox', or hex color)

Point Appearance

  • setPointColorType(colorType) - Set point coloring mode (use PointColorType enum)
  • getPointColorType() - Get current color type
  • setPointSize(size) - Set point size in pixels (0.1 - 5.0)
  • setPointOpacity(opacity) - Set point opacity (0.0 - 1.0)
  • setPointShape(shape) - Set point shape ('circle' or 'square')
  • setPointSizeType(type) - Set size scaling ('fixed', 'attenuated', or 'adaptive')

Eye-Dome Lighting (EDL)

  • enableEDL() - Enable EDL effect
  • disableEDL() - Disable EDL effect
  • toggleEDL() - Toggle EDL on/off (returns new state)
  • isEDLEnabled() - Check if EDL is enabled
  • setEDLStrength(strength) - Set EDL strength (0.0 - 2.0)
  • setEDLRadius(radius) - Set EDL radius (0.5 - 3.0)
  • setEDLOpacity(opacity) - Set EDL opacity (0.0 - 1.0)
  • setEDLSettings(options) - Set multiple EDL parameters at once
  • getEDLSettings() - Get current EDL configuration
  • getEDLInternalState() - Get EDL internal state (for debugging)

Measurements

  • setMeasurementMode(mode) - Set measurement mode ('none', 'distance', 'height', 'angle', 'radius', 'volume')
  • getMeasurementMode() - Get current measurement mode
  • startMeasurement(type) - Programmatically start a measurement
  • finishMeasurement(id) - Finish a measurement by ID
  • getMeasurements() - Get array of all measurement summaries
  • removeMeasurement(id) - Remove a specific measurement
  • clearMeasurements() - Clear all measurements

Advanced Access

  • getPotree() - Get underlying Potree instance
  • getScene() - Get Three.js scene
  • getCamera() - Get Three.js camera
  • getRenderer() - Get Three.js WebGL renderer
  • getConsole() - Get PotreeViewerConsole instance (if attached)
  • recenterOnObject() - Set OrbitControls target to point cloud center

Lifecycle

  • dispose() - Clean up and free all resources

Detailed Usage Examples

Camera & View Control

// Set camera position and target
viewer.setView(
  { x: 10, y: 10, z: 10 },  // position
  { x: 0, y: 0, z: 0 }      // target
);

// Set predefined view
viewer.setNamedView('top' | 'bottom' | 'front' | 'back' | 'left' | 'right');

// Get current view name
const viewName = viewer.getNamedView(); // returns view name or 'custom'

// Set field of view (controls camera perspective)
viewer.setFov(60);  // degrees (30 - 120), default: 80

// Fit point cloud to screen
viewer.fitToScreen();

Point Cloud Management

// Load additional point cloud
await viewer.loadPointCloud('path/to/metadata.json', 'cloud-name');

// Set point budget
viewer.setPointBudget(2_000_000);

// Set background
viewer.setBackground('white');
viewer.setBackground('#87CEEB');

Point Appearance

import { PointColorType, PointSizeType, PointShape } from 'potree-core';

// Point Color Mode
viewer.setPointColorType(PointColorType.RGB);           // RGB colors (default)
viewer.setPointColorType(PointColorType.CLASSIFICATION); // LAS classification
viewer.setPointColorType(PointColorType.ELEVATION);     // Height-based gradient
viewer.setPointColorType(PointColorType.INTENSITY);     // Intensity-based
const colorType = viewer.getPointColorType();           // Get current color type

// Point Size
viewer.setPointSize(1.5);  // Set size in pixels (0.1 - 5.0)

// Point Opacity
viewer.setPointOpacity(0.8);  // Set opacity (0.0 - 1.0), default: 1.0

// Point Shape
viewer.setPointShape('circle');  // 'circle' or 'square'

// Point Size Type (how size scales with distance)
viewer.setPointSizeType('adaptive');  // 'fixed', 'attenuated', or 'adaptive'

Available PointColorType values:

  • RGB - RGB colors from point cloud data
  • CLASSIFICATION - LAS classification colors (ground=brown, vegetation=green)
  • ELEVATION - Height-based gradient
  • INTENSITY - Intensity-based colors
  • INTENSITY_GRADIENT - Intensity with gradient colors
  • RETURN_NUMBER - LiDAR return number
  • SOURCE - Source ID
  • NORMAL - Surface normals
  • LOD - Level of detail
  • DEPTH - Distance from camera (if available)

Eye-Dome Lighting (EDL)

EDL enhances depth perception by applying a shading effect based on point depth differences. It's particularly useful for RGB point clouds where depth is hard to perceive.

// Enable/Disable EDL
viewer.enableEDL();   // Enable with current settings
viewer.disableEDL();  // Disable EDL
viewer.toggleEDL();   // Toggle on/off (returns new state: true/false)

// Check if enabled
const isEnabled = viewer.isEDLEnabled(); // returns true/false

// Configure EDL parameters
viewer.setEDLStrength(1.2);  // Intensity of shading (0.0 - 2.0)
viewer.setEDLRadius(2.0);    // Sampling radius in pixels (0.5 - 3.0)
viewer.setEDLOpacity(0.8);   // Effect opacity (0.0 - 1.0)

// Set multiple parameters at once
viewer.setEDLSettings({
  enabled: true,
  strength: 1.5,
  radius: 2.0,
  opacity: 1.0
});

// Get current settings
const edlSettings = viewer.getEDLSettings();
// Returns: { enabled, strength, radius, opacity, pointCloudLayer, neighbourCount }

// Initialize viewer with EDL enabled
const viewer = new PotreeViewer({
  container: document.getElementById('viewer'),
  pointCloudUrl: 'cloud/metadata.json',
  edl: {
    enabled: true,
    strength: 0.8,
    radius: 1.6,
    opacity: 1.0
  }
});

EDL Parameters Explained:

  • strength - Controls the intensity of the depth-based shading effect (0.0 = no effect, 2.0 = maximum)
  • radius - Sampling radius in screen pixels for neighbor points (larger = smoother but less detailed)
  • opacity - Blending opacity of the EDL effect (1.0 = full effect, 0.0 = invisible)
  • pointCloudLayer - WebGL render layer for point cloud (typically 1, advanced use only)
  • neighbourCount - Number of neighbor samples (8 or 4, advanced use only)

Important: When updating EDL parameters at runtime, always ensure you're passing the complete configuration. The setEDL*() methods handle this automatically, but if you're using setEDLSettings() or working with the underlying potreeRenderer.setEDL() directly, use the spread operator:

// ✅ Correct - passes all properties
const edl = viewer.getEDLSettings();
edl.strength = 2.0;
viewer.setEDLSettings({ ...edl });

// ❌ Wrong - may disable EDL or not update properly
viewer.setEDLSettings({ strength: 2.0 }); // Missing other properties!

Measurements

// Set measurement mode
viewer.setMeasurementMode('distance');  // Distance measurement
viewer.setMeasurementMode('height');    // Height measurement
viewer.setMeasurementMode('angle');     // Angle measurement
viewer.setMeasurementMode('radius');    // Radius measurement
viewer.setMeasurementMode('volume');    // Volume measurement
viewer.setMeasurementMode('none');      // Return to navigation mode

// Get current mode
const mode = viewer.getMeasurementMode();

// Programmatic measurement control
const measurement = viewer.startMeasurement('distance');
viewer.finishMeasurement(measurement.id);
viewer.removeMeasurement(measurement.id);
viewer.clearMeasurements();

// Get all measurements
const measurements = viewer.getMeasurements();
// Returns array of measurement summaries:
// [{
//   id: 'measurement-123',
//   type: 'distance' | 'height' | 'angle' | 'radius' | 'volume',
//   points: [{ x, y, z }, { x, y, z }, ...],
//   result: { /* measurement-specific results */ }
// }, ...]

Advanced Access

// Get underlying instances (for advanced use)
const potree = viewer.getPotree();      // Potree instance
const scene = viewer.getScene();        // Three.js scene
const camera = viewer.getCamera();      // Three.js camera
const renderer = viewer.getRenderer();  // Three.js renderer
const console = viewer.getConsole();    // PotreeViewerConsole instance (if attached)

// Recenter camera target on point cloud
viewer.recenterOnObject();

Cleanup

// Dispose viewer and free resources
viewer.dispose();

Toolbar Methods

// Create toolbar
const toolbar = new Toolbar(viewer, options);

// Dispose toolbar
toolbar.dispose();

Console Methods

// Show/hide console
console.show();
console.hide();
console.toggleVisibility();
console.isVisible(); // returns true/false

// Toggle collapsed state
console.toggle();

// Clear all messages
console.clear();

// Add custom messages (filtered by log level)
console.log('Message', 'info');    // Generic log method
console.debug('Debug info');        // Debug messages (shown only with logLevel='debug')
console.info('Information');        // Info messages
console.warn('Warning message');    // Warning messages
console.error('Error message');     // Error messages

// Legacy log method with type parameter
console.log('Success!', 'success');
console.log('Warning!', 'warning');
console.log('Error!', 'error');

// Manage log level
console.setLogLevel('debug');      // Change log level dynamically
const level = console.getLogLevel(); // Get current log level

// Dispose console
console.dispose();

Events

The viewer uses an event system for notifications. Subscribe to events using viewer.on(eventName, callback) and unsubscribe with viewer.off(eventName, callback).

Available Events:

  • ready - Viewer initialized
  • error - Error occurred
  • pointcloud-loaded - Point cloud loaded successfully
  • view-changed - Camera position/target changed
  • measurement-started - New measurement created
  • measurement-updated - Point added to current measurement
  • measurement-finished - Measurement completed
  • measurement-mode-changed - Measurement mode changed
  • measurements-cleared - All measurements cleared
  • color-type-changed - Point color mode changed
  • background-changed - Background changed
  • edl-changed - EDL settings changed

Subscribe to viewer events:

// Viewer lifecycle
viewer.on('ready', (viewerInstance) => {
  console.log('Viewer initialized');
});

viewer.on('error', (error) => {
  console.error('Error:', error);
});

// Point cloud events
viewer.on('pointcloud-loaded', (pointCloud) => {
  console.log('Point cloud loaded:', pointCloud.name);
});

// View events
viewer.on('view-changed', ({ namedView, position, target }) => {
  console.log('Camera moved to:', namedView);
});

// Measurement events
viewer.on('measurement-started', (measurement) => {
  console.log('Measurement started:', measurement.type);
  // Payload: { id, type, points: [], result: {} }
  // Note: measurement object is created but has no points yet
});

viewer.on('measurement-updated', (measurement) => {
  console.log('Point added:', measurement.points.length);
  // Payload: { id, type, points: [{ x, y, z }, ...], result: {...} }
  // Fired every time a point is added to the current measurement
});

viewer.on('measurement-finished', (measurement) => {
  console.log('Measurement complete:', measurement.result);
  // Payload: { id, type, points: [{ x, y, z }, ...], result: {...} }
  // Fired when measurement is completed (Enter key or required points reached)
});

viewer.on('measurement-mode-changed', (mode) => {
  console.log('Measurement mode:', mode);
  // Payload: string - 'none' | 'distance' | 'height' | 'angle' | 'radius' | 'volume'
});

viewer.on('measurements-cleared', () => {
  console.log('All measurements cleared');
  // No payload
});

// Appearance events
viewer.on('color-type-changed', (colorType) => {
  console.log('Color type changed:', colorType);
  // Payload: number - PointColorType enum value
});

viewer.on('background-changed', (background) => {
  console.log('Background changed:', background);
  // Payload: string - 'black' | 'white' | 'gradient' | 'skybox' | hex color
});

viewer.on('edl-changed', (settings) => {
  console.log('EDL settings changed:', settings);
  // Payload: object - { enabled?, strength?, radius?, opacity? }
  // Only changed properties are included in the payload
});

// Unsubscribe
viewer.off('ready', handler);

Measurements

All measurements are interactive - click on the point cloud to add measurement points. The Clear button (X) becomes enabled as soon as you add the first point and allows you to clear all measurements and exit measurement mode.

Distance Measurement

Click multiple points to create line segments. Press Enter to finish or ESC to cancel.

// Start measurement
viewer.setMeasurementMode('distance');

// Result format from getMeasurements()
{
  id: 'measurement-123',
  type: 'distance',
  points: [{ x, y, z }, { x, y, z }, ...],
  result: {
    distanceTotal: 45.67  // Total distance in meters
  }
}
// Note: Internal measurement objects also have a 'finished' property

Height Measurement

Click 2 points to measure vertical (Y-axis) difference.

// Start measurement
viewer.setMeasurementMode('height');

// Result format from getMeasurements()
{
  id: 'measurement-456',
  type: 'height',
  points: [{ x, y, z }, { x, y, z }],
  result: {
    deltaY: 12.34,        // Vertical difference in meters
    height: 12.34,        // Alias for deltaY
    distance3D: 15.67     // 3D distance in meters
  }
}
// Automatically finishes after 2 points

Angle Measurement

Click 3 points to measure angle formed by the points (vertex is the second point).

// Start measurement
viewer.setMeasurementMode('angle');

// Result format from getMeasurements()
{
  id: 'measurement-789',
  type: 'angle',
  points: [{ x, y, z }, { x, y, z }, { x, y, z }],
  result: {
    angleDegrees: 45.5,   // Angle in degrees (0-180)
    angleRadians: 0.794,  // Angle in radians
    vertex: { x, y, z }   // Vertex position
  }
}
// Automatically finishes after 3 points

Radius Measurement

Click 2 points to define circle radius: center point and edge point.

// Start measurement
viewer.setMeasurementMode('radius');

// Result format from getMeasurements()
{
  id: 'measurement-abc',
  type: 'radius',
  points: [{ x, y, z }, { x, y, z }],
  result: {
    radius: 5.67,         // Radius in meters
    diameter: 11.34,      // Diameter in meters
    circumference: 35.61, // Circumference in meters
    area: 101.09,         // Circle area in square meters
    center: { x, y, z }   // Center position
  }
}
// Automatically finishes after 2 points

Volume Measurement

Click 2 points to define sphere volume: center point and radius point. Calculates the volume of point cloud data within the sphere using voxel grid method.

// Start measurement
viewer.setMeasurementMode('volume');

// Result format from getMeasurements()
{
  id: 'measurement-def',
  type: 'volume',
  points: [{ x, y, z }, { x, y, z }],
  result: {
    volume: 123.45,       // Volume in cubic meters (calculated from point cloud data within sphere)
    radius: 3.14,         // Average radius in meters
    radii: {              // Ellipsoid radii (rx, ry, rz)
      rx: 3.14,
      ry: 3.14,
      rz: 3.14
    },
    surfaceArea: 123.97,  // Sphere surface area in square meters
    center: { x, y, z },  // Center position
    pointCount: 12345,    // Number of points within sphere
    voxelSize: 0.1        // Voxel size used for volume calculation
  }
}
// Automatically finishes after 2 points

Keyboard shortcuts for measurements:

  • ESC - Cancel current measurement and exit measurement mode
  • Enter - Finish current measurement (for distance measurements only; other types auto-finish)
  • Right mouse button - Rotate camera while in measurement mode

Framework Integration

React

import { useEffect, useRef } from 'react';
import { PotreeViewer, Toolbar, PotreeViewerConsole } from 'potree-viewer';

function PointCloudViewer({ pointCloudUrl }) {
  const containerRef = useRef();
  const viewerRef = useRef();
  const toolbarRef = useRef();
  const consoleRef = useRef();

  useEffect(() => {
    // Initialize viewer
    viewerRef.current = new PotreeViewer({
      container: containerRef.current,
      pointCloudUrl,
      autoFitOnLoad: true,
    });

    // Create toolbar
    toolbarRef.current = new Toolbar(viewerRef.current);

    // Create console
    consoleRef.current = new PotreeViewerConsole(viewerRef.current, {
      position: 'bottom-left',
    });

    // Cleanup
    return () => {
      consoleRef.current?.dispose();
      toolbarRef.current?.dispose();
      viewerRef.current?.dispose();
    };
  }, [pointCloudUrl]);

  return <div ref={containerRef} style={{ width: '100%', height: '100vh' }} />;
}

Vue 3

<template>
  <div ref="container" style="width: 100%; height: 100vh"></div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import { PotreeViewer, Toolbar, PotreeViewerConsole } from 'potree-viewer';

const props = defineProps({
  pointCloudUrl: String
});

const container = ref(null);
let viewer = null;
let toolbar = null;
let viewerConsole = null;

onMounted(() => {
  viewer = new PotreeViewer({
    container: container.value,
    pointCloudUrl: props.pointCloudUrl,
    autoFitOnLoad: true,
  });

  toolbar = new Toolbar(viewer);
  viewerConsole = new PotreeViewerConsole(viewer);
});

onUnmounted(() => {
  viewerConsole?.dispose();
  toolbar?.dispose();
  viewer?.dispose();
});
</script>

Vanilla JavaScript

import { PotreeViewer, Toolbar, PotreeViewerConsole } from 'potree-viewer';

const viewer = new PotreeViewer({
  container: document.getElementById('viewer'),
  pointCloudUrl: 'cloud/metadata.json',
  autoFitOnLoad: true,
});

const toolbar = new Toolbar(viewer, {
  alignment: 'top-right'
});

const console = new PotreeViewerConsole(viewer, {
  position: 'bottom-left',
  visible: true
});

// Custom button interactions
document.getElementById('measure-distance').addEventListener('click', () => {
  viewer.setMeasurementMode('distance');
});

document.getElementById('view-top').addEventListener('click', () => {
  viewer.setNamedView('top');
});

// Listen to measurement results
viewer.on('measurement-finished', (measurement) => {
  console.log('Measurement result:', measurement.result);
});

Advanced Usage

Custom Toolbar Buttons

const toolbar = new Toolbar(viewer, {
  alignment: 'top-right',
  buttons: [
    {
      id: 'custom-action',
      group: 'custom',
      label: 'My Custom Action',
      icon: '<svg>...</svg>',
      action: () => {
        console.log('Custom action clicked');
      }
    },
    // ... include default buttons if needed
  ]
});

Direct Three.js Scene Access

const scene = viewer.getScene();
const camera = viewer.getCamera();
const renderer = viewer.getRenderer();

// Add custom 3D objects
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

Load Multiple Point Clouds

const viewer = new PotreeViewer({
  container: document.getElementById('viewer'),
});

await viewer.loadPointCloud('cloud1/metadata.json', 'Building A');
await viewer.loadPointCloud('cloud2/metadata.json', 'Building B');

Custom View on Load

const viewer = new PotreeViewer({
  container: document.getElementById('viewer'),
  pointCloudUrl: 'cloud/metadata.json',
  initialView: {
    position: { x: 100, y: 50, z: 100 },
    target: { x: 0, y: 0, z: 0 }
  }
});

Point Cloud Data Preparation

Use PotreeConverter to prepare your point cloud data:

./PotreeConverter input.laz -o output_directory

Supported input formats: LAS, LAZ, PLY, PTX, XYZ (via TXT2LAS)

The converter will generate:

  • metadata.json - Point cloud metadata
  • octree.bin - Octree structure
  • hierarchy.bin - Hierarchy data
  • Individual node files

Browser Compatibility

  • Modern browsers with WebGL support (Chrome, Firefox, Edge, Safari)
  • Requires ES module support
  • No IE11 support

Development

Running the Demo

cd viewer-lib
npm install
npm run dev

Demo will open at http://localhost:3000/demo.html

Building for Production

npm run build

Project Structure

viewer-lib/
├── src/
│   ├── index.js                  # Main exports
│   ├── PotreeViewer.js           # Main viewer class
│   ├── utils/
│   │   ├── EventEmitter.js       # Event system
│   │   ├── config.js             # Configuration
│   │   └── TextSprite.js         # Text labels
│   ├── measurements/
│   │   ├── Measurement.js        # Base class
│   │   ├── DistanceMeasurement.js
│   │   ├── HeightMeasurement.js
│   │   ├── AngleMeasurement.js
│   │   ├── RadiusMeasurement.js
│   │   ├── VolumeMeasurement.js
│   │   └── MeasurementManager.js
│   └── ui/
│       ├── Toolbar.js            # UI toolbar component
│       └── PotreeViewerConsole.js # Console component
├── demo.html                     # Demo page
├── package.json
├── vite.config.js
└── README.md

Troubleshooting

"Cannot find module 'three'"

cd viewer-lib
npm install three potree-core

Point cloud not loading

  • Check the path to metadata.json is correct
  • Open browser console for detailed error messages
  • Ensure server is serving point cloud files correctly
  • Verify CORS headers if loading from different origin

Webpack/Bundler issues

Add to your bundler configuration:

resolve: {
  extensions: ['.js', '.json'],
  alias: {
    'three': path.resolve(__dirname, 'node_modules/three'),
  }
}

Current Status

This library is under active development. Current features:

  • ✅ Point cloud loading and rendering
  • ✅ 5 measurement types (Distance, Height, Angle, Radius, Volume)
  • ✅ Modern toolbar with dropdown menus
  • ✅ Console for measurement results
  • ✅ Multiple color modes
  • ✅ Named camera views
  • ✅ Eye-Dome Lighting (EDL) for enhanced depth perception
  • ✅ Point appearance controls (size, shape, size type)
  • ✅ Multiple background options
  • ✅ Event system for integrations
  • ⏳ Publishing to npm (planned)

License

MIT

Credits