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

tsl-sky

v0.1.4

Published

Production-quality Hillaire atmospheric sky for Three.js / TSL on the WebGPU renderer. Drop-in vanilla and React (R3F) entries.

Readme

tsl-sky

Production-quality atmospheric sky for Three.js / TSL on the WebGPU renderer. Port of Sébastien Hillaire's A Scalable and Production Ready Sky and Atmosphere Rendering Technique (EGSR 2020), with vanilla and React (R3F) entry points.

Install

npm install tsl-sky

Peer-deps: three (≥0.184), and optionally react + @react-three/fiber (≥10.0.0-alpha) if you use the React bindings. Requires the WebGPU renderer.

Vanilla

import * as THREE from 'three/webgpu';
import { pass } from 'three/tsl';
import { Sky } from 'tsl-sky';

const renderer = new THREE.WebGPURenderer({ antialias: true });
await renderer.init();

const sky = new Sky(renderer, {
  preset: 'earth',     // 'earth' | 'mars' | 'titan'
  timeOfDay: 14.5,     // 0..24
  latitude: 37.7,
  exposure: 40
});

const scene = new THREE.Scene();
sky.attach(scene);     // sets scene.environment + scene.background

renderer.setAnimationLoop(() => {
  sky.update(camera);
  renderer.render(scene, camera);
});

Aerial-perspective haze

import { pass } from 'three/tsl';

const scenePass = pass(scene, camera);
const post = new THREE.RenderPipeline(renderer);
post.outputNode = sky.applyHaze(scenePass.getTextureNode(), {
  scenePass,
  policy: 'auto'       // 'auto' | 'ap' | 'raymarch'
});

renderer.setAnimationLoop(() => {
  sky.update(camera);
  sky.updateAerialPerspective();
  post.render();
});

React (R3F)

import { Sky } from 'tsl-sky/react';
import { AutoHaze } from 'tsl-sky/react/auto-haze';

function Scene() {
  return (
    <>
      <Sky preset="earth" timeOfDay={14.5}>
        <AutoHaze />
      </Sky>
      <Mountains />
    </>
  );
}

<AutoHaze> lives in its own sub-export so the useRenderPipeline hook it depends on is only pulled into bundles that actually need it. R3F builds that don't yet export useRenderPipeline (e.g. @react-three/[email protected]) can still use the plain <Sky>; haze becomes available once your R3F build includes the hook.

To compose with your own pipeline, skip <AutoHaze /> and grab the instance via useSky():

import { useSky } from 'tsl-sky/react';
import { useRenderPipeline } from '@react-three/fiber/webgpu';

function CustomPipeline() {
  const sky = useSky();
  useRenderPipeline(({ renderPipeline, passes }) => {
    if (!sky) return;
    renderPipeline.outputNode = sky.applyHaze(
      passes.scenePass.getTextureNode(),
      { scenePass: passes.scenePass, policy: 'auto' }
    );
  });
  return null;
}

API

The Sky class:

| Method | Description | |---|---| | setTimeOfDay(hours) | NOAA solar position; combined with latitude + dayOfYear | | setLatitude(deg) / setDayOfYear(day) | Solar position inputs | | setSunDirection({ elevation, azimuth }) | Direct override | | setNorth('+X' \| '-X' \| '+Z' \| '-Z') | Which world axis is geographic north | | setExposure(n) | Sky luminance scale (default 40) | | setSunDisc(boolean \| { angularDiameter }) | Disc visibility + size in radians | | setTurbidity(n) | Mie scattering scalar (1 = Earth) | | setGroundAlbedo(n \| Vector3) | Multi-scatter LUT input | | setMirrorBelowHorizon(boolean) | Bake a Y-mirrored sky on the cube's lower hemisphere instead of lit-ground albedo (clean sky HDRI for reflective-floor scenes) | | setPreset('earth' \| 'mars' \| 'titan') | Swap atmosphere defaults | | setAtmosphere(partial) | Direct atmosphere-params override | | setHazeStrength(n) / setHazePolicy(p) / setHazeAltitudeBlend({startKm, endKm}) | Live haze knobs | | update(camera, { planetCenter? }) | Per-frame; planet-frame altitude when planetCenter is set | | updateAerialPerspective() | Per-frame; required when applyHaze is wired | | applyHaze(sceneColorNode, options) | Returns a vec4 TSL output node | | createSun(opts) / createGround(opts) / createGroundedSkybox(opts) / createMoon(opts) | Factories for the optional helper objects | | attach(scene) / detach() / dispose() | Lifecycle |

GroundedSkybox (optional)

A ground-projected skybox mesh — the lower hemisphere of the cube is reprojected onto a flat disc at world y=0, so the cube content acts as a "floor" without needing an explicit ground plane. Pass reflective: true for a mirror-floor / wet-pavement look (disc samples the cube via reflect(viewDir, +Y)). Pair with sky.setMirrorBelowHorizon(true) if you want PBR materials' downward IBL to match the visible floor.

const skybox = sky.createGroundedSkybox({ height: 4, radius: 200, reflective: false });
scene.add(skybox);

// per frame, so the disc stays anchored under the camera:
skybox.followCamera(camera);

Starters

Self-contained Vite projects you can clone and run:

npx degit DennisSmolek/tsl-sky-starters/vanilla my-sky-app
# or
npx degit DennisSmolek/tsl-sky-starters/r3f my-sky-app

Status

Phase 1 (baked sky), Phase 2 (aerial perspective), and Phase 3 (planet-scale ground→orbit) are functional. Volumetric clouds and god-rays are out of scope.

Changelog

  • 0.1.4
    • New GroundedSkybox. Ground-projected skybox mesh that reprojects the cube's lower hemisphere onto a flat disc at world y=0. Optional reflective mode for wet-pavement / mirror-floor looks. Use sky.createGroundedSkybox({ height, radius, reflective }). See examples/15-grounded-skybox.html for dial-in.
    • New mirrorBelowHorizon constructor option + sky.setMirrorBelowHorizon(flag) runtime setter. When enabled, the cube bake fills the lower hemisphere with a clean Y-mirror of the sky instead of the LUT's lit-ground-albedo content. Pair with reflective-floor scenes so PBR IBL doesn't pick up a coloured ground tint from below.
    • Sky-View LUT now bakes the ground-albedo bounce by default. environmentTexture's lower hemisphere is lit ground colour instead of black/dim, so matte materials' downward IBL picks up the ground tint correctly without needing an explicit SkyGround plane. Flip back to the previous behaviour any time by toggling mirrorBelowHorizon on (which bypasses the ground branch entirely).
  • 0.1.3 — Reuse the PMREM render target across bakes so environmentTexture keeps stable identity. Prior versions reallocated per sun/atmosphere change, which invalidated the WebGPU TSL pipeline cache for every material referencing scene.environment and stalled renderer.render() (~150 ms per slider tick in consumer scenes with many TSL materials).

License

MIT © Dennis Smolek