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

@juanlaria/lifted

v0.1.5

Published

Beautiful, realistic CSS shadows with layered depth - inspired by Josh Comeau & Tobias Ahlin

Readme

Lifted

Beautiful, realistic CSS shadows with layered depth.

Inspired by Josh Comeau's "Designing Beautiful Shadows" and Tobias Ahlin's "Smoother & sharper shadows".

Features

  • Layered shadows using powers-of-2 technique for realistic depth
  • Continuous elevation (-1 to 1) with smooth interpolation
  • Inner shadows - negative elevation creates inset/pressed effects
  • Dynamic light source - static angles or mouse/cursor tracking
  • Color-matched shadows - automatically derives shadow color from background
  • Dark mode support - automatic detection + manual override
  • Framework agnostic - works with React, vanilla JS, or any framework
  • Next.js App Router compatible - includes "use client" directives

Installation

npm install @juanlaria/lifted

Quick Start

React

import { LiftedBox } from '@juanlaria/lifted/react';

// Raised card
<LiftedBox elevation={0.5} background="#FDFDFD">
  Card content
</LiftedBox>

// Pressed/inset effect
<LiftedBox elevation={-0.3} background="#F5F5F5">
  Pressed button
</LiftedBox>

// Mouse-tracking light
<LiftedBox elevation={0.6} lightSource="mouse">
  Dynamic shadows!
</LiftedBox>

Vanilla JavaScript

import { initLiftedBox } from '@juanlaria/lifted/vanilla';

const instance = initLiftedBox(element, {
  elevation: 0.5,
  background: '#FDFDFD',
});

instance.setElevation(-0.2); // Inner shadow
instance.destroy(); // Cleanup

API Reference

LiftedBox Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | elevation | number | 0.3 | Elevation level from -1 (max inner shadow) to 1 (max drop shadow). Negative = inset, zero = none, positive = raised. | | as | keyof JSX.IntrinsicElements | 'div' | HTML element to render as ('div', 'section', 'button', etc.). | | lightSource | number \| 'mouse' \| 'ambient' \| LightSource | -45 | Light source configuration. Number = angle in degrees, 'mouse' = follows cursor, 'ambient' = even shadow on all sides. | | background | string | — | Background color (CSS). Used to auto-calculate shadow color. | | shadowColor | string | — | Manual shadow color override (CSS color). | | shadowColorDark | string | — | Shadow color for dark mode when using auto-detect. | | intensity | number | 1 | Shadow opacity multiplier. 0.5 = lighter, 1 = normal, 2 = darker. | | scale | number | 1 | Shadow size multiplier. 0.5 = smaller/contained (~8px max), 1 = default (~16px max), 2 = larger/dramatic (~32px max). | | animated | boolean | true | Whether to animate shadow changes with transitions. Automatically disabled when using lightSource="mouse" for smooth tracking. | | transitionDuration | number | 150 | Transition duration in milliseconds. | | children | React.ReactNode | — | Content to render inside the component. |

Plus all standard HTML div attributes (className, style, onClick, etc.).

Light Source Options

// Static angle (degrees, -180 to 180)
// -45 = top-left, 0 = left, 45 = top-right, 90 = top
<LiftedBox lightSource={-45} />

// Mouse tracking (follows cursor)
<LiftedBox lightSource="mouse" />

// Full configuration object
<LiftedBox
  lightSource={{
    type: 'mouse',
    fallbackAngle: -45,  // Angle when mouse unavailable (default: -45)
  }}
/>

// Custom controlled angle
<LiftedBox
  lightSource={{
    type: 'custom',
    angle: myAngleState,
  }}
/>

// Ambient light - even shadow on all edges (no directional offset)
// Great for "detaching" elements from their container
<LiftedBox lightSource="ambient" elevation={0.5} />

Elevation Values

| Value | Effect | |-------|--------| | -1 | Maximum inner shadow (deeply pressed) | | -0.5 | Medium inner shadow | | -0.3 | Subtle pressed effect | | 0 | No shadow | | 0.3 | Subtle raised card | | 0.5 | Medium elevation | | 0.75 | High elevation (modals, dropdowns) | | 1 | Maximum floating effect |

Vanilla JS API

initLiftedBox(element, options)

Initializes shadow on a DOM element.

const instance = initLiftedBox(element, {
  elevation: 0.5,
  lightSource: -45,
  background: '#FFFFFF',
  shadowColor: undefined,      // Auto-calculated from background
  shadowColorDark: undefined,  // For dark mode
  intensity: 1,
  animated: true,
  transitionDuration: 150,
  isDarkMode: false,
});

Instance Methods

| Method | Description | |--------|-------------| | setElevation(n) | Update elevation (-1 to 1) | | setLightSource(source) | Update light source | | update(options) | Update multiple options at once | | getShadowCSS() | Get current box-shadow CSS string | | destroy() | Remove shadows and cleanup listeners |

Utility Functions

import {
  generateBoxShadow,
  applyLift,
  removeLift,
  getLiftCSS
} from '@juanlaria/lifted/vanilla';

// Generate CSS string directly
const css = generateBoxShadow(0.5, { background: '#FFF' });
// → "0.7px 0.7px 1px hsl(...)..."

// Apply shadow to element (one-time, no instance)
applyLift(element, 0.5, { background: '#FFF' });

// Remove shadow from element
removeLift(element);

// Get CSS without applying
const shadowCSS = getLiftCSS(0.5, { background: '#FFF' });

Presets

import { ELEVATION_PRESETS } from '@juanlaria/lifted';

// Available presets:
ELEVATION_PRESETS.deepInset  // -0.75
ELEVATION_PRESETS.inset      // -0.3
ELEVATION_PRESETS.none       // 0
ELEVATION_PRESETS.subtle     // 0.15
ELEVATION_PRESETS.small      // 0.25
ELEVATION_PRESETS.medium     // 0.5
ELEVATION_PRESETS.large      // 0.75
ELEVATION_PRESETS.xlarge     // 1

Hooks (React)

import { useElevation, useDarkMode } from '@juanlaria/lifted/react';

// Interactive elevation with hover/active states
const { elevation, elevationProps } = useElevation({
  base: 0.3,    // Default state
  hover: 0.5,   // On hover
  active: -0.1, // On click (inner shadow!)
});

<LiftedBox elevation={elevation} {...elevationProps}>
  Interactive card
</LiftedBox>

// Dark mode detection (SSR-safe)
const isDark = useDarkMode();

TypeScript

Full TypeScript support included. Key types:

import type {
  LiftedBoxProps,
  LightSource,
  LightSourceProp,
  VanillaLiftedBoxOptions,
  VanillaLiftedBoxInstance,
  ShadowOptions,
  ShadowResult,
} from '@juanlaria/lifted';

License

MIT © Juan Laria