# Decode

> A readout locking on: every character shows random glyphs that change quickly, then settles on the real one, left to right. The line never moves while it plays.

Source: https://ngwr.dev/animations/decode  
Kind: Animation, Directive, DOM  
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 { WrDecode } from 'ngwr/animations/decode';

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

```scss
@use 'ngwr/animations/decode';
```

## Basic

Put `wrDecode` on the element that holds the text. By default it plays once, when most of the element is in view. A glyph keeps the shape of the character it stands in for, so the word shape stays readable, and spaces never scramble.

```angular-html
<wr-tag color="primary" outlined><span wrDecode>Developer experience</span></wr-tag>
<h2 wrDecode>Release 15.7 is out.</h2>
```

## Hover

`trigger="hover"` plays on every pointer enter and on focus, of the element or of its closest focusable ancestor, so a label inside a button decodes when the button is reached by keyboard too. A play in progress is never restarted.

```angular-html
<button wr-btn outlined type="button"><span wrDecode trigger="hover">Hover or focus me</span></button>
```

## Glyphs

`glyphs` is the set every slot draws from, instead of the shape of its own character: binary for a readout, a few symbols for a glitch.

```angular-html
<p wrDecode glyphs="01">Resolved in 2.4 ms</p>
```

## Timing

`delay` is the pause between the trigger and the first glyph; the text stands as authored meanwhile. `stagger` is the gap between one slot locking and the next, 36 ms unset, and the locks spread over 1.2 s at most. The colour a glyph paints in before it locks is `--wr-decode-tint`, mixed from the text's own colour.

```angular-html
<p wrDecode delay="400" stagger="80">Slow enough to watch each slot lock.</p>
```

```scss
.readout {
  --wr-decode-tint: color-mix(in srgb, var(--wr-color-primary) 50%, transparent);
}
```

## Accessibility

| Part | Behaviour |
| --- | --- |
| Screen readers | While the slots play they are `aria-hidden`, and a visually hidden copy of the text stands beside them, so the text is announced once and the noise never. At rest the element holds its original text nodes. |
| Reduced motion | Under `prefers-reduced-motion: reduce` nothing plays, in either trigger mode: the text is shown as authored. The demos on this page follow the same setting. |
| Keyboard | In `hover` mode focus plays it too, read on the closest focusable ancestor, so a label inside a button or a link behaves the same for a pointer and for Tab. |
| Layout | The real character stays in its slot, hidden, and the glyph is painted over it out of flow, so the line keeps its width and nothing around it moves. |
| Server | The server renders the plain text. The slots are created in the browser, after the first render, and in `view` mode only where `IntersectionObserver` exists. |

## API

| Name | Description | Type | Default |
| --- | --- | --- | --- |
| `trigger` | `view` plays once, the first time most of the host is in the viewport. `hover` plays on every pointer enter and focus of the host or its closest focusable ancestor, but never restarts while already playing. | `WrDecodeTrigger` | `'view'` |
| `glyphs` | The characters random glyphs are drawn from, for every slot. Unset, each slot draws from the shape of its own character: uppercase letters and digits for an uppercase letter, lowercase for lowercase, digits for a digit, a few symbols for anything else. | `string \| null` | `null` |
| `stagger` | Gap between one slot locking and the next, in ms. Unset, 36. Either way the locks spread over 1.2 s at most, so for a long text the gap shrinks until the last slot locks by then. | `number \| null` | `null` |
| `delay` | Pause between the trigger and the first glyph, in ms. The text stands as authored meanwhile. | `number` | `0` |

## 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/decode` declares each default on its own element.

| Variable | Default | Declared on |
| --- | --- | --- |
| `--wr-decode-ease` | `var(--wr-ease-out)` | `.wr-decode` |
| `--wr-decode-settle` | `240ms` | `.wr-decode` and inline on the element, written by the component from its inputs or its state — a rule holds only until the component writes |
| `--wr-decode-tint` | `color-mix(in srgb, currentColor 45%, transparent)` | `.wr-decode` |

## See also

- [Blur Reveal](https://ngwr.dev/animations/blur-reveal) — A text comes in piece by piece the first time it scrolls into view: each word, or each letter, from blurred and a little below its place to sharp and in place.
- [Shimmer](https://ngwr.dev/animations/shimmer) — A soft band of light crosses the glyphs of a short label, waits, and crosses again for as long as the label is on screen.
- [Motion](https://ngwr.dev/guides/tokens/motion) — Easing and duration tokens for your transitions and animations.
- [Badge](https://ngwr.dev/reference/components/badge) — A small label for a count or a status.
