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 🙏

© 2025 – Pkg Stats / Ryan Hefner

physics-glass-effects

v1.0.0

Published

Physics-based glass effects using WebGL with real optical science - works with React, Vue, Next.js, and vanilla JS

Readme

Physics Glass Effects

npm version TypeScript WebGL

A sophisticated WebGL library that creates realistic glass effects using genuine optical physics principles. Unlike typical "glassmorphism" effects, this library implements real physics including Snell's Law, Fresnel reflection, chromatic dispersion, and 3D ray tracing.

🔬 Real Physics • 🎨 Multiple Shapes • ⚡ High Performance • 🎯 Framework Agnostic

✨ Features

🔬 Advanced Optical Physics

  • 3D Ray Tracing: Accurate ray-object intersection for different glass geometries
  • Snell's Law: Proper 3D refraction calculations through glass volumes
  • Fresnel Equations: Realistic reflection/transmission ratios based on viewing angle
  • Chromatic Dispersion: Different wavelengths (RGB) refract at different angles
  • Geometric Distortion: Dramatic background distortion based on actual glass shape

🎨 Multiple Glass Shapes

  • Sphere: Strong barrel distortion with curvature-dependent effects
  • Cylinder: One-directional distortion creating unique stretching patterns
  • Convex Lens: Magnification at center with edge distortion effects
  • Triangular Prism: Directional refraction with enhanced chromatic separation
  • Flat Glass: Minimal geometric distortion with pure optical effects

🌈 Background Patterns

  • Black & White Stripes: Perfect for demonstrating geometric distortion
  • Grid Pattern: Shows both horizontal and vertical distortion clearly
  • Concentric Circles: Demonstrates radial distortion effects
  • Custom Textures: Use your own images for realistic environmental refraction

🚀 Framework Support

  • React - Full component support with hooks
  • Vue - Complete composition API integration
  • Next.js - SSR-safe with dynamic loading
  • Vanilla JS - Zero dependencies, works anywhere
  • TypeScript - Full type definitions included

📦 Installation

npm install physics-glass-effects

🚀 Quick Start

Vanilla JavaScript

import { PhysicsGlass } from 'physics-glass-effects';

const canvas = document.getElementById('canvas');
const glass = new PhysicsGlass(canvas, {
  shape: 'sphere',
  backgroundPattern: 'stripes',
  refractionIndex: 1.5,
  dispersion: 0.03
});

React

import React, { useRef, useEffect } from 'react';
import { PhysicsGlass } from 'physics-glass-effects';

const GlassEffect = () => {
  const canvasRef = useRef<HTMLCanvasElement>(null);

  useEffect(() => {
    if (canvasRef.current) {
      const glass = new PhysicsGlass(canvasRef.current, {
        shape: 'sphere',
        backgroundPattern: 'stripes',
        mouse: { enabled: true, followCursor: true },
        onReady: () => console.log('Glass effect ready!')
      });

      return () => glass.destroy();
    }
  }, []);

  return <canvas ref={canvasRef} width={800} height={600} />;
};

Vue 3

<template>
  <canvas ref="canvasRef" :width="800" :height="600" />
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import { PhysicsGlass } from 'physics-glass-effects';

const canvasRef = ref(null);
let glass = null;

onMounted(() => {
  if (canvasRef.value) {
    glass = new PhysicsGlass(canvasRef.value, {
      shape: 'sphere',
      backgroundPattern: 'stripes'
    });
  }
});

onUnmounted(() => {
  if (glass) glass.destroy();
});
</script>

Next.js (SSR Safe)

import dynamic from 'next/dynamic';

const GlassEffect = dynamic(
  () => import('./GlassEffectClient'),
  { ssr: false }
);

export default function Page() {
  return <GlassEffect width={800} height={600} />;
}

🎛️ Configuration Options

interface PhysicsGlassConfig {
  // Glass properties
  shape?: 'sphere' | 'cylinder' | 'lens' | 'prism' | 'flat';
  size?: number; // 0.1 to 0.4
  refractionIndex?: number; // 1.0 to 2.5
  dispersion?: number; // 0.0 to 0.1
  thickness?: number; // 0.1 to 1.0
  
  // Background
  backgroundPattern?: 'stripes' | 'grid' | 'circles' | 'texture';
  backgroundTexture?: HTMLImageElement | HTMLCanvasElement | string;
  
  // Interaction
  mouse?: {
    enabled: boolean;
    followCursor: boolean;
    centerX?: number;
    centerY?: number;
  };
  
  // Animation
  animation?: {
    enabled: boolean;
    speed: number; // 0.0 to 5.0
    surfaceRipples: boolean;
  };
  
  // Callbacks
  onReady?: () => void;
  onError?: (error: Error) => void;
  onShapeChange?: (shape: GlassShape) => void;
}

🛠️ API Reference

Main Class

PhysicsGlass

class PhysicsGlass {
  constructor(canvas: HTMLCanvasElement | string, config?: PhysicsGlassConfig);
  
  // Shape and appearance
  setShape(shape: GlassShape): void;
  setSize(size: number): void;
  setBackgroundPattern(pattern: BackgroundPattern): void;
  setBackgroundTexture(texture: HTMLImageElement | HTMLCanvasElement | string): Promise<void>;
  
