Skip to content

The ligr.gfx.v1 protocol

Your graphic and the LIGR overlay page talk over postMessage. The overlay is the parent window. Your graphic runs in an iframe. Every message in both directions uses one envelope and the protocol name ligr.gfx.v1.

{ "protocol": "ligr.gfx.v1", "sessionId": "cg_…", "seq": 12, "type": "GRAPHIC_UPDATE", "payload": {} }
FieldValue
protocolAlways ligr.gfx.v1
sessionIdThe session the overlay opened for this load of your frame. Copy it from HELLO
seqA counter. Each side keeps its own and increases it by 1 per message
typeThe message type. See the two tables below
payloadThe body of the message. Its shape depends on type

Two rules apply to every message you send.

  • Echo the sessionId. Copy the exact string from the HELLO message into every message you send. The overlay drops a message with a different sessionId.
  • Increase seq. Start your counter at 1 and add 1 on every message. The overlay does not refuse a gap, but it logs a warning for one.

The overlay refuses a message over 1 MB in either direction. It reports the oversize message as a GRAPHIC_ERROR in its own log. Keep externalData and your own payloads small.

The overlay sends HELLO when your frame fires its load event. It repeats HELLO every 250 ms until you answer READY, up to 20 times. A graphic that answers no HELLO within 5 seconds is logged as an error and never loads. Answer the first HELLO you receive. You can also answer every HELLO. The overlay ignores every READY after the first one of a session.

StepDirectionTypePayload
1Overlay → graphicHELLO{ width, height }, the frame size
2Graphic → overlayREADY{ version }, the version of your graphic
3Overlay → graphicLOAD_GRAPHICThe full data payload

From then on, every change arrives as a GRAPHIC_UPDATE.

TypeWhenPayload
HELLOOn frame load, repeated until READY{ width, height }
LOAD_GRAPHICAfter READYEvery surface. See Data binding
GRAPHIC_UPDATEWhen any surface changesgraphicId, show, sport, plus only the surfaces that changed
GRAPHIC_HIDEAn operator, an automation or a REST command hides the graphic{ graphicId }
PINGEvery 10 seconds{}

A GRAPHIC_UPDATE carries only the surfaces whose JSON changed since the previous message. Merge it over the state you hold. A surface that is absent did not change.

If the overlay fails to deliver a LOAD_GRAPHIC, it sends the full load again on the next data change. If it fails to deliver a GRAPHIC_UPDATE, it drops its diff baseline and sends a full LOAD_GRAPHIC on the next data change. Your graphic must render correctly from a LOAD_GRAPHIC at any time, not only the first one.

TypeWhenPayload
READYYou answer HELLO{ version }
HIDDENYour out-animation ends{ graphicId }
PONGYou answer PING{}
ACKOptional, after any command{ ackSeq }, the seq of the message you acknowledge
GRAPHIC_ERRORYour graphic hits a runtime error{ message, stack?, graphicId? }
METRICSOptional{ graphicId, renderTimeMs, frameCount? }

Answer every PING with a PONG. The overlay logs a warning when no PONG arrives within 5 seconds.

  1. The overlay sends GRAPHIC_HIDE.
  2. Your graphic plays its out-animation and sends HIDDEN.
  3. The overlay hides the frame when HIDDEN arrives, or after exitDurationMs from the manifest. The default is 1500 ms.

Two rules govern show and hide.

  • GRAPHIC_HIDE is the only hide trigger. Hide your graphic only when you receive it. Do not hide on any other message.
  • show inside GRAPHIC_UPDATE is informational. There is no separate show message. Treat show: true in a GRAPHIC_UPDATE that arrives after a hide as the signal to show your graphic again.

Always send HIDDEN when your out-animation ends. If you never send it, the overlay hides the frame at the deadline and your animation looks cut off. If your animation is longer than the default deadline, raise exitDurationMs in the manifest.

Post messages to window.parent. Capture event.origin from the first HELLO you receive and use it as the target origin for every later message. Before you know the origin, '*' is accepted.

Your graphic runs in a sandboxed frame with an opaque origin. It cannot read the overlay page. The overlay accepts messages only from your frame. See Bundle rules.

createGraphic from the @ligrsystems/graphics-sdk package implements this listener, with the origin check, the merge of every GRAPHIC_UPDATE, and HIDDEN after your out-animation. Use the listener below when you cannot add a dependency.

protocol.js
const PROTOCOL = 'ligr.gfx.v1'
let sessionId = null
let parentOrigin = '*'
let seq = 0
export function send(type, payload) {
window.parent.postMessage({ protocol: PROTOCOL, sessionId, seq: ++seq, type, payload }, parentOrigin)
}
export function listen(handlers) {
window.addEventListener('message', (event) => {
const msg = event.data
if (!msg || msg.protocol !== PROTOCOL) return
if (msg.type === 'HELLO') {
sessionId = msg.sessionId
parentOrigin = event.origin || '*'
send('READY', { version: '1.0.0' })
return
}
if (msg.sessionId !== sessionId) return
if (msg.type === 'PING') {
send('PONG', {})
return
}
handlers[msg.type]?.(msg.payload)
})
}

handlers maps LOAD_GRAPHIC, GRAPHIC_UPDATE and GRAPHIC_HIDE to your own functions. The Quick start has a full graphic that uses this shape.