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

@danielblagy/three-mmi

v1.0.0

Published

A utility class that lets you easily set up mouse event handlers for threejs meshes.

Readme

MouseMeshInteraction

is a utility class that lets you easily set up mouse event handlers for threejs meshes (THREE.Mesh objects).

Making Xylophone Simulation (Youtube video)

Making the example (Youtube video)

File System Visualizer that uses three_mmi (Github repository)

Download:

To download the script, go to three_mmi.js, open in raw view, right click -> Save as... (or Ctrl + S)

The "module" version of the script is at module/three_mmi.js

Include:

You can include three_mmi as a simple js script in index.html:

/* index.html */
// inside of html body
<script src="js/three.js"></script>
// comes after including three.js
<script src="js/three_mmi.js"></script>

npm install

If you want to use three mmi in a nodejs project, you can install the module with npm.

npm i @danielblagy/three-mmi

or you can include it as a module, for example:

/* script.js */
import * as THREE from 'three'
import MouseMeshInteraction from './three_mmi'

Usage:

Initialize MouseMeshInteraction object (doesn't have to come before creating mesh objects)

// pass threejs scene and camera
const mmi = new MouseMeshInteraction(scene, camera);

Create an interactable mesh

// create an interactable mesh
const mesh = new THREE.Mesh(geometry, material);
// specify a name for the mesh (needed for mmi to work, you can give the same name to multiple meshes)
mesh.name = 'my_interactable_mesh';
scene.add(mesh);

Add a handler of a mouse event for a mesh with a specified name Supported mouse events:

  • 'click' (left mouse button click)
  • 'dblclick' (left mouse button double click)
  • 'contextmenu' (right mouse button click, triggered before opening the context menu)
  • 'mouseenter' (mouse cursor is moved onto the element that has the listener attached)
  • 'mouseleave' (mouse cursor is moved off the element that has the listener attached)
  • 'mousedown' (mouse button is pressed on an element)
  • 'mouseup' (mouse button is released over an element)
// create a handler for when user clicks on a mesh with the name 'my_interactable_mesh'
mmi.addHandler('my_interactable_mesh', 'click', function(mesh) {
	console.log('interactable mesh has been clicked!');
	console.log(mesh);
});

Inside of render & update loop, call update function

// put mmi.update() inside the graphics update function
function animate() {
	requestAnimationFrame( animate );
	
	mmi.update();
	
	renderer.render( scene, camera );
}
animate();

That's it!

Quickstart Template (as a js script):

For a project with the following structure:

  • index.html
  • js/three.js
  • js/three_mmi.js
/* index.html */
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>three_mmi Quickstart Template</title>
	</head>
	<body>
		<script src="js/three.js"></script>
		<script src="js/three_mmi.js"></script>
		<script>
			const scene = new THREE.Scene();
			
			const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
			camera.position.set(0, 0, 50);
					
			const renderer = new THREE.WebGLRenderer({antialias : true});
			renderer.setSize(window.innerWidth, window.innerHeight);
			renderer.setClearColor(0xe0b2a4, 1.0);
			document.body.appendChild(renderer.domElement);
			
			// create an interactable light buld mesh
			
			const gray_color = new THREE.Color(0x57554f);
			const yellow_color = new THREE.Color(0xe0c53a);
			
			const bulb_geometry = new THREE.BoxGeometry(5, 5, 5);
			
			const bulb_material = new THREE.MeshBasicMaterial( { color: yellow_color } );
			
			var bulb_mesh = new THREE.Mesh(bulb_geometry, bulb_material);
			// add a name to the mesh (needed for mmi to work, you can give the same name to multiple meshes)
			bulb_mesh.name = 'bulb';
			bulb_mesh.position.set(0, 0, 0);
			scene.add(bulb_mesh);
			
			// initialize instance of class MouseMeshInteraction, passing threejs scene and camera
			const mmi = new MouseMeshInteraction(scene, camera);
			
			// add a handler on mouse click for mesh (or meshes) with the name 'bulb'
			mmi.addHandler('bulb', 'click', function(mesh) {
				console.log('bulb mesh is being clicked!');
				// switch between colors
				if (mesh.material.color === gray_color) {
					mesh.material.color = yellow_color;
				}
				else {
					mesh.material.color = gray_color;
				}
			});
			
			function render() {
				requestAnimationFrame(render);
				// update the mmi
				mmi.update();
				renderer.render(scene, camera);
			}
			
			render();
		</script>
	</body>
</html>

Quickstart Template (as a js module):

/* script.js */

import * as THREE from 'three'
import MouseMeshInteraction from 'three_mmi'

const scene = new THREE.Scene();
			
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 0, 50);
		
