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

copper3d

v3.1.1

Published

A 3d visualisation package base on threejs provides multiple scenes and Nrrd image load funtion.

Readme

copper3d

NPM Package Read the Docs Copper3d Examples NRRD_Segmentation_Tool example MedTech Heart example

A 3D visualisation package based on three.js — multiple scenes, NRRD/DICOM image loading, and a full medical image segmentation annotation engine.

Documentation

https://copper3d-visualisation.readthedocs.io/en/latest/

Previous versions

Old: https://www.npmjs.com/package/copper3d_visualisation Very old: https://www.npmjs.com/package/gltfloader-plugin-test

Examples

Pick model with Gltfloader Copper3d_examples


Basic Usage

Load demo

import * as Copper from "copper3d";
import { getCurrentInstance, onMounted } from "vue";

let appRenderer;
onMounted(() => {
  const { $refs } = (getCurrentInstance() as any).proxy;
  const bg: HTMLDivElement = $refs.classfy;
  appRenderer = new Copper.copperRenderer(bg);
  appRenderer.getCurrentScene().createDemoMesh();
  appRenderer.animate();
});

Options

appRenderer = new Copper.copperRenderer(bg, { guiOpen: true });

Multiple scenes with glTF

function loadModel(url: string, name: string) {
  let scene = appRenderer.getSceneByName(name);
  if (!scene) {
    scene = appRenderer.createScene(name);
    appRenderer.setCurrentScene(scene);
    scene.loadViewUrl("/noInfarct_view.json");
    scene.loadGltf(url);
  } else {
    appRenderer.setCurrentScene(scene);
  }
}

View data structure

CameraViewPoint {
  nearPlane: number = 0.1;
  farPlane: number = 2000.0;
  eyePosition: Array<number> = [0.0, 0.0, 0.0];
  targetPosition: Array<number> = [0.0, 0.0, 0.0];
  upVector: Array<number> = [0.0, 1.0, 0.0];
}

NrrdTools Usage Guide

Copper3D NrrdTools — Medical Image Segmentation Annotation Engine

NrrdTools manages multi-layer mask volumes, a layered canvas pipeline, drawing tools, undo/redo history, channel color customization, and keyboard shortcuts on top of a Three.js medical image viewer.

Internal Architecture: NrrdTools is a Facade using composition (no inheritance). It composes:

  • CanvasState — unified state container (nrrd_states, gui_states, protectedData, callbacks, keyboardSettings)
  • DrawToolCore — tool orchestration and event routing
  • RenderingUtils — slice extraction and canvas compositing helpers
  • LayerChannelManager — layer/channel/sphere-type management and color customization
  • SliceRenderPipeline — slice setup, canvas rendering, mask reload, canvas flip
  • DataLoader — NRRD slice loading, NIfTI voxel loading

The old inheritance chain (NrrdTools → DrawToolCore → CommToolsData) has been fully replaced. All modules communicate via ToolContext (shared state). The public API below is unchanged.


1. Quick Start

import * as Copper from 'copper3d';

const container = document.getElementById('viewer') as HTMLDivElement;
const nrrdTools = new Copper.NrrdTools(container);

nrrdTools.reset();
nrrdTools.setAllSlices(allSlices); // allSlices from Copper scene loader

nrrdTools.drag({ getSliceNum: (index) => console.log('Slice:', index) });

nrrdTools.draw({
  getMaskData: (sliceData, layerId, channelId, sliceIndex, axis, width, height, clearFlag) => {
    // Called after every stroke, undo, redo — sync to backend here
  }
});

scene.addPreRenderCallbackFunction(nrrdTools.start);

2. Constructor & Initialization

new Copper.NrrdTools(container: HTMLDivElement, options?: { layers?: string[] })

| Parameter | Type | Default | Description | |-----------|------|---------|-------------| | container | HTMLDivElement | required | Host DOM element for all annotation canvases | | options.layers | string[] | ["layer1","layer2","layer3"] | Named layers to create |

// Custom layer set
const nrrdTools = new Copper.NrrdTools(container, {
  layers: ['layer1', 'layer2', 'layer3', 'layer4']
});

