$ signage-as-code
A category, not a product

Your screens
are frontends.
They keep rendering
when you're not looking.

Signage-as-Code is headless and offline-first. Content stays in the systems that already own it — your CRM, your PIM, your calendar, your warehouse. The screen reads, renders, and keeps rendering when the network drops.

deploy.ts
ready

        
lobby-tv
Acme HQ · Reception
This screen reflects the file on the left, live.
The manifesto

Six principles for screens that don't go dark.

Signage drifted into the world of creative tools and never came back. We're putting it back where it belongs — next to your codebase, your CI, your data warehouse, your incident channel.

  1. 01

    The screen reads. It does not store.

    Content lives in the systems that already own it — CRM, PIM, calendar, warehouse. The screen is a render-target, not a destination. If a number changes in your data, it changes on the wall. Once.

  2. 02

    And keeps reading when it can't.

    Network drops are non-events. The player holds a snapshot of the world; the world changing doesn't break the player. Reconnect syncs the diff. A black screen during a fire drill is a bug with an owner.

  3. 03

    Snapshot is the contract.

    Publish writes a complete, self-contained snapshot. Render reads only from snapshots. No live-build fallback, no half-applied changes, no "it worked on the demo unit."

  4. 04

    Composable, not monolithic.

    Pick your data sources. Pick your layouts. Pick your delivery. The vendor doesn't own each layer. The CMS-of-old conflated render and content because it had nowhere else to put them. Today, content already lives somewhere.

  5. 05

    Hardware is replaceable inventory.

    A screen has a name — lobby-tv — not a serial number. Swap the box behind the TV; nothing upstream changes. The file is the asset. The hardware is replaceable.

  6. 06

    API or it doesn't exist.

    A feature you can only do in the dashboard is a feature only one person can do, slowly, while logged in. Every behaviour is automatable, scriptable, observable. From day one. For free.

  7. Boring — on purpose.

    The dramatic part of signage is the content on the glass. The plumbing should be dull, predictable, and ignored. That's the goal.

A consequence of the manifesto

Brand is a source too.

Your marketing site has your brand. Your CRM knows what's happening today. So when twelve locations need to say "Closed today" by 09:00, you don't open a design tool.

await g.comet('lobby-tv', {
  say: 'Closed today.'
})

We read your brand from where it already lives — your site, your logo, your tone. We read "closed today" from where that lives — your calendar, your CRM, your POS. The screen composes the two.

We call this a comet. A short, branded message that lands on a screen without a designer in the loop. It's what headless looks like when your brand is upstream too.

g.bind(...) is for the continuous things — listings, prices, KPIs that stream forever. g.comet(...) is for the one-shot things — today's closure, this morning's incident, the next hour's promo.

Same medium. Two universes.

It's 4:47pm on Friday. The lobby still says "Q3 All-Hands".

The Q4 launch starts in fourteen minutes. The wifi is the wifi. Here's what happens next, in both worlds.

The old way CMS · drag · publish · pray

Open the dashboard. Hope it remembers you.

  1. Log in to the vendor portal
  2. Find the right screen, in the right folder
  3. Open the playlist editor
  4. Upload the new asset (wrong size)
  5. Re-export. Re-upload.
  6. Drag to position 3, before "Coffee Break"
  7. Set start time, set end time
  8. Click Publish
  9. Wifi blips — screen goes black
  10. Lobby still showing Q3 All-Hands
Time38 min
Clicks47
Single points of failure4
The new way read · render · survive the wifi

A comet. A sentence. Done before the coffee is.

  1. Send a comet: say: 'Q4 launch · 17:00'
  2. Brand picked up from your marketing site
  3. Wifi blips — screen keeps rendering the last snapshot
  4. Wifi back — new snapshot syncs
  5. Lobby shows Q4 launch
Time90 sec
Lines of code3
Single points of failure0
The architecture, in one diagram

Two phases. Three layers. One contract.

Your systems
CRM · PIM · calendar · warehouse · marketing site (for brand)
publish
Snapshot
A complete, self-contained description of what every screen should be playing right now
render
Screens
Read-only. Cached locally. Survive the network. 5-year lifetime.
  • Publish is a write. Render is a read.

    The two phases never talk directly. Publish writes a snapshot. Render reads a snapshot. No live-build fallback path; the absence of a snapshot is a 503 with a fixable message, not a silent half-render.

  • The snapshot is the boundary.

    On one side: your messy, evolving systems-of-record. On the other: deterministic playback for years. The snapshot is what makes signage durable.

  • Failure is a declared route.

    on_error: fallback-loop. alert: #screens-pagerduty. A screen has owners, escalation paths, and a known last good state. Signage stops being a special case and joins the rest of production.

Objections, handled

"Wait, isn't this just…"

Yes — plus offline-first. A regular headless CMS assumes the client can call back to the API. A lobby TV in a basement on hotel wifi cannot make that assumption. Headless gets you the architecture; offline-first is what makes it survive the medium.

A one-shot, branded message that lands on one or many screens without a designer in the loop. You write the sentence; the system reads your brand from upstream (your marketing site, your logo, your tone) and renders the scene. It's the natural consequence of treating brand as just another upstream source.

No. Marketers change content where they already do — the CRM, the PIM, the campaign tool. Signage-as-Code is the pipe between those systems and the glass. The people who maintain the pipe are the same people who maintain your website, your CI, your integration layer.

You still do. Every change renders a preview of every affected screen, at the right resolution and orientation. You approve a snapshot. You publish. The wall changes. WYSIWYG without the YG being a single point of failure.

The medium has a long tail. A reception screen lives longer than the team that installed it, the laptop that configured it, and the vendor that sold it. The architecture has to match the medium — deterministic snapshots, replaceable hardware, named screens, owned failures.

The category is new; the practice isn't. Teams have been gluing playlists, cron jobs, and integration scripts together for years. Signage-as-Code names the pattern. The reference implementation — the one this site is maintained by — is Gibeon. Others are welcome.

Three steps. (1) Sign up free at gibeon.io — the reference implementation. (2) Install the SDK: npm install @gibeon/sdk. (3) Bind a screen to a source: g.bind('lobby-tv', { source: yourCRM.listings }). The screen reads, renders, and keeps rendering when the network drops. No dashboard, no playlist editor, no upload step.

A comet: g.comet('lobby-tv', { say: 'Closed today.' }). One sentence, one line. The system reads your brand from upstream (your marketing site, your logo, your tone) and renders the scene. No design tool, no upload, no scheduling. You write what should be on the wall — it appears.

Start in 90 seconds

Free. Three lines. Your screen works.

The manifesto is free. The category is open. The reference implementation is one signup away — no credit card, no onboarding call, no “contact sales”.

  1. 01

    Sign up free at gibeon.io

    The reference implementation. Free tier. No card. Get your SDK token.

  2. 02

    Install the SDK

    npm install @gibeon/sdk
  3. 03

    Bind a screen — or send a comet

    import { Gibeon } from '@gibeon/sdk'
    const g = new Gibeon({ token: process.env.GIBEON_TOKEN })
    
    // continuous: source streams forever
    await g.bind('lobby-tv', { source: yourCRM.listings })
    
    // one-shot: branded message, no design tool
    await g.comet('lobby-tv', { say: 'Closed today.' })

That’s it. Coder, AI agent, or human at a keyboard — no thinking required. The plumbing should be dull, predictable, and ignored.

Treat your screens like frontends.

Headless. Offline-first. Boring on purpose. The manifesto is free. The category is open.