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

@stereos/sdk

v0.1.3

Published

Client SDK for Stereos - Convert Gaussian splats to glTF

Readme

@stereos/sdk

npm version License: MIT

Client SDK for Stereos — Convert 3D Gaussian splats to optimized glTF/glb format entirely in the browser using WebAssembly.

Features

  • 🚀 Browser-native processing — All conversion happens client-side via WebAssembly
  • 📦 Zero dependencies — Lightweight SDK with no external runtime dependencies
  • 🔐 Secure token-based auth — Short-lived JWTs for safe API access
  • 🧹 Built-in cleaning — Remove low-quality splats automatically
  • 🗜️ Advanced compression — Position quantization and meshopt compression support
  • 🎨 View-dependent rendering — Optional full spherical harmonics export

Installation

npm install @stereos/sdk

Quick Start

import { Stereos } from '@stereos/sdk';

// Initialize with your API key
const stereos = new Stereos({ apiKey: 'sk_live_...' });

// Convert a PLY file to glb
const result = await stereos.convert(plyFile);

// Download the result
Stereos.download(result);

Architecture

Overview

┌─────────────────────────────────────────────────────────────┐
│                     Your Application                         │
├─────────────────────────────────────────────────────────────┤
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────────┐  │
│  │  Stereos    │───▶│  WASM Core  │───▶│  glTF/glb Output │  │
│  │   Client    │    │ (stereos-wasm)│   │                  │  │
│  └─────────────┘    └─────────────┘    └─────────────────┘  │
│         │                                                    │
│         ▼                                                    │
│  ┌─────────────┐                                             │
│  │  Token API  │  (Secure short-lived JWT authentication)     │
│  └─────────────┘                                             │
└─────────────────────────────────────────────────────────────┘

Components

1. Stereos Client (src/client.ts)

The main SDK class that orchestrates:

  • Token management: Automatically fetches and caches JWT tokens from the API
  • WASM loading: Lazy-loads the WebAssembly module on first use
  • Conversion pipeline: Handles file reading, WASM execution, and result formatting
class Stereos {
  private apiKey: string;
  private wasm: WasmModule | null;
  private token: string | null;
  
  async convert(file, options): Promise<ConvertResult>
  async validateToken(): Promise<TokenClaims>
  static download(result): void
}

2. WASM Module (wasm/)

Compiled from Rust (crates/stereos-wasm) using wasm-bindgen:

  • Core processing: PLY parsing, cleaning algorithms, glTF generation
  • Zero-copy: Efficient memory sharing between JS and WASM
  • Streaming: Supports incremental processing of large files

3. Types (src/types.ts)

TypeScript interfaces for:

  • Configuration options
  • API responses
  • Conversion results
  • Cleaning statistics

API Reference

Stereos Class

Constructor

new Stereos(options: StereosOptions): Stereos

| Option | Type | Required | Description | |--------|------|----------|-------------| | apiKey | string | ✅ | Your Stereos API key |

Methods

convert(file, options?)

Convert a PLY file to glTF/glb format.

async convert(
  file: File | Blob | ArrayBuffer | Uint8Array,
  options?: ConvertOptions
): Promise<ConvertResult>

ConvertOptions:

| Option | Type | Default | Description | |--------|------|---------|-------------| | format | 'glb' \| 'gltf' | 'glb' | Output format | | quantizeColors | boolean | true | Quantize colors to u8 | | exportFullSh | boolean | false | Export all 48 SH coefficients | | quantizePositions | boolean | false | Quantize positions to i16 | | meshoptCompression | boolean | false | Enable meshopt compression | | clean | boolean \| CleanOptions | false | Enable cleaning/filtering |

CleanOptions (when clean is an object):

| Option | Type | Default | Description | |--------|------|---------|-------------| | minOpacity | number | 0.005 | Remove splats below this opacity | | minScale | number | 0.0001 | Remove splats smaller than this | | outlierSigma | number | — | Remove outliers N std devs from centroid |

validateToken()

Validate the current token and return its claims.

async validateToken(): Promise<TokenClaims>

Returns:

