# Ripple Grid

> Grid lines behind your content that the pointer sends ripples through.

Source: https://ngwr.dev/bits/ripple-grid  
Added in v15.1

## Installation

Import the class, and `@use` the entry point in your global styles: without it the component renders unstyled.

```typescript
import { Component } from '@angular/core';
import { WrRippleGrid } from 'ngwr/bits/ripple-grid';

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

```scss
@use 'ngwr/bits/ripple-grid';
```

## Playground

Put it in a positioned box; it fills that box. Press anywhere in it, or move the pointer over the content in front of it.

```angular-html
<section style="position: relative; min-height: 18rem; overflow: hidden">
  <wr-ripple-grid
    [cellSize]="40"
    [lineWidth]="1"
    [strength]="10"
    [speed]="320"
    [decay]="1.4"
  />
  <h1 style="position: relative">Content above the grid</h1>
</section>
```

```angular-ts
import { Component } from '@angular/core';

import { WrRippleGrid } from 'ngwr/bits/ripple-grid';

/**
 * Playground
 */
@Component({
  selector: 'ngwr-the-angular-ui-library-for-signal-forms-playground-example',
  templateUrl: './ngwr-the-angular-ui-library-for-signal-forms-playground-example.html',
  imports: [WrRippleGrid],
})
export class NgwrTheAngularUiLibraryForSignalFormsPlaygroundExample {}
```

## On its own

An idle interval sends a ring out from the centre every so often, so the grid moves before anyone touches it. Here moves are ignored, a press still ripples, and the button keeps every click.

```angular-html
<section class="hero">
  <wr-ripple-grid [idleInterval]="2400" [rippleOnMove]="false" />
  <div class="hero__content">
    <h2>Make some waves</h2>
    <p>A ring leaves the centre on its own; a press anywhere sends another.</p>
    <wr-btn color="primary">Get started</wr-btn>
  </div>
</section>

<style>
  .hero { position: relative; min-height: 20rem; overflow: hidden; }
  .hero__content {
    position: relative;
    display: grid;
    place-items: center;
    align-content: center;
    gap: 1rem;
    min-height: 20rem;
    padding: 2rem;
    text-align: center;
  }
  .hero__content > * { margin: 0; }
</style>
```

```angular-ts
import { Component } from '@angular/core';

import { WrRippleGrid } from 'ngwr/bits/ripple-grid';
import { WrButton } from 'ngwr/button';

/**
 * On its own
 */
@Component({
  selector: 'ngwr-the-angular-ui-library-for-signal-forms-on-its-own-example',
  templateUrl: './ngwr-the-angular-ui-library-for-signal-forms-on-its-own-example.html',
  imports: [WrRippleGrid, WrButton],
})
export class NgwrTheAngularUiLibraryForSignalFormsOnItsOwnExample {}
```

## Light only

A strength of 0 keeps every line straight and only lights it. Colours take any CSS colour, a theme token included, and follow the colour scheme.

```angular-html
<section style="position: relative; min-height: 12rem; overflow: hidden">
  <wr-ripple-grid rippleColor="var(--wr-color-success)" [strength]="0" [cellSize]="24" />
</section>
```

```angular-ts
import { Component } from '@angular/core';

import { WrRippleGrid } from 'ngwr/bits/ripple-grid';

/**
 * Light only
 */
@Component({
  selector: 'ngwr-the-angular-ui-library-for-signal-forms-light-only-example',
  templateUrl: './ngwr-the-angular-ui-library-for-signal-forms-light-only-example.html',
  imports: [WrRippleGrid],
})
export class NgwrTheAngularUiLibraryForSignalFormsLightOnlyExample {}
```

## API

| Name | Description | Type | Default |
| --- | --- | --- | --- |
| `cellSize` | Distance between grid lines (px), never under 12. | `number` | `40` |
| `lineColor` | Line colour. Unset, it follows the theme. | `string \| null` | `null` |
| `rippleColor` | Colour a line takes where a ripple passes. Unset, it follows the theme. | `string \| null` | `null` |
| `lineWidth` | Line width (px), never under 0.25. | `number` | `1` |
| `strength` | How far a fresh ripple from a press bends the lines (px); a moving pointer bends them 40% as far. 0 only lights them; negative bends them inward. Never far enough to fold a line over: about 0.3 of a cell (11.7px at the default), shared by ripples that overlap. | `number` | `10` |
| `speed` | How fast a ripple travels outward (px per second). 0 keeps it where it started. | `number` | `320` |
| `decay` | How fast a ripple fades, per second: its strength is multiplied by e^-decay each second. | `number` | `1.4` |
| `rippleOnMove` | Whether a moving pointer leaves ripples behind it, and not only a press. | `boolean` | `true` |
| `idleInterval` | Milliseconds between the ripples sent out from the centre on their own, never under 500. 0 sends none. | `number` | `0` |

## CSS variables

Set these on the component's selector or a wrapper, not on `:root`: the defaults are declared on `ngwr/bits/ripple-grid`'s own element.

| Variable | Default | Declared on |
| --- | --- | --- |
| `--wr-ripple-grid-cell-size` | `40px` | `.wr-ripple-grid` |
| `--wr-ripple-grid-line-color` | `var(--wr-border-base)` | `.wr-ripple-grid` |
| `--wr-ripple-grid-line-width` | `1px` | `.wr-ripple-grid` |
| `--wr-ripple-grid-ripple-color` | `var(--wr-color-primary)` | `.wr-ripple-grid` |

## See also

- [Dot Grid](https://ngwr.dev/bits/dot-grid) — A field of dots behind your content that lights up and moves aside near the pointer.
- [Waves](https://ngwr.dev/bits/waves) — Drifting lines behind your content that bend around the pointer.
- [Threads](https://ngwr.dev/bits/threads) — Thin lines flowing behind your content like strands in a current.
- [Aurora](https://ngwr.dev/bits/aurora) — An animated aurora background for a hero or a section.
- [resolveCssColor](https://ngwr.dev/reference/utils/resolve-css-color) — Resolves a CSS colour, such as a var() or light-dark(), to a value a canvas can paint with.
