<!-- Protocore Design System — LineArt -->
# LineArt

- **Category:** Media (`media`)
- **Slug:** `media/line-art`
- **Status:** stable
- **Platforms:** web
- **Import:** `import { LineArt } from "@protocore/pds";`
- **Docs:** https://pds.protocore.io/components/media/line-art

> The house generative imagery — hundreds of thin currentColor strokes.

## The house imagery

**LineArt** is Protocore's illustration language: no fills, no photography, no gradients — light and volume implied purely by **line density**. Every field is hundreds of sub-pixel strokes drawn at low alpha with `stroke="currentColor"`, so the whole field inverts automatically with the theme (the `<svg>` defaults to `--pds-color-muted`). Set `color` on the `<LineArt>` element itself to retint it — `--pds-accent` for a hero, `--pds-color-muted` for a quiet backdrop. There are **44 variants** in two families: **band fields** (wide 1000×400, full-bleed) and **centered fields** (square 1000×1000, rendered cover). Set the wrapper's height and let the field fill edge to edge — it is composed to leave no dead corners.

## Usage budget

LineArt is deliberately quiet — treat it as texture, not content. **One field per view.** Keep it behind or beside real content, never competing with it: at `--pds-color-muted` (opacity capped at 0.42) it reads as a whisper; reserve `bold` and `--pds-accent` for a single hero moment per page. Never place body text directly over a dense field without a surface or scrim behind the text. Because it is pure `currentColor` line work it costs nothing in assets and re-themes for free — but its restraint is what makes it read as *system*, not decoration.

## Props

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `animate` | `boolean` | no | `true` | Draw the strokes in on mount (front-to-back, ease-out). Set false — or rely on `prefers-reduced-motion` — to render the final frame instantly. |
| `bold` | `boolean` | no | `false` | Bolder rendering — denser alpha, brighter focal points. For hero fields. |
| `className` | `string` | no | — | Extra className on the root `<svg>`. |
| `style` | `CSSProperties` | no | — | Inline style merged onto the root `<svg>`. |
| `variant` | `enum` | no | `valley` | Which generative field to render. |

## Examples

### Band fields

Wide, full-bleed fields for section backdrops and strip dividers. They stretch to any aspect ratio. Good defaults: `valley`, `horizon`, `sweep`, `grid`, `waveform`.

```tsx
import { LineArt, Text, type LineArtVariant } from "@protocore/pds";

const BANDS: LineArtVariant[] = [
  "valley",
  "horizon",
  "sweep",
  "vortex",
  "lens",
  "grid",
  "mesh",
  "stream",
  "waveform",
  "contour",
  "terrain",
  "scan",
  "weave",
  "fan",
  "rays",
  "wavefront",
  "hatch",
  "delta",
  "comb",
];

function Field({ variant }: { variant: LineArtVariant }) {
  return (
    <figure style={{ margin: 0 }}>
      <div
        style={{
          height: 96,
          color: "var(--pds-color-muted)",
          border: "1px solid var(--pds-border-faint)",
          overflow: "hidden",
        }}
      >
        <LineArt variant={variant} style={{ width: "100%", height: "100%", display: "block" }} />
      </div>
      <figcaption style={{ marginTop: "var(--pds-space-2)" }}>
        <Text as="span" size="sm" mono color="muted">
          {variant}
        </Text>
      </figcaption>
    </figure>
  );
}

export default function Demo() {
  return (
    <div
      style={{
        display: "grid",
        gridTemplateColumns: "repeat(auto-fill, minmax(180px, 1fr))",
        gap: "var(--pds-space-4)",
      }}
    >
      {BANDS.map((v) => (
        <Field key={v} variant={v} />
      ))}
    </div>
  );
}
```

### Centered fields

Square, volumetric fields rendered `cover` so they fill their frame from the center — wireframe spheres, stacked discs, orbits, lattices. Use these where the composition has a clear focal point (a card, a feature tile, a spot illustration).

```tsx
import { LineArt, Text, type LineArtVariant } from "@protocore/pds";

const CENTERED: LineArtVariant[] = [
  "sphere",
  "globe",
  "cylinder",
  "dome",
  "torus",
  "cube",
  "gyro",
  "shell",
  "orbit",
  "atom",
  "spiral",
  "helix",
  "moire",
  "ripple",
  "star4",
  "flare",
  "swaps",
  "quincunx",
  "corners4",
  "nexus",
  "burst",
  "rosette",
  "lattice",
  "nodes",
];

function Field({ variant }: { variant: LineArtVariant }) {
  return (
    <figure style={{ margin: 0 }}>
      <div
        style={{
          height: 140,
          color: "var(--pds-color-muted)",
          border: "1px solid var(--pds-border-faint)",
          overflow: "hidden",
        }}
      >
        <LineArt variant={variant} style={{ width: "100%", height: "100%", display: "block" }} />
      </div>
      <figcaption style={{ marginTop: "var(--pds-space-2)" }}>
        <Text as="span" size="sm" mono color="muted">
          {variant}
        </Text>
      </figcaption>
    </figure>
  );
}

export default function Demo() {
  return (
    <div
      style={{
        display: "grid",
        gridTemplateColumns: "repeat(auto-fill, minmax(160px, 1fr))",
        gap: "var(--pds-space-4)",
      }}
    >
      {CENTERED.map((v) => (
        <Field key={v} variant={v} />
      ))}
    </div>
  );
}
```

## Do & don't

**Do**

- Set an explicit height on the wrapper and let the field fill it edge to edge.
- Control tint by setting `color` on the `<LineArt>` element — `--pds-color-muted` for backdrops, `--pds-accent` for a hero.
- Reserve `bold` for large hero backdrops that need presence.
- Give text over a field a surface or scrim so it stays legible.

**Don't**

- Don't stack multiple LineArt fields in one viewport — one field, one moment.
- Don't raise the opacity past the designed cap; density, not alpha, carries the image.
- Don't lay unscrimmed body copy directly over a dense centered field.
- Don't treat it as a data visual — for real data use Sparkline or the charts family.

## Accessibility

**Notes**

- The root `<svg>` is `aria-hidden` — LineArt is purely decorative and never announced. Convey any meaning in adjacent real text.
- The draw-in respects `prefers-reduced-motion`: under it the field renders its final frame with no animation.
- Strokes use `currentColor`, so contrast follows the surrounding text color and inverts with the theme automatically.
- No focus, no interaction — it never sits in the tab order.

## Related

`logo`, `logo-marquee`, `icon`, `sparkline`

---

© Protocore. All rights reserved. Use of the Protocore Design System requires prior written authorization from Protocore (contact@protocore.io). These machine-readable materials must not be ingested into ML-training datasets or derivative design systems. See https://pds.protocore.io/legal/
