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

@luwiostack/utopia

v0.1.0

Published

Fluid, viewport-relative type and space scales — CSS clamp() vars ported from utopia.fyi's own calculator.

Readme

@luwiostack/utopia

Fluid, viewport-relative type, space & grid scales as CSS custom properties — clamp() math ported from utopia.fyi's own calculators (type, space, and grid), so a scale you've already tuned there drops straight in. No media-query breakpoints, no JS resize listener: each step interpolates smoothly between a size at one viewport width and a size at another.

Standalone — no dependency on @luwiostack/theme or anything else in LuwioStack. If you're already using @luwiostack/theme for colours, mount <Utopia> alongside <Theme>; they don't know about each other.

Install

npm install @luwiostack/utopia

react is a peer — needed only for @luwiostack/utopia/react.

Two entry points

  • @luwiostack/utopia — the React-free generator: generateVars, generateTextScaleVars, generateSpaceScaleVars, generateGridScaleVars, fluidClamp, DEFAULT.
  • @luwiostack/utopia/react — the one mounting component, <Utopia config?>.

config is optional everywhere it appears — omitting it is the same as 'on', so the scale is active by default. Pass it only to override.

Usage

import { generateVars } from '@luwiostack/utopia'

generateVars()
// → { '--step-0': 'clamp(1.125rem, ...)', '--step-1': '...', '--space-s': '...',
//     '--grid-gutter': '...', '--grid-columns': '12', '--grid-max-width': '77.5rem', ... }

generateVars returns a flat { [varName]: value } map — apply it however you like: spread it onto an inline style object (scoped to one element or container), or build your own <style> block.

React

import { Utopia } from '@luwiostack/utopia/react'

// Mount once, anywhere — active by default, no props needed. Renders one inline <style>
// targeting :root, SSR-safe.
<Utopia />

function Heading() {
  return <h1 style={{ fontSize: 'var(--step-2)' }}>Fluid heading</h1>
}

The scale

{
  "width": { "min": 360, "max": 1240 },
  "rootFontSize": 16,
  "units": ["vw", "cqi"],
  "text": {
    "fontSize": { "min": 18, "max": 20 },
    "typeScale": { "min": 1.2, "max": 1.25 },
    "steps": { "positive": 5, "negative": 2 },
    "prefix": "step"
  },
  "space": {
    "base": { "min": 18, "max": 20 },
    "multipliers": { "negative": [0.75, 0.5, 0.25], "positive": [1.5, 2, 3, 4, 6] },
    "pairs": { "oneUp": true, "custom": [["xs", "m"]] },
    "prefix": "space"
  },
  "grid": {
    "columns": 12,
    "gutter": { "min": 18, "max": 40 },
    "columnMaxWidth": 60,
    "prefix": "grid"
  }
}

text / space / grid compile viewport-relative type, space, and grid scales straight to clamp(). text emits one clamp() per step, named by signed offset from the base — --step-0, --step-1, --step--1, … — sized as baseSize * ratio^step (the min ratio at width.min, the max ratio at width.max); text.fontSize doubles as space's own base size below. space emits t-shirt-named tokens (--space-xs, --space-s, --space-m, …) built from multipliers of a base size, which defaults to text.fontSize when space.base isn't given directly. By default space also emits "one-up" pairs for the gaps between adjacent tokens (--space-s-m) — set pairs.oneUp: false to skip them, or add pairs.custom: [["s", "xl"]] for named pairs beyond the adjacent ones. grid emits --grid-gutter (a clamp(), the fluid column gap and outer container padding), --grid-columns (a plain column count, not fluid), and --grid-max-width (a plain rem value, derived as columns * columnMaxWidth + (columns + 1) * gutter.max — one gutter per internal gap, plus one on each outer edge). A {min, max} pair (width, fontSize, typeScale, base, gutter) is written whole or not at all — there's no partial pair.

Every fluid var is emitted once per unit in units (default ['vw', 'cqi']) — the first is unsuffixed (--step-0), every other gets a trailing -${unit} (--step-0-cqi, sized off a containing block with container-type: inline-size rather than the viewport; --grid-columns / --grid-max-width aren't fluid, so they're emitted once regardless). It's one setting for the whole config, shared by text, space, and grid alike, rather than something each declares on its own. Each scale's var prefix (step / space / grid) is itself just a default — pass text.prefix / space.prefix / grid.prefix to rename any of them.

Defaults

generateVars (and <Utopia config>) take Config = 'on' | Settings, and config is optional everywhere — omitting it is the same as 'on', which (like {}) means "give me DEFAULT in full". A partial Settings object merges underneath DEFAULT instead, so you only write what you want to change:

generateVars()                                            // DEFAULT in full
generateVars({ text: { fontSize: { min: 16, max: 18 } } }) // DEFAULT, with just fontSize overridden

width is required as soon as text, space, or grid is set (by you or by DEFAULT) — in practice this only matters if you build one of them by hand without going through 'on'/{}/a merge, since DEFAULT always supplies one. Pass text: null / space: null / grid: null inside an object form to drop just one scale, even though DEFAULT has it — independently of the other two:

generateVars({ space: null }) // DEFAULT's text and grid scales, no space scale at all
generateVars({ text: null, space: null, grid: null }) // {} — nothing to generate

DEFAULT mirrors utopia.fyi's own type, space, and grid calculators — DEFAULT.grid's gutter is that same space scale's s token (at width.min) through its l token (at width.max), and columnMaxWidth is its xl token's max, matching utopia.fyi/grid/calculator's own example exactly. Import DEFAULT directly to merge your own values over pieces of it yourself:

import { DEFAULT, generateVars } from '@luwiostack/utopia'

generateVars({ ...DEFAULT, width: { min: 320, max: 1240 } })