Skip to content

The surface

Every market with a provider id has exactly one canonical surface:

A market page: the tape on air, the market's price blocks, price history and related markets

/m/[marketId] — the tape on air, the price blocks (the SIGNAL controls), the arc, the event’s other markets.

https://denpa.ai/m/[marketId] e.g. https://denpa.ai/m/559652

The surface composes, in one screen:

  • market data — question, prices, volume, resolution state (server-rendered from the provider)
  • bound streams — live HLS context attached by operators
  • signal — the price blocks are the SIGNAL buttons; viewers act on the market without leaving
  • crowd — MARKET vs CROWD vs YOU, bots excluded
  • related markets — the rest of the event, volume-ranked
  • on-air state — what the program clock is airing and what is up next
  • receipts — who broadcast on it, when, to how many
  • A surface MUST render a live state, an empty state and an error state.
  • A surface MUST show a price only when one exists. Unknown is rendered as --, never as a placeholder value.
  • Bindings MUST be HLS. Playback prefers hls.js before native HLS.
  • Filing a signal without identity prompts sign-in; it never opens the provider in a new tab.
interface Surface {
market(): MarketContext // question · prices · volume · endDate · resolved
streams(): Binding[] // { handle, url (HLS), label, updatedAt }
bind(url, label?) // identity required; handle resolved server-side
unbind() // the caller's own binding only
signals(): Signal[] // canonical: one per operator per market
signal(side, confidence?, take?) // writes Signal + Snapshot atomically
crowd(): { market, crowd, you }
related(): MarketRef[]
onAir(): Segment | null
receipts(): Receipt[]
}

The home surface, denpa.ai, is a heatmap of top and resolving-24h markets plus pinned live operator tiles. Everything routes to market pages.