Added
Server.Snapshot()— returns latest frame from each connected module. Designed for compositor render tick pattern (Android BufferQueue / Vulkan MAILBOX semantics).Frame.Sequence— monotonic frame counter mapped from wire protocol header, for change detection.- Per-module mailbox — each module's latest frame is stored server-side. Intermediate frames silently overwritten (latest-frame-wins).
Push-based delivery officially supported
Modules can call PublishFrame() at any time without waiting for OnFrameRequest. The server accepts and stores frames unconditionally. Both push and pull patterns coexist on the same connection — no mode negotiation needed.
// Compositor render tick (new pattern):
frames := srv.Snapshot()
for id, frame := range frames {
compositor.Blit(id, frame)
}
// Push module (sends whenever data changes):
client.PublishFrame(compose.Frame{Pixels: rgba, Width: 400, Height: 120})
// Pull module (renders only when asked — unchanged from v0.1.0):
client.OnFrameRequest(func() {
client.PublishFrame(renderClock())
})Architecture
Based on research across 9 production compositors (Wayland, Android SurfaceFlinger, Chromium viz, Flutter, PipeWire, Windows DWM, macOS Core Animation, Vulkan MAILBOX, X11). See ADR-002.
Backward compatible
No wire protocol changes. No handshake changes. OnFrame callback still fires on every receipt. Existing v0.1.0 code works unchanged.