# Flow Lines

> A dense field of thin parallel lines behind a section's content that flows like silk: a slow, smooth noise field bends every line in long gentle waves, neighbours moving together, so the field reads like a surface or a contour map in a breeze. The pointer is a soft weight on it: nearby lines are pushed away, take on the accent where they bend the most and spring back with a small bounce when it moves on, so a moving pointer leaves a short living wake. A click sends a ring out across the field. The hero of this site runs it.

Source: https://ngwr.dev/animations/flow-lines  
Kind: Animation, Component, WebGL  
Added in v15.7

## Installation

Import the class, and `@use` the entry point in your global styles. Nothing warns you when the `@use` is missing.

```typescript
import { Component } from '@angular/core';
import { WrFlowLines } from 'ngwr/animations/flow-lines';

@Component({ imports: [WrFlowLines] })
export class MyComponent {}
```

```scss
@use 'ngwr/animations/flow-lines';
```

## Basic

Put `<wr-flow-lines />` first inside the region it should fill. The drawing is one WebGL pass: every pixel measures its distance to the nearest line of the bent field, so a line is a crisp anti-aliased hairline and a curve is smooth whatever bends it, never a chain of segments. The context is made when the host is first on screen and sized, and the loop runs while it stays on screen and the document is visible: thirty frames a second while only the drift moves, the screen's rate while a wake, a ripple or the intro is live. The parent takes the pointer, passively; a moving finger is ignored, so a scroll over the section is never fought, and a tap may ripple.

```angular-html
<section class="hero">
  <wr-flow-lines />
  <h1>Angular components that bind straight to Signal Forms.</h1>
</section>
```

## The parent

The host is absolute, `inset: 0`, at `z-index: -1`, under no pointer, and the field fades out softly at the top and the bottom; the sides run on to the edge. The parent provides two things: it is positioned, so the host fills it, and isolated, so the host's negative z-index lands at the floor of the parent's own stacking context, under the content and over the page background.

```scss
.hero {
  position: relative;
  isolation: isolate;
}
```

## Calmer

`spacing` is the distance between two lines, `amplitude` how far the drift bends a line at most, both in px, `speed` how fast the drift moves and `push` how hard the pointer pushes; none turns the push off. Wider lines, a lower and slower wave and a lighter touch is a field that barely stirs.

```angular-html
<wr-flow-lines spacing="14" amplitude="16" speed="0.5" push="0.6" />
```

## Vertical

`orientation` set to `vertical` runs the lines from top to bottom. Everything else, the drift, the pointer's push and the ripple, works the same way; `twist` tilts from whichever way they run.

```angular-html
<wr-flow-lines orientation="vertical" />
```

## Dense, with a twist

Closer lines, a finer `lineWidth` (px) and a `twist` (degrees; positive falls toward the inline end, mirrored under RTL) is a sheet of silk rather than a ruled page; a higher `amplitude` bends it further. The canvas renders under a pixel budget of its own, so a wide section is never a wide texture, and the cost is per pixel, not per line.

```angular-html
<wr-flow-lines spacing="7" lineWidth="0.75" twist="-8" amplitude="36" />
```

## Dashed

`dashed` cuts every line into dashes that stream along it, each line starting its dashes at a place of its own, so the field reads as a current rather than a grid. `speed` moves the dashes as it moves the drift.

```angular-html
<wr-flow-lines dashed speed="1.4" />
```

## The push and the ripple

`reach` is how far from the pointer a line is still pushed, in px, with a smooth falloff to nothing at the edge; `push` is how far it moves them, a seventh of `reach` at one, nothing right at the pointer and the most about halfway out, so the lines part round it like water round a stone; `bounce` is how far a released line swings past its place before it settles, none settling without a swing. A click sends a ring out across the field, lifting the lines as it passes and tinting its crest; `ripple` turns it off.

```angular-html
<wr-flow-lines ripple="false" />
```

## Intro

`intro` draws the lines in from the inline start the first time the host is on screen, each line a little behind the one before, over about a second and a half. Under reduced motion the field is whole from the first frame.

```angular-html
<wr-flow-lines intro />
```

## Colours