// Optional: show current slice index in a panel
nrrdTools.setDisplaySliceIndexPanel(document.getElementById('slice-panel') as HTMLDivElement);

// Optional: connect dat.GUI / lil-gui
import GUI from 'lil-gui';
nrrdTools.setupGUI(new GUI() as any);

3. Data Loading

// Reset state then load new slices
nrrdTools.reset();
nrrdTools.setAllSlices(allSlices);

// Load existing NIfTI mask data
const layerVoxels = new Map<string, Uint8Array>([
  ['layer1', layer1Uint8Array],
  ['layer2', layer2Uint8Array],
]);
nrrdTools.setMasksFromNIfTI(layerVoxels);

// With loading progress bar
const loadingBar = { value: 0 };
nrrdTools.setMasksFromNIfTI(layerVoxels, loadingBar);

4. Render Loop Integration

// Register once after initialization
const callbackId = scene.addPreRenderCallbackFunction(nrrdTools.start);

// Unregister on teardown
scene.removePreRenderCallbackFunction(callbackId);

5. Drawing Setup

drag() — Slice navigation

nrrdTools.drag({
  showNumber: true,
  getSliceNum: (sliceIndex, contrastIndex) => updateUI(sliceIndex),
});

draw() — Annotation callbacks

nrrdTools.draw({
  getMaskData: (sliceData, layerId, channelId, sliceIndex, axis, width, height, clearFlag?) => {
    sendSliceToBackend({ sliceData, layerId, channelId, sliceIndex, axis, width, height, clearFlag });
  },
  onClearLayerVolume: (layerId) => notifyBackendLayerCleared(layerId),
  getSphereData: (sphereOrigin, sphereRadius) => sendSphereToBackend({ sphereOrigin, sphereRadius }),
  getCalculateSpherePositionsData: (tumour, skin, rib, nipple, axis) => {
    if (tumour && skin && rib && nipple) aiBackend.runSegmentation({ tumour, skin, rib, nipple, axis });
  },
});

enableContrastDragEvents() — Window/Level

nrrdTools.enableContrastDragEvents((step, towards) => {
  console.log(`Contrast: ${towards} ${step}`);
});

SphereTool — Sphere Types & Channel Mapping

| Sphere Type | Channel | Default Color | activeSphereType value | |-------------|---------|---------------|--------------------------| | tumour | 1 | #10b981 | "tumour" (default) | | nipple | 2 | #f43f5e | "nipple" | | ribcage | 3 | #3b82f6 | "ribcage" | | skin | 4 | #fbbf24 | "skin" |

nrrdTools.setActiveSphereType('nipple');  // also updates brush/fill color
const type = nrrdTools.getActiveSphereType(); // → 'tumour' | 'skin' | 'nipple' | 'ribcage'

Programmatic sphere placement (backend → frontend):

// Replicates full click flow internally — no user interaction needed
nrrdTools.setCalculateDistanceSphere(120, 95, 42, 'tumour');
// Coordinates are in unscaled image space; sizeFactor is applied internally

6. Layer & Channel Management

// Active layer / channel
nrrdTools.setActiveLayer('layer2');
nrrdTools.setActiveChannel(3);
const layer   = nrrdTools.getActiveLayer();
const channel = nrrdTools.getActiveChannel();

// Layer visibility
nrrdTools.setLayerVisible('layer2', false);
const visible = nrrdTools.isLayerVisible('layer2');
const visMap  = nrrdTools.getLayerVisibility(); // { layer1: true, layer2: false, ... }

// Channel visibility (per layer)
nrrdTools.setChannelVisible('layer1', 2, false);
const allChannelVis = nrrdTools.getChannelVisibility();

// Check if a layer has annotations
if (nrrdTools.hasLayerData('layer1')) await saveLayer('layer1');

7. Channel Color Customization

Default colors:

| Channel | Color | Hex | |---------|-------|-----| | 1 | Emerald | #10b981 | | 2 | Rose | #f43f5e | | 3 | Blue | #3b82f6 | | 4 | Amber | #fbbf24 | | 5 | Fuchsia | #d946ef | | 6 | Cyan | #06b6d4 | | 7 | Orange | #f97316 | | 8 | Violet | #8b5cf6 |

