---
title: "Loading: everything has its shape · OpenVibe.Design"
canonical: "https://openvibe.design/loading"
updated: null
---

# Loading: everything has its shape · OpenVibe.Design

HTML: [Loading: everything has its shape · OpenVibe.Design](https://openvibe.design/loading)

Loading

# Everything has its shape. The wait is the mark’s own.

How OpenVibe waits: the page arrives drawn, a list shows its own shape until it fills in, the mark works while a page moves, and a slow load says so. The same parts on every site, from `openvibe-shared`.

## Placeholders shaped like the content

Seven shapes cover the network’s lists. Press **Fill in**: the real content takes the placeholder’s place, and the page says how far everything below it moved.

- **Card**

   

  A video or stream: its 16:9 picture and two lines.

   

  

  

  

  

  

  

  

  

  

    

  `kit.skeleton({ kind: 'card', count: 3 })`
- **Row**

   

  A person or a result: an avatar and two lines.

   

  

  

  

  

  

  

  

  

  

    

  `kit.skeleton({ kind: 'row', count: 3 })`
- **Tile**

   

  A square in a grid: an emote, an icon, a cover.

   

  

  

  

    

  `kit.skeleton({ kind: 'tile', count: 6 })`
- **Chip**

   

  A tag or a filter.

   

  

  

  

    

  `kit.skeleton({ kind: 'chip', count: 6 })`
- **Line**

   

  Text that is on its way.

   

  

  

  

    

  `kit.skeleton({ kind: 'line', count: 3 })`
- **Chat**

   

  A chat message: a dot and a line.

   

  

  

  

  

  

  

  

  

  

    

  `kit.skeleton({ kind: 'chat', count: 3 })`
- **Stat**

   

  A number and what it counts.

   

  

  

  

  

  

  

  

  

  

    

  `kit.skeleton({ kind: 'stat', count: 3 })`

## The mark at work

For a stream or a player that takes a moment: its own picture blurred behind, the V bobbing and the O breathing, one word of status and a line that fills with each step. Slow, it explains; failed, it says what happened.

Press Start

~~~~
const l = OpenVibeLoading.mount(player, { poster, label: 'Connecting', sub: 'Getting your viewer ready', steps: 4 });
l.update({ step: 1, label: 'Joining' });
l.slow({ hint: 'Still connecting', actions: [{ label: 'Try again', onClick: retry }] });
l.fail({ title: 'The stream ended', actions: [{ label: 'Retry', onClick: retry }] });
l.done();
~~~~

## Between pages

While a page or a route loads, the mark in the navbar works and a two-pixel line runs under it; it settles when the page is in. boost.js and the route loaders call it for you; anything else can too.

Look at the mark, top left.

~~~~
OpenVibeNavbar.busy(true);   // the mark works, the line runs
// …the page or route arrives…
OpenVibeNavbar.busy(false);
~~~~

## The rules

What every OpenVibe site does while you wait. Live’s measurements are in [its performance audit](https://openvibe.live/docs/performance-audit).

1. **The page arrives drawn.** Server-rendered HTML with its icons already drawn (no icon font to wait for), and only the CSS the first screen needs before it paints.
2. **A list shows its shape at once.** Its placeholders are in the first HTML, the same size as what replaces them, so filling in moves nothing (each demo above measures it).
3. **A picture sits on its own colour first.** Its dominant colour, or a tiny blurred copy, until it arrives. The first picture asks for itself first (fetchpriority="high"); the rest wait until they are near (loading="lazy").
4. **Moving between pages feels like one app.** The mark works in the navbar with a two-pixel line under it. Links are fetched when pointed at (speculation rules), and the navbar and app bar stay still while the page cross-fades (view transitions).
5. **The wait is the mark’s own.** Its O goes round as dots while it works, three dots rise inside it while an agent thinks, and a line fills when the length is known. Calm plays it slower; only motion off keeps it still.
6. **Slow says so.** After a few seconds a load explains itself and offers what to do. A failure says what happened and offers Retry, never an endless wait.
7. **Off screen costs nothing.** Long lists skip the work for what is not on screen yet (content-visibility: auto).

## Use it

On an OpenVibe site the navbar brings all of it. Anywhere else, the files are free (MIT).

### Placeholders, on the server

~~~~
const kit = require('openvibe-shared/kit');
kit.skeleton({ kind: 'card', count: 6, label: 'Loading streams' });
// card · row · tile · chip · line · chat · stat
~~~~

### The loader, in a page

~~~~
<link rel="stylesheet" href="https://openvibe.design/shared/kit.css">
<script src="https://openvibe.design/shared/loading.js" defer></script>
~~~~

### App-like page moves

~~~~
<script src="https://openvibe.design/shared/boost.js" defer></script>
<meta name="ov-boost" content="mysite@1">
~~~~