  // Optical properties
  setRefractionIndex(index: number): void;
  setDispersion(dispersion: number): void;
  setThickness(thickness: number): void;
  
  // Material presets
  setMaterial(material: GlassMaterial | string): void;
  getMaterials(): GlassMaterial[];
  
  // Interaction
  setMousePosition(x: number, y: number): void;
  enableMouseTracking(enabled: boolean): void;
  
  // Animation
  startAnimation(): void;
  stopAnimation(): void;
  setAnimationSpeed(speed: number): void;
  
  // Lifecycle
  destroy(): void;
  resize(): void;
  
  // Utility
  getConfig(): PhysicsGlassConfig;
  getCanvas(): HTMLCanvasElement;
  isWebGLSupported(): boolean;
}

Material Presets

const materials = {
  water: { refractionIndex: 1.33, dispersion: 0.01 },
  crownGlass: { refractionIndex: 1.52, dispersion: 0.02 },
  flintGlass: { refractionIndex: 1.65, dispersion: 0.05 },
  diamond: { refractionIndex: 2.42, dispersion: 0.08 }
};

// Usage
glass.setMaterial('diamond');
// or
glass.setMaterial(materials.diamond);

Utility Functions

import { isWebGLSupported, GLASS_MATERIALS } from 'physics-glass-effects';

if (!isWebGLSupported()) {
  console.log('WebGL not supported');
}

console.log(GLASS_MATERIALS.diamond); // { name: 'Diamond', refractionIndex: 2.42, ... }

🎯 Usage Examples

Dynamic Shape Switching

const glass = new PhysicsGlass(canvas);

// Switch between different glass shapes
glass.setShape('sphere');    // Strong barrel distortion
glass.setShape('cylinder');  // Unidirectional stretching
glass.setShape('lens');      // Magnification effects
glass.setShape('prism');     // Rainbow dispersion

Material Demonstrations

// Cycle through different materials
const materials = ['water', 'crownGlass', 'flintGlass', 'diamond'];
let currentMaterial = 0;

setInterval(() => {
  glass.setMaterial(materials[currentMaterial]);
  currentMaterial = (currentMaterial + 1) % materials.length;
}, 2000);

Custom Background Textures

// Using an image URL
glass.setBackgroundTexture('https://example.com/texture.jpg');

// Using an Image element
const img = new Image();
img.onload = () => glass.setBackgroundTexture(img);
img.src = 'texture.jpg';

// Using a canvas
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// ... draw on canvas ...
glass.setBackgroundTexture(canvas);

Interactive Controls

// Mouse position control
glass.enableMouseTracking(false);
glass.setMousePosition(0.3, 0.7); // 30% from left, 70% from top

// Animation control
glass.setAnimationSpeed(2.0); // 2x speed
glass.stopAnimation();
glass.startAnimation();

🔬 Physics Deep Dive

Real Optical Equations

The library implements authentic physics equations:

Snell's Law: n₁ sin θ₁ = n₂ sin θ₂

vec3 refract3D(vec3 incident, vec3 normal, float eta) {
    float cosI = dot(-incident, normal);
    float sinT2 = eta * eta * (1.0 - cosI * cosI);
    if(sinT2 >= 1.0) return reflect(incident, normal); // Total internal reflection
    float cosT = sqrt(1.0 - sinT2);
    return eta * incident + (eta * cosI - cosT) * normal;
}

Fresnel Equations: R = R₀ + (1 - R₀)(1 - cos θ)⁵

float fresnel(float cosTheta, float n1, float n2) {
    float r0 = pow((n1 - n2) / (n1 + n2), 2.0);
    return r0 + (1.0 - r0) * pow(1.0 - cosTheta, 5.0);
}

Shape-Specific Distortions

Each glass shape creates unique distortion patterns:

  • Sphere: Barrel distortion increases quadratically from center
  • Cylinder: Uniform stretching in one direction only
  • Lens: Radial magnification with focal point effects
  • Prism: Angular refraction creating rainbow separation

⚡ Performance

  • Hardware Accelerated: Uses WebGL for 60fps rendering
  • Optimized Shaders: Single-pass fragment shader rendering
  • Memory Efficient: Automatic resource cleanup
  • Responsive: Real-time parameter updates

Browser Support

  • ✅ Chrome/Chromium (recommended)
  • ✅ Firefox
  • ✅ Safari (with WebGL enabled)
  • ✅ Edge
  • ❌ Internet Explorer

🐛 Troubleshooting

Common Issues

WebGL not supported:

import { isWebGLSupported } from 'physics-glass-effects';

if (!isWebGLSupported()) {
  // Show fallback UI
  console.warn('WebGL not supported, showing fallback');
}

Canvas sizing issues:

// Ensure proper canvas sizing
const glass = new PhysicsGlass(canvas, {
  performance: {
    pixelRatio: window.devicePixelRatio || 1
  }
});

// Handle resize
window.addEventListener('resize', () => glass.resize());

Memory leaks:

// Always cleanup when component unmounts
useEffect(() => {
  const glass = new PhysicsGlass(canvas);
  return () => glass.destroy(); // Critical!
}, []);

🤝 Contributing

We welcome contributions! See our Contributing Guide for details.

📄 License

MIT License - see LICENSE file for details.

🔗 Links


Made with ❤️ by developers who believe in the beauty of real physics