interface TokenClaims {
  sub: string;           // API key ID
  exp: number;           // Expiration timestamp
  iat: number;           // Issued at timestamp
  conversions_remaining: number;
  max_file_size: number;
  formats: string[];
}
version()

Get the SDK/WASM version.

async version(): Promise<string>
Stereos.download(result) (static)

Trigger a browser download of the conversion result.

static download(result: ConvertResult): void
Stereos.createDownloadUrl(result) (static)

Create a blob URL for the conversion result.

static createDownloadUrl(result: ConvertResult): string

Types Reference

Core Types

StereosOptions

interface StereosOptions {
  /** Your API key */
  apiKey: string;
}

ConvertResult

interface ConvertResult {
  /** The converted file data */
  data: Uint8Array;
  /** Output format */
  format: "glb" | "gltf";
  /** Suggested filename */
  filename: string;
  /** Cleaning statistics (if cleaning was enabled) */
  cleanStats?: CleanStats;
}

CleanStats

interface CleanStats {
  /** Number of splats before cleaning */
  original_count: number;
  /** Number of splats removed due to low opacity */
  removed_low_opacity: number;
  /** Number of splats removed due to small scale */
  removed_small_scale: number;
  /** Number of splats removed as outliers */
  removed_outliers: number;
  /** Number of splats after cleaning */
  final_count: number;
}

ApiError

interface ApiError {
  error: string;       // Error code
  message?: string;    // Human-readable message
}

Usage Examples

Basic Conversion

import { Stereos } from '@stereos/sdk';

const stereos = new Stereos({ apiKey: 'sk_live_...' });
const result = await stereos.convert(plyFile);
Stereos.download(result);

With File Input

const fileInput = document.getElementById('file');
fileInput.addEventListener('change', async (e) => {
  const file = e.target.files[0];
  const result = await stereos.convert(file, { format: 'glb' });
  Stereos.download(result);
});

Maximum Compression

Best for web delivery — smallest file size:

const result = await stereos.convert(file, {
  format: 'glb',
  quantizeColors: true,      // u8 colors (default)
  quantizePositions: true,   // i16 positions (~2x smaller)
  clean: true,               // Remove low-quality splats
  exportFullSh: false,       // DC colors only
  meshoptCompression: true,  // Additional 2-4x compression
});

Full Quality Export

For view-dependent rendering with full spherical harmonics:

const result = await stereos.convert(file, {
  format: 'glb',
  quantizeColors: false,     // Keep f32 precision
  exportFullSh: true,        // All 48 SH coefficients
  clean: {
    minOpacity: 0.001,       // Keep more splats
    minScale: 0.00005,
  },
});

Cleaning with Custom Options

const result = await stereos.convert(file, {
  clean: {
    minOpacity: 0.01,        // Aggressive opacity filtering
    minScale: 0.001,         // Remove tiny splats
    outlierSigma: 3,         // Remove statistical outliers
  },
});

if (result.cleanStats) {
  const { original_count, final_count, removed_outliers } = result.cleanStats;
  console.log(`Cleaned: ${original_count} → ${final_count} splats`);
  console.log(`Removed ${removed_outliers} outliers`);
}

Check Token Status

const claims = await stereos.validateToken();
console.log(`Conversions remaining: ${claims.conversions_remaining}`);
console.log(`Max file size: ${claims.max_file_size} bytes`);

Error Handling

try {
  const result = await stereos.convert(file);
} catch (error) {
  if (error.message.includes('401')) {
    console.error('Invalid API key');
  } else if (error.message.includes('quota')) {
    console.error('Out of conversions');
  } else {
    console.error('Conversion failed:', error.message);
  }
}

Testing

All tests are currently passing

Run tests with: cargo test -p stereos-core

Test Files

crates/stereos-core/src/lib.rs

Core library tests:

  • test_gaussian_cloud_capacity — Validates GaussianCloud capacity calculations
  • test_export_config_default — Tests default ExportConfig values

crates/stereos-core/src/token.rs

JWT token validation tests:

  • test_claims_allows_format — Tests format permission checking in claims
  • test_validate_invalid_key — Tests invalid API key rejection (native only)

