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

@alekstar79/3d-polyhedra

v1.0.0

Published

Interactive 3D polyhedra renderer (TypeScript)

Readme

3D Polyhedra Library

npm version License: MIT TypeScript Vite

Interactive 3D polyhedra renderer with smooth subdivision, real-time lighting, and intuitive controls.

3D-Polyhedrons

Live Demo

Features

  • 5 Platonic Solids – Tetrahedron, Cube, Octahedron, Dodecahedron, Icosahedron
  • Dynamic Subdivision – level 0–4 for smooth surfaces
  • Interactive Controls – mouse drag rotation, touch support
  • Real-time Lighting – dynamic directional light based on pointer position
  • Hole Effect – configurable aperture for wireframe-like style
  • Color Palette – hue shift and random per-face colors
  • Performance – optimized with FPS counter
  • Framework Agnostic – pure TypeScript, no external dependencies (only for development)

Installation

For library usage

npm install @alekstar79/3d-polyhedra

For development / demo

Clone the repository and install dependencies:

git clone https://github.com/alekstar79/3d-polyhedra.git
cd 3d-polyhedra
npm install

Demo

Run the demo locally:

npm run dev

Open http://localhost:3000 to see the interactive 3D scene with control panel.

To build the demo for production:

npm run build:demo

The output will be in the dist folder.


Usage Examples

Below are two primary ways to use the library – the high-level Renderer and low-level components for full control.

Simple renderer setup

The easiest way to get started is to use the Renderer class. It handles all the rendering, animation loop, and interaction.

import { Renderer } from '@alekstar79/3d-polyhedra';

const canvas = document.getElementById('canvas') as HTMLCanvasElement;

const renderer = new Renderer({
  canvas,
  polyhedronType: 3,   // Dodecahedron
  division: 1,
  hole: 0.3,
  color: 0.6,
  speed: 1.5,
});

renderer.start();

Dynamic updates

You can change any parameter on the fly after initialization.

// ... after renderer is started

// Switch to Icosahedron with higher subdivision and different color
renderer.update({
  polyhedronType: 4,
  division: 2,
  color: 0.9,
});

// You can also add rotation from external controls (e.g., keyboard)
renderer.addRotation(0.1, 0.05);

// Get current state
const state = renderer.getState();
console.log(state);

Low-level control

For advanced scenarios where you need to customize every step, use the individual components directly.

import {
  Icosahedron,
  Projector,
  RotationController,
  LightingCalculator,
  PolyhedronDrawer,
} from '@alekstar79/3d-polyhedra';

const canvas = document.getElementById('canvas') as HTMLCanvasElement;
const ctx = canvas.getContext('2d')!;

// Set up components
const poly = new Icosahedron();
const projector = new Projector([0, 0, 5], 0.5, canvas.width, canvas.height);
const rotation = new RotationController();
const lighting = new LightingCalculator();
lighting.setLightDirection([1, 1, 1]);
const drawer = new PolyhedronDrawer(ctx);

function animate() {
  const matrix = rotation.update(16, 1.0);
  const level = 0;

  const verts = poly.verticesD[level];
  const faces = poly.facesD[level];
  const normals = poly.faceNormalsD[level];
  const centers = poly.faceCentersD[level];
  const colors = poly.colorsD[level];

  // Apply rotation, project, calculate lighting, and draw
  const rotatedVerts = verts.map(v => applyMatrix(v, matrix));
  const rotatedNormals = normals.map(n => applyMatrix(n, matrix));
  const rotatedCenters = centers.map(c => applyMatrix(c, matrix));

  const projectedVerts = projector.projectMany(rotatedVerts);
  const projectedCenters = projector.projectMany(rotatedCenters);
  const intensities = lighting.calculateIntensities(rotatedNormals);

  ctx.clearRect(0, 0, canvas.width, canvas.height);
  drawer.draw(
    projectedVerts,
    faces,
    projectedCenters,
    colors,
    0.0,          // hole size
    intensities,
    0.5           // color parameter
  );

  requestAnimationFrame(animate);
}
animate();

// Helper: apply 3x3 matrix to a vector
function applyMatrix(v: [number, number, number], m: readonly number[]): [number, number, number] {
  const [x, y, z] = v;
  const [m00, m01, m02, m10, m11, m12, m20, m21, m22] = m;
  return [
    m00 * x + m01 * y + m02 * z,
    m10 * x + m11 * y + m12 * z,
    m20 * x + m21 * y + m22 * z,
  ];
}

More Examples