A line is `--wr-flow-lines-color`, the muted ink by default, and a pushed line and a ripple's crest blend toward `--wr-flow-lines-accent`, the primary by default; set either on the host, where the defaults are declared. Both are read through `resolveCssColorChannels` and re-read when the scheme changes. The surface is read too: on a dark one the lines lay a little more light than they lay ink on a light one, so the field weighs the same under both schemes.

```angular-html
<wr-flow-lines style="--wr-flow-lines-color: var(--wr-color-info); --wr-flow-lines-accent: var(--wr-color-warning)" />
```

## API

| Name | Description | Type | Default |
| --- | --- | --- | --- |
| `spacing` | Between two lines, in CSS px, four at least. | `number` | `10` |
| `lineWidth` | How thick a line is, in CSS px. | `number` | `1` |
| `amplitude` | How far the drift bends a line at most, in CSS px. | `number` | `28` |
| `orientation` | Which way the lines run across the region. | `WrFlowLinesOrientation` | `'horizontal'` |
| `twist` | The lines' tilt from their orientation, in degrees: positive falls toward the inline end. | `number` | `0` |
| `speed` | How fast the drift and the dashes move, a multiplier: none holds the field still between pushes. | `number` | `1` |
| `reach` | How far from the pointer a line is still pushed, in CSS px. | `number` | `160` |
| `push` | How hard the pointer pushes, a multiplier: one moves a line a seventh of `reach` at most; none turns the push off. | `number` | `1` |
| `bounce` | How much a released line swings past its place, a multiplier: none settles without a swing. | `number` | `1` |
| `ripple` | Whether a click, or a tap, sends a ring out across the field. | `boolean` | `true` |
| `intro` | Whether the lines draw in from the inline start when first on screen. | `boolean` | `false` |
| `dashed` | Whether the lines are dashed, with the dashes streaming along them. | `boolean` | `false` |

## Accessibility

| Part | Behaviour |
| --- | --- |
| Screen readers | Decorative: the host is `aria-hidden`, holds no text, takes no pointer and is never focusable. The listeners on the parent are passive and stop nothing, so every control over the field behaves as before. |
| Touch | A moving finger pushes nothing, nothing is prevented and `touch-action` is left alone, so a scroll that starts over the region scrolls. A tap sends a ripple, as a click does. |
| Reduced motion | Under `prefers-reduced-motion: reduce` one still frame of the whole field is drawn, with no push, no ripple and no intro, and nothing moves; a preference that flips mid-flight stops the loop at once. Under `forced-colors: active` nothing is drawn. |
| Contrast | A line is a hairline laid in the muted ink at well under full coverage, so the text over it reads as it does on the plain surface; the accent shows only where a line is pushed. |
| No WebGL | Without WebGL nothing is drawn; a lost context is let go and rebuilt when the browser restores it. |
| Server | The empty canvas is rendered, absolutely positioned, so the browser's first draw shifts no layout. |

## CSS variables

Set these on the element itself, with a rule more specific than its Declared on selector. In a global stylesheet, put a class of yours on an ancestor it really has: `<body>` for an overlay panel, which renders outside your markup. In a component stylesheet the selector alone works, but only for an element in that component's own template. A value on a wrapper or `:root` is shadowed, because `ngwr/animations/flow-lines` declares each default on its own element.

| Variable | Default | Declared on |
| --- | --- | --- |
| `--wr-flow-lines-accent` | `var(--wr-color-primary)` | `.wr-flow-lines` |
| `--wr-flow-lines-color` | `var(--wr-color-on-surface-muted)` | `.wr-flow-lines` |

## See also

- [Thread Lines](https://ngwr.dev/animations/thread-lines) — A wide ribbon of fine threads behind a section's content, like silk: dozens of hair-thin strands flowing across the region at a slight angle, close together near one end, almost a single cord, and parting as they go toward the other, each taking a path of its own.
- [Dot Grid](https://ngwr.dev/animations/dot-grid) — An even field of small, faint dots behind a section's content.
- [Motion](https://ngwr.dev/guides/tokens/motion) — Easing and duration tokens for your transitions and animations.
- [Alert](https://ngwr.dev/reference/components/alert) — An inline status message.