crates/stereos-core/src/ply.rs

PLY file parsing tests:

  • test_sigmoid — Tests sigmoid activation function
  • test_parse_vertex_count — Tests vertex count extraction from PLY header
  • test_parse_vertex_count_missing — Tests handling of missing element vertex

crates/stereos-core/src/clean.rs

Cleaning/filtering algorithm tests:

  • test_clean_removes_low_opacity_splats — Opacity threshold filtering
  • test_clean_keeps_splats_at_opacity_threshold — Boundary condition handling
  • test_clean_removes_small_scale_splats — Scale-based filtering
  • test_clean_keeps_splat_if_any_scale_dimension_large_enough — Multi-dimensional scale check
  • test_clean_removes_outliers_by_sigma — Statistical outlier removal
  • test_clean_no_outlier_removal_when_sigma_none — Optional outlier skipping
  • test_clean_applies_all_filters — Combined filter application
  • test_clean_stats_count_each_removal_reason_once — Statistics accuracy
  • test_clean_empty_cloud — Empty input handling
  • test_clean_preserves_all_attributes — Data preservation verification
  • test_clean_with_default_options — Default options behavior

crates/stereos-core/src/gltf.rs

glTF/glb export tests:

  • test_sh_to_rgba — Spherical harmonics to RGBA conversion
  • test_sh_to_rgba_with_values — SH conversion with specific values
  • test_export_glb_structure — GLB binary structure validation
  • test_export_glb_with_stats_structure — GLB with embedded stats
  • test_export_gltf_embedded — Embedded glTF JSON export
  • test_compute_bounds — Bounding box calculations
  • test_compute_bounds_empty — Empty cloud bounds handling
  • test_compute_bounds_single_point — Single point bounds
  • test_export_with_full_sh — Full spherical harmonics export (48 coefficients)
  • test_export_dc_only_no_sh_attribute — Diffuse color only export
  • test_export_with_position_quantization — Position quantization to i16
  • test_export_without_position_quantization — Full precision positions
  • test_full_sh_buffer_size_larger — Buffer size verification for SH data
  • test_quantized_positions_smaller — Quantization size reduction
  • test_quantized_positions_bounds_accuracy — Quantization precision
  • test_export_with_meshopt_compression — Meshopt compression (with feature flag)
  • test_meshopt_compression_reduces_size — Compression ratio verification
  • test_meshopt_buffers_have_correct_layout — Buffer layout validation
  • test_meshopt_compression_stats — Compression statistics
  • test_export_without_meshopt_no_extension — Without compression flag
  • test_color_quantization — Color quantization to u8
  • test_empty_cloud — Empty cloud export handling
  • test_large_cloud — Large dataset performance
  • test_compression_stats_structure — Stats metadata structure

Test Coverage Summary

| Module | Test Count | Coverage | |-----------|--------|----------| | lib.rs | 2 | Core data structures | | token.rs | 2 | JWT validation | | ply.rs | 3 | PLY parsing | | clean.rs | 11 | Cleaning algorithms | | gltf.rs | 24 | glTF/glb export | | Total | 42 | Comprehensive |

Browser Support

| Browser | Version | Notes | |---------|---------|-------| | Chrome | 80+ | Full support | | Firefox | 75+ | Full support | | Safari | 14+ | Full support | | Edge | 80+ | Full support |

Requirements:

  • WebAssembly (Wasm) support
  • ES2020+ (BigInt, dynamic imports)

Project Structure

packages/sdk/
├── src/
│   ├── client.ts       # Main Stereos class
│   ├── types.ts        # TypeScript interfaces
│   └── index.ts        # Public exports
├── wasm/               # WebAssembly files (generated)
│   ├── stereos_wasm.js
│   ├── stereos_wasm_bg.wasm
│   └── *.d.ts
├── dist/               # Compiled output (generated)
├── package.json
├── tsconfig.json
└── README.md

Support

  • Documentation: In Development
  • Issues: https://github.com/StereosOrg/stereos/issues
  • Email: [email protected]