const renderer = new THREE.WebGLRenderer({antialias : true});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0xe0b2a4, 1.0);
document.body.appendChild(renderer.domElement);

// create an interactable light buld mesh

const gray_color = new THREE.Color(0x57554f);
const yellow_color = new THREE.Color(0xe0c53a);

const bulb_geometry = new THREE.BoxGeometry(5, 5, 5);

const bulb_material = new THREE.MeshBasicMaterial( { color: yellow_color } );

var bulb_mesh = new THREE.Mesh(bulb_geometry, bulb_material);
// add a name to the mesh (needed for mmi to work, you can give the same name to multiple meshes)
bulb_mesh.name = 'bulb';
bulb_mesh.position.set(0, 0, 0);
scene.add(bulb_mesh);

// initialize instance of class MouseMeshInteraction, passing threejs scene and camera
const mmi = new MouseMeshInteraction(scene, camera);

// add a handler on mouse click for mesh (or meshes) with the name 'bulb'
mmi.addHandler('bulb', 'click', function(mesh) {
	console.log('bulb mesh is being clicked!');
	// switch between colors
	if (mesh.material.color === gray_color) {
		mesh.material.color = yellow_color;
	}
	else {
		mesh.material.color = gray_color;
	}
});

// just to test if the new features are conflicting with previously supported events
//		(everything seems to be OK)
mmi.addHandler('bulb', 'dblclick', function(mesh) {
	console.log('bulb mesh is double clicked!');
});
mmi.addHandler('bulb', 'contextmenu', function(mesh) {
	console.log('bulb mesh is pressed with the right button!');
});

const green_color = new THREE.Color(0x00bb00);
const orange_color = new THREE.Color(0xffaa00);
const red_color = new THREE.Color(0xff0a0a);
const test_mesh_geometry = new THREE.BoxGeometry( 5, 5, 5 ); 
const test_mesh_material = new THREE.MeshBasicMaterial( { color: green_color } );
var test_mesh = new THREE.Mesh(test_mesh_geometry, test_mesh_material);
test_mesh.name = 'new_features_mesh';
test_mesh.position.set(10, 0, 10);
scene.add(test_mesh);
		
mmi.addHandler('new_features_mesh', 'mouseenter', function(mesh) {
	console.log('mouse is over the mesh!  ', mesh);
	mesh.material.color = orange_color;
});

mmi.addHandler('new_features_mesh', 'mouseleave', function(mesh) {
	console.log('mouse has left!  ', mesh);
	mesh.material.color = green_color;
});

mmi.addHandler('new_features_mesh', 'mousedown', function(mesh) {
	console.log('mouse button is pressing on the mesh!  ', mesh);
	mesh.material.color = red_color;
});

mmi.addHandler('new_features_mesh', 'mouseup', function(mesh) {
	console.log('mouse button is released on the mesh!  ', mesh);
	mesh.material.color = orange_color;
});

mmi.addHandler('new_features_mesh', 'click', function(mesh) {
	console.log('mouse button is clicked on the mesh!  ', mesh);
});

function render() {
	requestAnimationFrame(render);
	// update the mmi
	mmi.update();
	renderer.render(scene, camera);
}

render();