// Set one channel color (RGBAColor: { r, g, b, a } — 0-255)
nrrdTools.setChannelColor('layer1', 3, { r: 255, g: 128, b: 0, a: 255 });

// Batch-set (one reloadMasksFromVolume call — better performance)
nrrdTools.setChannelColors('layer1', {
  1: { r: 255, g: 80, b: 80, a: 255 },
  2: { r: 80, g: 180, b: 255, a: 255 },
});

// Apply same channel color across all layers
nrrdTools.setAllLayersChannelColor(1, { r: 0, g: 220, b: 100, a: 255 });

// Read colors
const rgba = nrrdTools.getChannelColor('layer1', 3);
const hex  = nrrdTools.getChannelHexColor('layer1', 3);  // → "#ff8000"
const css  = nrrdTools.getChannelCssColor('layer1', 3);  // → "rgba(255,128,0,1.00)"

// Reset
nrrdTools.resetChannelColors('layer1', 3); // one channel
nrrdTools.resetChannelColors('layer1');    // all channels in layer
nrrdTools.resetChannelColors();            // everything

8. Undo / Redo

Per-layer undo stack (max 50 entries). Every completed stroke pushes a delta snapshot.

nrrdTools.undo();
nrrdTools.redo();

// Or via keyboard
window.addEventListener('keydown', (e) => {
  if (e.ctrlKey && e.key === 'z') nrrdTools.undo();
  if (e.ctrlKey && e.key === 'y') nrrdTools.redo();
});

9. Keyboard Shortcuts

| Action | Default Key | |--------|-------------| | Draw mode | Shift (hold) | | Undo | z | | Redo | y | | Contrast adjust | Ctrl / Meta (hold) | | Crosshair | s | | Sphere mode | q | | Mouse wheel | Zoom |

nrrdTools.setKeyboardSettings({ undo: 'u', mouseWheel: 'Scroll:Slice' });
const settings = nrrdTools.getKeyboardSettings();

// Suppress shortcuts while a form input is focused
inputEl.addEventListener('focus', () => nrrdTools.enterKeyboardConfig());
inputEl.addEventListener('blur',  () => nrrdTools.exitKeyboardConfig());

10. Clearing Annotations

nrrdTools.reset();           // Reset ALL layers, volumes, undo histories, canvases (use when switching cases)
nrrdTools.clearActiveLayer(); // Clear active layer's entire 3D volume + undo history, fire onClearLayerVolume
nrrdTools.clearActiveSlice(); // Clear only the currently viewed 2D slice (undoable)

11. API Summary

