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

@otaga/three-effects

v1.0.1

Published

Three.js 3D effects and model components for web and plain HTML

Downloads

204

Readme

@otaga/three-effects

Three.js-powered 3D visual effects for the web. Each effect ships as a vanilla JavaScript class (works in plain HTML or any framework) and as an optional React component wrapper.

Installation

npm install @otaga/three-effects three

Optional — React wrappers (peer dependency):

npm install react react-dom

Effects

| Effect | Vanilla Class | React Component | | :--- | :--- | :--- | | Floating card with mouse-tracking tilt | FloatingCard | FloatingCardReact | | Card with radial glow and pulse animation | GlowCard | GlowCardReact | | Animated particle system background | ParticleBackground | ParticleBackgroundReact | | Interactive ripple on click/touch | RippleEffect | RippleEffectReact | | Text morphing between strings | MorphText | MorphTextReact |


Vanilla Usage (plain HTML / any framework)

Each class attaches a Three.js canvas to a container element and manages its own animation loop. Call destroy() to clean up when done.

FloatingCard

A 3D card that bobs up and down and tilts to follow the mouse.

import { FloatingCard } from '@otaga/three-effects';

const card = new FloatingCard(document.getElementById('card-container')!, {
  color: 0x6366f1,       // card color (hex number)
  image: '/card.png',    // optional texture — overrides color
  floatSpeed: 1.2,       // vertical oscillation speed
  floatAmplitude: 0.18,  // oscillation height
  tiltStrength: 0.35,    // mouse-tracking tilt intensity
  width: 2.8,
  height: 4,
  depth: 0.06,
});

// Cleanup
card.destroy();

| Option | Type | Default | Description | | :--- | :--- | :--- | :--- | | color | number | 0x6366f1 | Card color (hex) | | emissiveColor | number | 0x1a1040 | Emissive/glow color | | image | string | '' | URL for texture map | | floatSpeed | number | 1.2 | Oscillation frequency | | floatAmplitude | number | 0.18 | Oscillation height | | tiltStrength | number | 0.35 | Mouse tilt multiplier | | width | number | 2.8 | Card width (Three.js units) | | height | number | 4 | Card height | | depth | number | 0.06 | Card thickness |


GlowCard

A card with a radial sprite glow behind it that pulses over time.

import { GlowCard } from '@otaga/three-effects';

const glow = new GlowCard(document.getElementById('glow-container')!, {
  color: 0x0f0f1a,
  glowColor: 0x6366f1,
  glowIntensity: 1.2,
  pulseSpeed: 1.5,
});

glow.destroy();

| Option | Type | Default | Description | | :--- | :--- | :--- | :--- | | color | number | 0x0f0f1a | Card surface color | | glowColor | number | 0x6366f1 | Glow / emissive color | | glowIntensity | number | 1.2 | Glow brightness multiplier | | image | string | '' | Optional texture URL | | floatSpeed | number | 1 | Float oscillation speed | | tiltStrength | number | 0.3 | Mouse tilt multiplier | | pulseSpeed | number | 1.5 | Glow pulse frequency |


ParticleBackground

An animated field of drifting particles with optional connecting lines.

import { ParticleBackground } from '@otaga/three-effects';

const particles = new ParticleBackground(document.getElementById('bg')!, {
  count: 150,
  color: 0x6366f1,
  connected: true,
  connectionDistance: 2.5,
  connectionOpacity: 0.15,
  speed: 0.08,
  spread: 10,
});

particles.destroy();

| Option | Type | Default | Description | | :--- | :--- | :--- | :--- | | count | number | 150 | Number of particles | | color | number | 0x6366f1 | Particle and line color | | size | number | 0.04 | Particle render size | | speed | number | 0.08 | Drift speed multiplier | | spread | number | 10 | Spawn area (Three.js units) | | connected | boolean | true | Draw lines between nearby particles | | connectionDistance | number | 2.5 | Max distance for a connection line | | connectionOpacity | number | 0.15 | Line opacity | | backgroundColor | number \| null | null | Scene background (null = transparent) |


RippleEffect

Click or tap the container to spawn expanding ring ripples.

import { RippleEffect } from '@otaga/three-effects';

const ripple = new RippleEffect(document.getElementById('ripple-container')!, {
  color: 0x6366f1,
  maxRipples: 8,
  duration: 1.2,
  maxRadius: 3,
  thickness: 0.04,
});

ripple.destroy();

| Option | Type | Default | Description | | :--- | :--- | :--- | :--- | | color | number | 0x6366f1 | Ripple ring color | | maxRipples | number | 8 | Max concurrent ripples | | duration | number | 1.2 | Ripple lifetime in seconds | | maxRadius | number | 3 | Max ring radius | | thickness | number | 0.04 | Ring line thickness | | backgroundColor | number \| null | null | Scene background (null = transparent) |


MorphText

Cycles through an array of strings, morphing particles between each one.

import { MorphText } from '@otaga/three-effects';

const morph = new MorphText(document.getElementById('text-container')!, {
  texts: ['Hello', 'World', 'Otaga'],
  fontSize: 80,
  color: 0x6366f1,
  particleSize: 0.04,
  particleCount: 3000,
  interval: 2500,      // ms between morphs
  morphDuration: 1.2,  // morph animation length in seconds
});

morph.destroy();

| Option | Type | Default | Description | | :--- | :--- | :--- | :--- | | texts | string[] | required | Strings to cycle through | | fontSize | number | 80 | Canvas font size for sampling | | color | number | 0x6366f1 | Particle color | | particleSize | number | 0.04 | Particle render size | | particleCount | number | 3000 | Number of particles | | interval | number | 2500 | Time between text changes (ms) | | morphDuration | number | 1.2 | Morph animation duration (s) |


React Usage

React wrappers accept the same options as props and handle mounting/unmounting automatically.

import { FloatingCardReact, ParticleBackgroundReact } from '@otaga/three-effects';

// FloatingCard as a React component
<FloatingCardReact
  color={0x6366f1}
  floatSpeed={1.2}
  tiltStrength={0.35}
  style={{ width: '100%', height: 400 }}
/>

// Particle background filling its container
<div style={{ position: 'relative', height: 500 }}>
  <ParticleBackgroundReact
    count={120}
    color={0x818cf8}
    connected
    style={{ position: 'absolute', inset: 0 }}
  />
</div>

All React components forward a style prop to the container <div> and clean up the Three.js renderer on unmount.

License

MIT