Tollerud

Tollerud UI/Backgrounds

Backgrounds · ported from tollerud.no

Backgrounds

The two atmospheres that power the live site, lifted into the system as drop-in components. Move your cursor over the grid — it lights the cell beneath it.

Noir glow · live shader

NoirGlowBackground from @tollerud/ui — the packaged @paper-design/shaders-react grain atmosphere (corners shape, yellow ramp, animated). Requires @paper-design/shaders-react in the host app.

NoirGlowBackground · live WebGL
noir-glow-live.jsx
<div className="relative min-h-[280px]">
  <NoirGlowBackground intensity="medium" speed="medium" className="absolute inset-0" />
  <div className="relative z-20">{children}</div>
</div>

Noir glow · CSS fallback

Pass forceCssFallback for static export, reduced-motion, or when WebGL is unavailable.

@tollerud/ui

Noir glow

Drop-in background for heroes and empty states. Pass forceCssFallback when WebGL is unavailable.

NoirGlowBackground · forceCssFallback
noir-glow.jsx
<NoirGlowBackground
  intensity="medium"
  preserveCenter
  forceCssFallback={false}
  className="absolute inset-0"
/>

Grain gradient · CSS only

A pure-CSS approximation using the same yellow ramp and corner composition — zero WebGL cost. NoirGlowBackground uses a similar fallback when forceCssFallback is set.

GrainGradient · CSS only

Hero readability treatments

Four ways to keep copy readable over the live grain gradient: a local blur scrim, a full-hero blur, a broad left-side shadow, or a scaled/offset shader that keeps motion toward the edges.

Copy blur scrim

v1.0 · noir + yellow>60 components

Dark. Monochrome.
Yellow where it counts.

The real Paper shader stays visible, while the copy keeps enough contrast to survive bright motion behind it.

copy blur scrim
hero-readable-scrim.jsx
import { NoirGlowBackground } from '@tollerud/ui'

export function HeroWithCopyScrim({ children }) {
  return (
    <section className="relative min-h-[420px] overflow-hidden">
      <NoirGlowBackground intensity="medium" className="absolute inset-0" />
      <div className="relative z-20 flex min-h-full items-center p-9">
        <div className="hero-copy-scrim max-w-[520px]">{children}</div>
      </div>
    </section>
  )
}
hero-readable-scrim.css
/* globals.css — local blur scrim behind copy only */
.hero-copy-scrim {
  margin: -24px -26px;
  padding: 24px 26px;
  border-radius: 14px;
  background: linear-gradient(90deg, rgba(0, 0, 0, 0.78), rgba(0, 0, 0, 0.54) 58%, rgba(0, 0, 0, 0.18));
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.42);
  backdrop-filter: blur(16px) saturate(0.9);
  -webkit-backdrop-filter: blur(16px) saturate(0.9);
}

Full hero blur

v1.0 · noir + yellow>60 components

Dark. Monochrome.
Yellow where it counts.

The whole hero gets a soft dark glass layer, so the copy reads without creating a separate text panel.

full hero blur
hero-readable-fullblur.jsx
import { NoirGlowBackground } from '@tollerud/ui'

export function HeroWithFullBlur({ children }) {
  return (
    <section className="relative min-h-[420px] overflow-hidden">
      <NoirGlowBackground intensity="medium" className="absolute inset-0" />
      <div className="hero-readable-fullblur absolute inset-0 z-10 pointer-events-none" aria-hidden />
      <div className="relative z-20 flex min-h-full items-center p-9">
        <div className="max-w-[520px]">{children}</div>
      </div>
    </section>
  )
}
hero-readable-fullblur.css
/* globals.css — soft glass across the whole hero */
.hero-readable-fullblur {
  background:
    radial-gradient(100% 100% at 50% 48%, rgba(0, 0, 0, 0.18), rgba(0, 0, 0, 0.46) 78%),
    rgba(0, 0, 0, 0.34);
  backdrop-filter: blur(14px) saturate(0.9);
  -webkit-backdrop-filter: blur(14px) saturate(0.9);
}

Left shadow gradient

v1.0 · noir + yellow>60 components

Dark. Monochrome.
Yellow where it counts.

The real Paper shader stays visible, while the copy keeps enough contrast to survive bright motion behind it.

left shadow gradient
hero-readable-shadow.jsx
import { NoirGlowBackground } from '@tollerud/ui'

export function HeroWithLeftShadow({ children }) {
  return (
    <section className="relative min-h-[420px] overflow-hidden">
      <NoirGlowBackground intensity="medium" className="absolute inset-0" />
      <div className="hero-readable-shadow absolute inset-0 z-10 pointer-events-none" aria-hidden />
      <div className="relative z-20 flex min-h-full items-center p-9">
        <div className="max-w-[520px]">{children}</div>
      </div>
    </section>
  )
}
hero-readable-shadow.css
/* globals.css — broad left-side shadow, shader stays visible on the right */
.hero-readable-shadow {
  background:
    radial-gradient(90% 120% at 0% 50%, rgba(0, 0, 0, 0.9) 0%, rgba(0, 0, 0, 0.68) 38%, rgba(0, 0, 0, 0.28) 64%, transparent 82%),
    linear-gradient(90deg, rgba(0, 0, 0, 0.68), rgba(0, 0, 0, 0.18) 58%, transparent);
}

Edge-biased shader

v1.0 · noir + yellow>60 components

Dark. Monochrome.
Yellow where it counts.

The shader is scaled down and shifted toward both edges, leaving calmer negative space behind the text.

edge-biased shader
hero-readable-edge.jsx
import { NoirGlowBackground } from '@tollerud/ui'

export function HeroWithEdgeShader({ children }) {
  return (
    <section className="relative min-h-[420px] overflow-hidden">
      <NoirGlowBackground intensity="medium" scale={1.55} offsetX={0.38} className="absolute inset-0" />
      <NoirGlowBackground intensity="subtle" speed="slow" scale={1.55} offsetX={-0.38} className="absolute inset-0" />
      <div className="relative z-20 flex min-h-full items-center p-9">
        <div className="max-w-[520px]">{children}</div>
      </div>
    </section>
  )
}

Animated grid

A scrolling canvas grid that fades to #060606 at the edges and fills the square under the cursor. Direction, speed, cell size and colors are all props.

direction: diagonal · #333 borders
accent: yellow borders + glow fill
squares.jsx
<Squares
  direction="diagonal"   // right | left | up | down | diagonal
  speed={0.5}
  squareSize={40}
  borderColor="#333"
  hoverFillColor="#222"
  base="#060606"
/>

In use

The grain gradient backs the Overview hero; the grid suits full-bleed section dividers and empty states. Both sit behind content at a lower z-index — keep foreground on z-20+.

live atmosphere

Run your stack like production.