| Category | Method | Description | |----------|--------|-------------| | Constructor | new NrrdTools(container, { layers }) | Create instance with optional layer config | | Setup | drag(opts?) | Enable slice-drag navigation | | | draw(opts?) | Bind annotation callbacks | | | setupGUI(gui) | Connect dat.GUI / lil-gui panel | | | enableContrastDragEvents(cb) | Enable Ctrl+drag windowing | | | setDisplaySliceIndexPanel(el) | Show slice index in a panel | | | setBaseDrawDisplayCanvasesSize(n) | Set canvas resolution multiplier (1–8) | | Data | reset() | Reset all volumes, undo histories, canvases, sphere data | | | clearActiveLayer() | Clear active layer volume + undo history | | | clearActiveSlice() | Clear current slice (undoable) | | | setAllSlices(slices) | Load NRRD slices, init MaskVolumes | | | setMasksFromNIfTI(map, bar?) | Load saved NIfTI voxel data | | Render | start | Frame callback — pass to render loop | | Layer | setActiveLayer(id) | Switch drawing target layer | | | getActiveLayer() | Read current layer | | | setLayerVisible(id, bool) | Toggle layer in composite view | | | isLayerVisible(id) | Query layer visibility | | | getLayerVisibility() | All layer visibility map | | | hasLayerData(id) | Check if layer has non-zero voxels | | Sphere | setActiveSphereType(type) | Set active sphere type, updates brush color | | | getActiveSphereType() | Read current sphere type | | | setCalculateDistanceSphere(x, y, slice, type) | Programmatically place a calculator sphere | | Channel | setActiveChannel(ch) | Switch drawing target channel | | | getActiveChannel() | Read current channel | | | setChannelVisible(id, ch, bool) | Toggle channel visibility in a layer | | | isChannelVisible(id, ch) | Query channel visibility | | | getChannelVisibility() | All channel visibility map | | Color | setChannelColor(id, ch, rgba) | Set one channel color in one layer | | | setChannelColors(id, map) | Batch-set colors in one layer | | | setAllLayersChannelColor(ch, rgba) | Set one channel color across all layers | | | getChannelColor(id, ch) | Read RGBA | | | getChannelHexColor(id, ch) | Read Hex string | | | getChannelCssColor(id, ch) | Read CSS rgba() string | | | resetChannelColors(id?, ch?) | Reset to defaults | | Tool Mode | setMode(mode) | Switch tool: "pencil" / "brush" / "eraser" / "sphere" / "calculator" | | | getMode() | Read current tool mode | | Drawing | setOpacity(value) | Set mask overlay opacity [0.1, 1] | | | getOpacity() | Read current opacity | | | setBrushSize(size) | Set brush/eraser size [5, 50] | | | getBrushSize() | Read current brush size | | Contrast | setWindowHigh(value) | Set window high | | | setWindowLow(value) | Set window low | | | finishWindowAdjustment() | Repaint all contrast slices after drag ends | | Actions | executeAction(action) | Run: "undo" / "redo" / "clearActiveSliceMask" / "clearActiveLayerMask" / "resetZoom" / "downloadCurrentMask" | | Navigation | setSliceOrientation(axis) | Switch viewing axis "x" / "y" / "z" | | History | undo() / redo() | Undo / redo last stroke | | Keyboard | setKeyboardSettings(partial) | Remap shortcuts | | | getKeyboardSettings() | Read current bindings | | | enterKeyboardConfig() / exitKeyboardConfig() | Suppress / restore shortcuts | | | setContrastShortcutEnabled(bool) | Enable/disable contrast key | | Inspect | getCurrentImageDimension() | [w, h, d] voxel dims | | | getVoxelSpacing() | Physical mm spacing | | | getSpaceOrigin() | World-space origin | | | getMaxSliceNum() | Max slice index per axis | | | getCurrentSlicesNumAndContrastNum() | Current slice & contrast index | | | getMaskData() | Raw IMaskData object | | | getNrrdToolsSettings() | Full NrrdState snapshot | | | getContainer() | Host HTMLElement | | | getDrawingCanvas() | Top-layer HTMLCanvasElement |


12. Type Reference

interface RGBAColor { r: number; g: number; b: number; a: number; } // 0-255

type ChannelColorMap = Record<number, RGBAColor>; // key = channel 1-8

interface IDrawOpts {
  getMaskData?: (
    sliceData: Uint8Array, layerId: string, channelId: number,
    sliceIndex: number, axis: 'x' | 'y' | 'z',
    width: number, height: number, clearFlag?: boolean
  ) => void;
  onClearLayerVolume?: (layerId: string) => void;
  getSphereData?: (sphereOrigin: number[], sphereRadius: number) => void;
  getCalculateSpherePositionsData?: (
    tumourOrigin: ICommXYZ | null, skinOrigin: ICommXYZ | null,
    ribOrigin: ICommXYZ | null, nippleOrigin: ICommXYZ | null,
    axis: 'x' | 'y' | 'z'
  ) => void;
}

interface IDragOpts {
  showNumber?: boolean;
  getSliceNum?: (sliceIndex: number, contrastIndex: number) => void;
}

interface IKeyBoardSettings {
  draw: string;
  undo: string;
  redo: string;
  contrast: string[];
  crosshair: string;
  sphere: string;
  mouseWheel: 'Scroll:Zoom' | 'Scroll:Slice';
}

interface ICommXYZ { x: number; y: number; z: number; }

type LayerId      = 'layer1' | 'layer2' | 'layer3' | 'layer4'; // or any string
type ChannelValue = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;

Acknowledgements

Special thanks to Duke University dataset for providing the MRI data.