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

@pmndrs/sky

v0.3.0

Published

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

Readme

@pmndrs/sky ports Sébastien Hillaire's A Scalable and Production Ready Sky and Atmosphere Rendering Technique (EGSR 2020) to Three.js TSL. Attach it to a scene and you get a physically-based sky driven by real solar position, correct at any camera altitude from ground level to orbit, with an opt-in aerial-perspective haze post-process for distant geometry — vanilla and React (R3F) entry points, one update() call per frame.

Full docs → · Demo gallery →

Install

npm install @pmndrs/sky
# or
pnpm add @pmndrs/sky

Peer-deps: three (≥0.185), and optionally react + @react-three/fiber (≥10.0.0-alpha.4 — earlier 10.x canaries import a WebGL-only class from three/webgpu and fail to load) if you use the React bindings. Requires the WebGPU renderer — see Installation for details.

Quick start

import * as THREE from 'three/webgpu'
import { Sky } from '@pmndrs/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)
})

See Your First Sky for the full walkthrough, or jump straight to examples/vanilla to run it locally.

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()
})

Full explanation of the AP-LUT/raymarch policies and known limitations: Haze guide.

React (R3F)

import { Sky } from '@pmndrs/sky/react'
import { AutoHaze } from '@pmndrs/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 '@pmndrs/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
}

Docs

A condensed method table for the Sky facade:

| 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 |

See the full Sky API reference for every option and setter.

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)

Demo gallery

Every example lives in examples/vanilla and is published at sky.docs.pmnd.rs/examples — baked sky, aerial-perspective haze, planet-scale ground-to-orbit, individual LUT debug views, and the numbered scratch demos used during development.

Status

Baked sky, aerial-perspective haze, and planet-scale (ground→orbit) rendering are all functional. Volumetric clouds and god-rays are out of scope.

Contributing

git clone https://github.com/pmndrs/sky.git
cd sky
pnpm install
pnpm run ci          # build + typecheck + lint + test + format check
pnpm example:vanilla  # Vite dev server on :5173 for examples/vanilla

The library itself builds via unbuild (pnpm dev runs unbuild --stub for library dev — that's not the examples server). See CLAUDE.md for the architecture write-up and a running list of hard-won implementation gotchas, and ROADMAP.md for current status and open work.

Changelog

  • 0.3.0
    • Fix React Suspense disposal. Keep the <Sky> resource owner mounted while children load assets, preventing Sky: instance is disposed errors when StrictMode replays effects. Suspended children now render a null fallback inside <Sky>.
    • Add a regression test covering suspended child rendering, layout effects, and passive effects in StrictMode.
  • 0.2.0 — first npm release.
    • Stylized looks. An artist-control layer over the physical sky: a colour ramp over view elevation plus a sun-relative tint, blended on two axes — chroma (swap hue, keep physical luminance) and value (override luminance too, for artificial moonlight). sky.setLook('ghibli-day'), sky.setLookTrack('ghibli') (follows sun elevation), registerLook(...). Built-in ghibli-night/dusk/day. Background, PMREM IBL and aerial-perspective haze all inherit the look. See docs/guides/looks.mdx.
    • Unreal-parity knobs. setMultiScatteringFactor(n) (feeds the LUT bake), setSkyLuminanceFactor(color) and setAerialPerspectiveDistanceScale(n) (uniforms, no rebake).
    • React: look, lookTrack, skyLuminanceFactor, apDistanceScale, multiScatteringFactor props on <Sky>. <Sky> is now an effect-owned resource with an explicit disposal contract (StrictMode-safe).
    • React bindings require @react-three/fiber >= 10.0.0-alpha.4 — earlier 10.x canaries import a WebGL-only class from three/webgpu and fail to load.
    • Headless-WebGPU verification script for the looks layer: examples/vanilla/scripts/verify-looks.mjs.
    • Known: the built-in Ghibli palette is a first pass and will be re-tuned.
  • 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/vanilla/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