Getting started
linescape draws large, designed lines behind websites and elements. You describe a line (where it goes, what it does along the way, how thick and what colour) and linescape builds the SVG for the element's real size, every time that size changes.
{ path: { from: "left 80%", to: "right 30%", bend: 0.08 },
features: [{ type: "loop", at: 0.55, radius: 50 }],
width: 48, paint: "#7c5cff" }Install
npm install linescapeReact is an optional peer dependency (18 or 19). The core, imported from linescape, has no dependencies and runs anywhere. The React component lives at linescape/react.
React
<Linescape> is a layer, not a wrapper. Put it inside the element it should sit behind, and give that element linescapeParentStyle:
import { linescapeParentStyle } from "linescape";
import { Linescape } from "linescape/react";
<section style={linescapeParentStyle}>
<Linescape line={{ path: { through: "center", angle: -12 }, width: 220, paint: "#ffe3d3" }} />
{children}
</section>linescapeParentStyle is { position: "relative", isolation: "isolate" }. The first makes the layer cover this element; the second keeps the layer (which uses z-index: -1) from slipping behind the element's own background. In development, <Linescape> warns if the parent is missing either. Import it from linescape, as above: imported from linescape/react (a client module) into a server component, it arrives as an empty reference and the styles silently drop out.
Several lines
One layer holds any number of lines, drawn in order, so later lines sit on top:
<Linescape lines={[band, swoosh]} />A content column, full-width lines
Put <Linescape> in a narrow column and add fullBleed: the layer keeps the column's height and breaks out to the full viewport width. Add overflow-x: clip to body to rule out a brief horizontal scrollbar before hydration.
Next.js and server rendering
<Linescape> ships with "use client" and renders on the server too. Lines depend on the element's size, which the server doesn't know, so the server renders at initialSize (1440 × 900) with the layer hidden; after mount it measures, redraws and fades in over 150ms, so lines never jump. With reveal="none" the server render shows straight away and is redrawn once measured.
Props
| Prop | Default | Meaning |
|---|---|---|
line / lines | One line, or several. | |
attach | "scroll" | "fixed" pins the layer to the viewport. |
fullBleed | false | Break out to the full viewport width. |
clip | true | Clip lines to the layer. |
initialSize | 1440 × 900 | Size rendered before measuring. |
reveal | "fade" | "none" shows the server render without waiting. |
className, style | On the layer. |
Phones
A line has one spec. A 220px band that suits a desktop hero can dominate a phone, so pass a thinner line at small widths (from a media query hook, or your own breakpoints). linescape deliberately has no responsive options of its own.
Next
Paths, patterns and features describe the shape; stroke and paint its look; animation how it moves. Or start in the playground and copy the code.