Seen by Dashing: Turning Content Distribution Into a Guided, Error-Proof Flow

Context
Seen runs content across networks of screens — menu boards, promo walls, totems — for schools, retailers and franchises. Every screen is its own media player, with its own orientation, resolution and site.
A distribution is what actually sends content out: which screens, when, what plays, in what layout. It’s also where a mistake stops being an internal problem and starts being visible — on a wall, in a store, in front of customers.
The Problem
Distribution used to live across disconnected modules, and getting a campaign live meant holding the whole configuration — and the right order to do things in — in your head:
- Screens and categories lived in different places, so picking a category meant trusting it held the right screens
- The schedule type quietly decided how many playlists you’d need next, and nothing said so up front
- Playlists, layouts and panels were three separate ideas operators had to stitch together in their head before publishing
- Editing a saved playlist could silently kill playback across sites, with no warning beforehand
The goal: one guided task where each step sets up the next, and nothing touching live screens happens without the operator seeing what it’ll affect first.
The Approach
Four steps, in the order people actually think about them. Each one carries a progress indicator, a one-line explanation of what it decides, and a sticky Back/Next bar — so a long, scrolling form never costs you your place.
- Target — individual screens, or whole categories
- Schedule — reuse a saved one, or build one of six types
- Playlist & Layout — compose layouts and media per daypart
- Review & Submit — one editable summary, then approval
Key Design Decisions
Target screens by what they are, not just where they are. Operators pick individual Screens or whole Categories from the same segmented control, instead of two separate pages. The Screen table puts orientation and resolution right next to each row, because pairing a portrait totem with a 21:9 display is a content decision — not something to discover after it fails. Pick a Category and a side panel shows exactly which screens are inside it before you commit to anything.


Six schedule types, one form that adapts. The step opens with a simple choice: reuse an existing schedule, or build a new one. Most networks repeat the same patterns, so reuse comes first. A single line of helper text ties this step to the next one — it decides how many playlists you’ll need — which the old product never said out loud. Pick a type and the form below adapts: date range, hours, days as chips, and numbered dayparts.
| Type | What it's for |
|---|---|
| Always | Default loop content |
| Take Over | Overrides everything for a period (launches, announcements) |
| Offline | Fallback content when connectivity drops |
| Future | Queued to start on a later date |
| Share of Voice | Guarantees a media item a percentage of airtime |
| After-hours | Content for closed / off-peak hours |

A playlist composer that reads like a timeline. The rule is printed right on the screen: one playlist per schedule slot, and each playlist can hold several layouts that play in sequence. So the hierarchy — daypart, playlist, layouts, panels, media — isn’t buried in a help doc, it’s just how the page is nested. Daypart tabs show a layout count so empty slots are obvious before you move on. Between layouts, a connector line says exactly when it advances to the next one, calculated from the longest panel — one sentence doing the work that used to be a support ticket.

Preview it, then pull media in without leaving the page. Preview loops the layout exactly as it will play on screen — panel split, timing, the lot, with a clear empty state where a panel has nothing in it yet. Add media opens the asset library in a side sheet: filter by type, search, multi-select, drop it straight into a panel. You can also pull in a whole saved playlist instead of picking files one at a time.


One review screen, and every line is editable. Four numbers up top — screens, schedule type, playlist items, total duration — answer "is this roughly right?" before anyone reads a word further down. Every section has an Edit link straight back to its step. And the button says Submit Distribution, not Publish, because this still has to clear approval first.

Deleting a live playlist now tells you what it breaks. A distribution doesn’t end at submit. Before you can delete or edit a playlist that’s already live, the dialog spells out exactly what happens: how many players, sites, and distributions are attached to it, what breaks at the next sync, and a safe default — Keep playlist — sitting right next to the destructive option.
The Distribution Report closes the loop. After submission, this is where you check it actually worked: summary cards for total, online, offline and needs-attention screens, above a table of publish time, schedule time and playback receipts per screen. Clients with nothing published yet get a real empty state instead of a blank table that looks broken.

Design System
Everything is built on the Moon Design System → Seen library. The wizard fed a few patterns back into it:
- Wizard shell — progress header, sticky action bar, current step name
- Choice cards for "existing vs. new" decisions
- Daypart tabs with layout-count badges
- Layout / panel / media-row stack with inline controls
- Impact confirmation dialog — stats, a warning, a safe default
Learnings
- Name the dependency, don’t hide it. One line of helper text — "this decides how many playlists you’ll create" — did more for comprehension than any layout change.
- Make time visible. The hard part in signage isn’t picking content, it’s understanding when it changes. The advance-timing connector and the looping preview were what made the composer click.
- Destructive actions need numbers, not adjectives. "This may affect players" gets ignored. "12 players across 3 sites" gets read.
- Reuse is the real speed feature. Saved schedules and playlists matter more to power users than shaving clicks off the builder itself.