The repository includes a dedicated examples/ folder with ready-to-run TypeScript files that demonstrate real-world use cases:

  • basic-dodecahedron.ts – minimal setup with a Dodecahedron.
  • subdivision-demo.ts – shows dynamic subdivision and switching between polyhedra.
  • low-level.ts – full low-level implementation (same as above but complete).

You can browse or download these files directly from the examples/ folder.


API Reference

Renderer

Main class that orchestrates the rendering pipeline.

Constructor

new Renderer(config: RendererConfig)

| Parameter | Type | Description | |-------------------------|---------------------|--------------------------------------------------------------------| | config.canvas | HTMLCanvasElement | Canvas element to render on | | config.polyhedronType | PolyhedronType | 0=Tetrahedron, 1=Cube, 2=Octahedron, 3=Dodecahedron, 4=Icosahedron | | config.division | number | Subdivision level (0–4) | | config.hole | number | Hole size (0–0.9) | | config.color | number | Color hue parameter (0–1.2) | | config.speed | number | Rotation speed multiplier |

Methods

| Method | Description | |--------------------------------------|---------------------------------------------------------------| | update(config: RendererUpdate) | Update one or more parameters (partial update) | | getState(): RendererState | Returns current full state | | start(): void | Starts the animation loop | | stop(): void | Stops animation (currently placeholder) | | resize(): void | Manually trigger resize (handles window resize automatically) | | addRotation(deltaX, deltaY): void | Add relative rotation (for custom controls) | | setLightDirection(dir: Vec3): void | Set light direction vector |

Properties

| Property | Type | Description | |---------------|-------------------------|--------------------------| | onFpsUpdate | (fps: number) => void | Callback for FPS updates |

Types

type PolyhedronType = 0 | 1 | 2 | 3 | 4;

interface RendererConfig {
  canvas: HTMLCanvasElement;
  polyhedronType: PolyhedronType;
  division: number;
  hole: number;
  color: number;
  speed: number;
}

interface RendererState extends RendererConfig {}

type RendererUpdate = Partial<RendererState>;

type Vec3 = readonly [x: number, y: number, z: number];
type Vec2 = readonly [x: number, y: number];
type Mat3 = readonly [ ... ]; // 9 numbers

Low-level Components

If you need more control, you can use individual components:

  • Polyhedron – base class (extended by Tetrahedron, Cube, etc.)
  • Projector – 3D to 2D projection
  • RotationController – handles rotation accumulation
  • LightingCalculator – calculates face intensities
  • PolyhedronDrawer – renders faces on Canvas 2D

Project Structure

src/
├── lib/                     # Library source
│   ├── index.ts            # Public API entry
│   ├── types.ts            # Interfaces and types
│   ├── math.ts             # Vector/matrix utilities
│   ├── polyhedron.ts       # Polyhedron classes
│   ├── projector.ts        # Projection logic
│   ├── rotation-controller.ts
│   ├── lighting-calculator.ts
│   ├── polyhedron-drawer.ts
│   └── renderer.ts         # Main renderer
├── demo/                    # Demo application
│   ├── app.ts
│   ├── ui.ts
│   ├── index.html
│   └── styles.css
├── examples/                # Example usage files
│   ├── basic-dodecahedron.ts
│   ├── subdivision-demo.ts
│   └── low-level.ts
├── dist/                    # Built demo (output)
├── lib-dist/                # Built library (for npm)
├── package.json
├── tsconfig.json
├── vite.config.ts          # Demo build config
├── vite.lib.config.ts      # Library build config
└── README.md

Build & Development

Commands

| Command | Description | |----------------------|---------------------------------------------------------| | npm run dev | Start demo dev server (port 3000) | | npm run build:demo | Build demo into dist | | npm run build:lib | Build library into lib-dist (JS + .d.ts) | | npm run build | Build both library and demo | | npm run preview | Preview built demo | | npm publish | Publish library to npm (runs build:lib automatically) |

Library Build Output

  • lib-dist/polyhedra3d.es.js – ESM format
  • lib-dist/polyhedra3d.umd.js – UMD format (for browsers, AMD, CommonJS)
  • lib-dist/index.d.ts – TypeScript declarations

Browser Support

The library works in all modern browsers that support:

  • Canvas 2D
  • ES6 modules
  • Touch events (for mobile)

Tested on:

  • Chrome 90+
  • Firefox 88+
  • Safari 14+
  • Edge 90+
  • Mobile Safari/Chrome

Contributing

Contributions are welcome! Please follow these steps:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Please ensure your code passes TypeScript strict checks and includes proper tests (if applicable).


License

This project is licensed under the MIT License – see the LICENSE file for details.


Contact