[{"data":1,"prerenderedAt":1992},["ShallowReactive",2],{"content-en-\u002Ffeatures\u002Fmulti-display":3},{"id":4,"title":5,"author":6,"body":7,"date":6,"description":1985,"extension":1986,"meta":1987,"navigation":1053,"path":1988,"seo":1989,"stem":1990,"tags":6,"__hash__":1991},"content_en\u002Ffeatures\u002Fmulti-display.md","Multi-Display Sync",null,{"type":8,"value":9,"toc":1964},"minimark",[10,14,23,28,33,40,43,54,58,65,68,74,84,272,275,280,309,313,319,322,326,387,394,398,405,411,434,440,444,450,477,481,485,488,492,500,581,592,600,666,669,673,679,723,729,820,825,917,922,1014,1017,1021,1024,1072,1075,1087,1090,1094,1101,1107,1111,1208,1212,1215,1349,1357,1363,1368,1518,1522,1793,1796,1800,1803,1833,1836,1953,1960],[11,12,5],"h1",{"id":13},"multi-display-sync",[15,16,17,18,22],"p",{},"XiboPlayer is the ",[19,20,21],"strong",{},"only Xibo player with cross-device synchronization",". Multiple screens — same machine or across a LAN — stay in perfect sync: coordinated layout transitions, synchronized video start, and automatic follower discovery.",[24,25,27],"h2",{"id":26},"two-sync-modes","Two Sync Modes",[29,30,32],"h3",{"id":31},"mirror-mode-default","Mirror Mode (default)",[15,34,35,36,39],{},"All displays show the ",[19,37,38],{},"same layout"," at the same time. The lead decides which layout to show and all followers load the same content.",[15,41,42],{},"Use case: multiple screens in a lobby, retail store, or airport — all showing identical content with perfectly synchronized transitions.",[44,45,50],"pre",{"className":46,"code":48,"language":49},[47],"language-text","Lead shows layout 42 ──→ Follower 1 shows layout 42\n                     ──→ Follower 2 shows layout 42\n                     ──→ Follower 3 shows layout 42\n","text",[51,52,48],"code",{"__ignoreMap":53},"",[29,55,57],{"id":56},"wall-mode-with-layoutmap","Wall Mode (with layoutMap)",[15,59,60,61,64],{},"Each display shows a ",[19,62,63],{},"different layout"," per position, but transitions are coordinated by the lead. This is how you build a video wall where each screen shows a portion of a larger composition.",[15,66,67],{},"You design individual layouts for each screen position in the CMS, then map them in the follower's config:",[44,69,72],{"className":70,"code":71,"language":49},[47],"Lead shows layout 42 ──→ Follower 1 maps 42 → 101 (top-right)\n                     ──→ Follower 2 maps 42 → 102 (bottom-left)\n                     ──→ Follower 3 maps 42 → 103 (bottom-right)\n",[51,73,71],{"__ignoreMap":53},[15,75,76,79,80,83],{},[19,77,78],{},"Follower config.json"," (",[51,81,82],{},"sync.layoutMap","):",[44,85,89],{"className":86,"code":87,"language":88,"meta":53,"style":53},"language-json shiki shiki-themes material-theme-lighter github-light github-dark","{\n  \"cmsUrl\": \"https:\u002F\u002Fcms.example.com\",\n  \"cmsKey\": \"yourKey\",\n  \"displayName\": \"lobby-top-right\",\n  \"sync\": {\n    \"layoutMap\": {\n      \"42\": 101,\n      \"43\": 105,\n      \"44\": 109\n    }\n  }\n}\n","json",[51,90,91,100,130,151,172,187,203,222,239,254,260,266],{"__ignoreMap":53},[92,93,96],"span",{"class":94,"line":95},"line",1,[92,97,99],{"class":98},"sP7_E","{\n",[92,101,103,107,111,114,117,121,125,127],{"class":94,"line":102},2,[92,104,106],{"class":105},"s39Yj","  \"",[92,108,110],{"class":109},"sseR_","cmsUrl",[92,112,113],{"class":105},"\"",[92,115,116],{"class":98},":",[92,118,120],{"class":119},"sjJ54"," \"",[92,122,124],{"class":123},"s_sjI","https:\u002F\u002Fcms.example.com",[92,126,113],{"class":119},[92,128,129],{"class":98},",\n",[92,131,133,135,138,140,142,144,147,149],{"class":94,"line":132},3,[92,134,106],{"class":105},[92,136,137],{"class":109},"cmsKey",[92,139,113],{"class":105},[92,141,116],{"class":98},[92,143,120],{"class":119},[92,145,146],{"class":123},"yourKey",[92,148,113],{"class":119},[92,150,129],{"class":98},[92,152,154,156,159,161,163,165,168,170],{"class":94,"line":153},4,[92,155,106],{"class":105},[92,157,158],{"class":109},"displayName",[92,160,113],{"class":105},[92,162,116],{"class":98},[92,164,120],{"class":119},[92,166,167],{"class":123},"lobby-top-right",[92,169,113],{"class":119},[92,171,129],{"class":98},[92,173,175,177,180,182,184],{"class":94,"line":174},5,[92,176,106],{"class":105},[92,178,179],{"class":109},"sync",[92,181,113],{"class":105},[92,183,116],{"class":98},[92,185,186],{"class":98}," {\n",[92,188,190,193,197,199,201],{"class":94,"line":189},6,[92,191,192],{"class":105},"    \"",[92,194,196],{"class":195},"sZMiF","layoutMap",[92,198,113],{"class":105},[92,200,116],{"class":98},[92,202,186],{"class":98},[92,204,206,209,213,215,217,220],{"class":94,"line":205},7,[92,207,208],{"class":105},"      \"",[92,210,212],{"class":211},"srdBf","42",[92,214,113],{"class":105},[92,216,116],{"class":98},[92,218,219],{"class":211}," 101",[92,221,129],{"class":98},[92,223,225,227,230,232,234,237],{"class":94,"line":224},8,[92,226,208],{"class":105},[92,228,229],{"class":211},"43",[92,231,113],{"class":105},[92,233,116],{"class":98},[92,235,236],{"class":211}," 105",[92,238,129],{"class":98},[92,240,242,244,247,249,251],{"class":94,"line":241},9,[92,243,208],{"class":105},[92,245,246],{"class":211},"44",[92,248,113],{"class":105},[92,250,116],{"class":98},[92,252,253],{"class":211}," 109\n",[92,255,257],{"class":94,"line":256},10,[92,258,259],{"class":98},"    }\n",[92,261,263],{"class":94,"line":262},11,[92,264,265],{"class":98},"  }\n",[92,267,269],{"class":94,"line":268},12,[92,270,271],{"class":98},"}\n",[15,273,274],{},"Each key is the lead's layout ID, each value is this display's corresponding layout ID. If a layout isn't in the map, the display falls back to mirror mode for that layout.",[15,276,277],{},[19,278,279],{},"How to set up a video wall:",[281,282,283,287,290,297,306],"ol",{},[284,285,286],"li",{},"In the CMS, design N layouts (one per screen position) — e.g., layout 42 (lead\u002Ftop-left), 101 (top-right), 102 (bottom-left), 103 (bottom-right)",[284,288,289],{},"Schedule layout 42 on the lead — it drives the timing",[284,291,292,293,296],{},"Schedule layouts 101, 102, 103 on followers so they're downloaded (or rely on the lead's schedule to push them via ",[51,294,295],{},"RequiredFiles",")",[284,298,299,300,302,303],{},"Add ",[51,301,82],{}," to each follower's ",[51,304,305],{},"config.json",[284,307,308],{},"All screens transition at the same moment, each showing its position-specific content",[24,310,312],{"id":311},"how-it-works","How It Works",[44,314,317],{"className":315,"code":316,"language":49},[47],"                    Lead Player (Screen 1)\n                    ┌────────────────────────┐\n                    │  SyncManager (lead)     │\n                    │  ┌──────────────────┐   │\n                    │  │  Proxy Server    │   │\n                    │  │  ┌────────────┐  │   │\n                    │  │  │ Sync Relay │  │   │\n                    │  │  │  \u002Fsync WS  │  │   │\n                    │  │  └─────┬──────┘  │   │\n                    │  └────────┼──────────┘   │\n                    └───────────┼──────────────┘\n                                │\n              ┌─────────────────┼─────────────────┐\n              │ WebSocket       │ WebSocket        │ WebSocket\n              ▼                 ▼                  ▼\n    ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐\n    │  Follower 1     │ │  Follower 2     │ │  Follower 3     │\n    │  (Screen 2)     │ │  (Screen 3)     │ │  (Screen 4)     │\n    │  SyncManager    │ │  SyncManager    │ │  SyncManager    │\n    └─────────────────┘ └─────────────────┘ └─────────────────┘\n",[51,318,316],{"__ignoreMap":53},[15,320,321],{},"The lead player orchestrates layout transitions. Its proxy server includes a built-in WebSocket relay — followers connect to it over the LAN, no additional infrastructure needed.",[24,323,325],{"id":324},"two-transport-layers","Two Transport Layers",[327,328,329,348],"table",{},[330,331,332],"thead",{},[333,334,335,339,342,345],"tr",{},[336,337,338],"th",{},"Transport",[336,340,341],{},"Scope",[336,343,344],{},"Use Case",[336,346,347],{},"How",[349,350,351,368],"tbody",{},[333,352,353,359,362,365],{},[354,355,356],"td",{},[19,357,358],{},"BroadcastChannel",[354,360,361],{},"Same machine",[354,363,364],{},"Multiple tabs or windows on one device",[354,366,367],{},"Browser-native API, zero config",[333,369,370,375,378,381],{},[354,371,372],{},[19,373,374],{},"WebSocket relay",[354,376,377],{},"Cross-device LAN",[354,379,380],{},"Separate devices on the same network",[354,382,383,384],{},"Connects to lead's proxy at ",[51,385,386],{},"\u002Fsync",[15,388,389,390,393],{},"The transport is auto-selected based on configuration. If ",[51,391,392],{},"relayUrl"," is set, WebSocket is used; otherwise BroadcastChannel.",[24,395,397],{"id":396},"group-isolation","Group Isolation",[15,399,400,401,404],{},"When multiple display groups share the same relay server, ",[19,402,403],{},"group isolation"," ensures messages stay within their group. Each display declares its sync group on connect, and the relay only broadcasts to peers in the same group.",[44,406,409],{"className":407,"code":408,"language":49},[47],"Relay Server (port 9590)\n├── Group \"lobby\"\n│   ├── lobby-lead (Screen 1)\n│   ├── lobby-left (Screen 2)\n│   └── lobby-right (Screen 3)\n│\n└── Group \"cafeteria\"\n    ├── cafe-lead (Screen 4)\n    └── cafe-right (Screen 5)\n",[51,410,408],{"__ignoreMap":53},[15,412,413,414,417,418,421,422,425,426,429,430,433],{},"A layout change on ",[51,415,416],{},"lobby-lead"," reaches ",[51,419,420],{},"lobby-left"," and ",[51,423,424],{},"lobby-right"," but never ",[51,427,428],{},"cafe-lead"," or ",[51,431,432],{},"cafe-right",".",[15,435,436,439],{},[19,437,438],{},"Backward compatible:"," Displays that don't declare a group fall back to broadcast-to-all behavior.",[24,441,443],{"id":442},"sync-protocol","Sync Protocol",[44,445,448],{"className":446,"code":447,"language":49},[47],"Lead                              Follower(s)\n────                              ──────────\nlayout-change(layoutId, showAt)  →  receives, loads layout (or mapped layout)\n                                 ←  layout-ready(layoutId, displayId)\n(waits for all followers ready)\nlayout-show(layoutId)            →  shows layout simultaneously\nvideo-start(layoutId, regionId)  →  unpauses video simultaneously\n",[51,449,447],{"__ignoreMap":53},[451,452,453,459,465,471],"ul",{},[284,454,455,458],{},[19,456,457],{},"Heartbeat",": every 5s, each node broadcasts its presence. The lead tracks active followers.",[284,460,461,464],{},[19,462,463],{},"Stale detection",": if a follower goes silent for 15s, it's excluded from the ready-wait.",[284,466,467,470],{},[19,468,469],{},"Ready timeout",": the lead waits up to 10s for followers, then proceeds without unresponsive ones.",[284,472,473,476],{},[19,474,475],{},"Stats delegation",": followers send their stats\u002Flogs to the lead, which submits them to the CMS on their behalf.",[24,478,480],{"id":479},"configuration-examples","Configuration Examples",[29,482,484],{"id":483},"same-machine-sync-two-tabs","Same-machine sync (two tabs)",[15,486,487],{},"No special config needed. Open the player in two browser tabs — BroadcastChannel handles sync automatically. Both tabs show the same content (mirror mode).",[29,489,491],{"id":490},"cross-device-mirrored-displays-3-screens-on-lan","Cross-device mirrored displays (3 screens on LAN)",[15,493,494,79,497,499],{},[19,495,496],{},"Lead player",[51,498,305],{}," on 192.168.1.100):",[44,501,503],{"className":86,"code":502,"language":88,"meta":53,"style":53},"{\n  \"cmsUrl\": \"https:\u002F\u002Fcms.example.com\",\n  \"cmsKey\": \"yourKey\",\n  \"displayName\": \"lobby-lead\",\n  \"serverPort\": 8765\n}\n",[51,504,505,509,527,545,563,577],{"__ignoreMap":53},[92,506,507],{"class":94,"line":95},[92,508,99],{"class":98},[92,510,511,513,515,517,519,521,523,525],{"class":94,"line":102},[92,512,106],{"class":105},[92,514,110],{"class":109},[92,516,113],{"class":105},[92,518,116],{"class":98},[92,520,120],{"class":119},[92,522,124],{"class":123},[92,524,113],{"class":119},[92,526,129],{"class":98},[92,528,529,531,533,535,537,539,541,543],{"class":94,"line":132},[92,530,106],{"class":105},[92,532,137],{"class":109},[92,534,113],{"class":105},[92,536,116],{"class":98},[92,538,120],{"class":119},[92,540,146],{"class":123},[92,542,113],{"class":119},[92,544,129],{"class":98},[92,546,547,549,551,553,555,557,559,561],{"class":94,"line":153},[92,548,106],{"class":105},[92,550,158],{"class":109},[92,552,113],{"class":105},[92,554,116],{"class":98},[92,556,120],{"class":119},[92,558,416],{"class":123},[92,560,113],{"class":119},[92,562,129],{"class":98},[92,564,565,567,570,572,574],{"class":94,"line":174},[92,566,106],{"class":105},[92,568,569],{"class":109},"serverPort",[92,571,113],{"class":105},[92,573,116],{"class":98},[92,575,576],{"class":211}," 8765\n",[92,578,579],{"class":94,"line":189},[92,580,271],{"class":98},[15,582,583,584,587,588,591],{},"The lead's sync group is set by the CMS via ",[51,585,586],{},"RegisterDisplay",". The proxy server at ",[51,589,590],{},":8765\u002Fsync"," acts as the relay.",[15,593,594,79,597,599],{},[19,595,596],{},"Follower 1",[51,598,305],{}," on 192.168.1.101):",[44,601,603],{"className":86,"code":602,"language":88,"meta":53,"style":53},"{\n  \"cmsUrl\": \"https:\u002F\u002Fcms.example.com\",\n  \"cmsKey\": \"yourKey\",\n  \"displayName\": \"lobby-left\"\n}\n",[51,604,605,609,627,645,662],{"__ignoreMap":53},[92,606,607],{"class":94,"line":95},[92,608,99],{"class":98},[92,610,611,613,615,617,619,621,623,625],{"class":94,"line":102},[92,612,106],{"class":105},[92,614,110],{"class":109},[92,616,113],{"class":105},[92,618,116],{"class":98},[92,620,120],{"class":119},[92,622,124],{"class":123},[92,624,113],{"class":119},[92,626,129],{"class":98},[92,628,629,631,633,635,637,639,641,643],{"class":94,"line":132},[92,630,106],{"class":105},[92,632,137],{"class":109},[92,634,113],{"class":105},[92,636,116],{"class":98},[92,638,120],{"class":119},[92,640,146],{"class":123},[92,642,113],{"class":119},[92,644,129],{"class":98},[92,646,647,649,651,653,655,657,659],{"class":94,"line":153},[92,648,106],{"class":105},[92,650,158],{"class":109},[92,652,113],{"class":105},[92,654,116],{"class":98},[92,656,120],{"class":119},[92,658,420],{"class":123},[92,660,661],{"class":119},"\"\n",[92,663,664],{"class":94,"line":174},[92,665,271],{"class":98},[15,667,668],{},"All three screens show the same content with synchronized transitions.",[29,670,672],{"id":671},"video-wall-2x2-grid-position-specific-content","Video wall (2x2 grid, position-specific content)",[15,674,675,678],{},[19,676,677],{},"Lead (top-left)"," — normal config, runs the schedule:",[44,680,682],{"className":86,"code":681,"language":88,"meta":53,"style":53},"{\n  \"displayName\": \"wall-top-left\",\n  \"serverPort\": 8765\n}\n",[51,683,684,688,707,719],{"__ignoreMap":53},[92,685,686],{"class":94,"line":95},[92,687,99],{"class":98},[92,689,690,692,694,696,698,700,703,705],{"class":94,"line":102},[92,691,106],{"class":105},[92,693,158],{"class":109},[92,695,113],{"class":105},[92,697,116],{"class":98},[92,699,120],{"class":119},[92,701,702],{"class":123},"wall-top-left",[92,704,113],{"class":119},[92,706,129],{"class":98},[92,708,709,711,713,715,717],{"class":94,"line":132},[92,710,106],{"class":105},[92,712,569],{"class":109},[92,714,113],{"class":105},[92,716,116],{"class":98},[92,718,576],{"class":211},[92,720,721],{"class":94,"line":153},[92,722,271],{"class":98},[15,724,725,728],{},[19,726,727],{},"Follower (top-right)"," — maps lead layouts to its position:",[44,730,732],{"className":86,"code":731,"language":88,"meta":53,"style":53},"{\n  \"displayName\": \"wall-top-right\",\n  \"sync\": {\n    \"layoutMap\": {\n      \"42\": 101,\n      \"43\": 105\n    }\n  }\n}\n",[51,733,734,738,757,769,781,795,808,812,816],{"__ignoreMap":53},[92,735,736],{"class":94,"line":95},[92,737,99],{"class":98},[92,739,740,742,744,746,748,750,753,755],{"class":94,"line":102},[92,741,106],{"class":105},[92,743,158],{"class":109},[92,745,113],{"class":105},[92,747,116],{"class":98},[92,749,120],{"class":119},[92,751,752],{"class":123},"wall-top-right",[92,754,113],{"class":119},[92,756,129],{"class":98},[92,758,759,761,763,765,767],{"class":94,"line":132},[92,760,106],{"class":105},[92,762,179],{"class":109},[92,764,113],{"class":105},[92,766,116],{"class":98},[92,768,186],{"class":98},[92,770,771,773,775,777,779],{"class":94,"line":153},[92,772,192],{"class":105},[92,774,196],{"class":195},[92,776,113],{"class":105},[92,778,116],{"class":98},[92,780,186],{"class":98},[92,782,783,785,787,789,791,793],{"class":94,"line":174},[92,784,208],{"class":105},[92,786,212],{"class":211},[92,788,113],{"class":105},[92,790,116],{"class":98},[92,792,219],{"class":211},[92,794,129],{"class":98},[92,796,797,799,801,803,805],{"class":94,"line":189},[92,798,208],{"class":105},[92,800,229],{"class":211},[92,802,113],{"class":105},[92,804,116],{"class":98},[92,806,807],{"class":211}," 105\n",[92,809,810],{"class":94,"line":205},[92,811,259],{"class":98},[92,813,814],{"class":94,"line":224},[92,815,265],{"class":98},[92,817,818],{"class":94,"line":241},[92,819,271],{"class":98},[15,821,822,116],{},[19,823,824],{},"Follower (bottom-left)",[44,826,828],{"className":86,"code":827,"language":88,"meta":53,"style":53},"{\n  \"displayName\": \"wall-bottom-left\",\n  \"sync\": {\n    \"layoutMap\": {\n      \"42\": 102,\n      \"43\": 106\n    }\n  }\n}\n",[51,829,830,834,853,865,877,892,905,909,913],{"__ignoreMap":53},[92,831,832],{"class":94,"line":95},[92,833,99],{"class":98},[92,835,836,838,840,842,844,846,849,851],{"class":94,"line":102},[92,837,106],{"class":105},[92,839,158],{"class":109},[92,841,113],{"class":105},[92,843,116],{"class":98},[92,845,120],{"class":119},[92,847,848],{"class":123},"wall-bottom-left",[92,850,113],{"class":119},[92,852,129],{"class":98},[92,854,855,857,859,861,863],{"class":94,"line":132},[92,856,106],{"class":105},[92,858,179],{"class":109},[92,860,113],{"class":105},[92,862,116],{"class":98},[92,864,186],{"class":98},[92,866,867,869,871,873,875],{"class":94,"line":153},[92,868,192],{"class":105},[92,870,196],{"class":195},[92,872,113],{"class":105},[92,874,116],{"class":98},[92,876,186],{"class":98},[92,878,879,881,883,885,887,890],{"class":94,"line":174},[92,880,208],{"class":105},[92,882,212],{"class":211},[92,884,113],{"class":105},[92,886,116],{"class":98},[92,888,889],{"class":211}," 102",[92,891,129],{"class":98},[92,893,894,896,898,900,902],{"class":94,"line":189},[92,895,208],{"class":105},[92,897,229],{"class":211},[92,899,113],{"class":105},[92,901,116],{"class":98},[92,903,904],{"class":211}," 106\n",[92,906,907],{"class":94,"line":205},[92,908,259],{"class":98},[92,910,911],{"class":94,"line":224},[92,912,265],{"class":98},[92,914,915],{"class":94,"line":241},[92,916,271],{"class":98},[15,918,919,116],{},[19,920,921],{},"Follower (bottom-right)",[44,923,925],{"className":86,"code":924,"language":88,"meta":53,"style":53},"{\n  \"displayName\": \"wall-bottom-right\",\n  \"sync\": {\n    \"layoutMap\": {\n      \"42\": 103,\n      \"43\": 107\n    }\n  }\n}\n",[51,926,927,931,950,962,974,989,1002,1006,1010],{"__ignoreMap":53},[92,928,929],{"class":94,"line":95},[92,930,99],{"class":98},[92,932,933,935,937,939,941,943,946,948],{"class":94,"line":102},[92,934,106],{"class":105},[92,936,158],{"class":109},[92,938,113],{"class":105},[92,940,116],{"class":98},[92,942,120],{"class":119},[92,944,945],{"class":123},"wall-bottom-right",[92,947,113],{"class":119},[92,949,129],{"class":98},[92,951,952,954,956,958,960],{"class":94,"line":132},[92,953,106],{"class":105},[92,955,179],{"class":109},[92,957,113],{"class":105},[92,959,116],{"class":98},[92,961,186],{"class":98},[92,963,964,966,968,970,972],{"class":94,"line":153},[92,965,192],{"class":105},[92,967,196],{"class":195},[92,969,113],{"class":105},[92,971,116],{"class":98},[92,973,186],{"class":98},[92,975,976,978,980,982,984,987],{"class":94,"line":174},[92,977,208],{"class":105},[92,979,212],{"class":211},[92,981,113],{"class":105},[92,983,116],{"class":98},[92,985,986],{"class":211}," 103",[92,988,129],{"class":98},[92,990,991,993,995,997,999],{"class":94,"line":189},[92,992,208],{"class":105},[92,994,229],{"class":211},[92,996,113],{"class":105},[92,998,116],{"class":98},[92,1000,1001],{"class":211}," 107\n",[92,1003,1004],{"class":94,"line":205},[92,1005,259],{"class":98},[92,1007,1008],{"class":94,"line":224},[92,1009,265],{"class":98},[92,1011,1012],{"class":94,"line":241},[92,1013,271],{"class":98},[15,1015,1016],{},"When the lead transitions from layout 42 to layout 43, all four screens transition simultaneously — each to its own position-specific layout.",[29,1018,1020],{"id":1019},"standalone-relay-server","Standalone relay server",[15,1022,1023],{},"For large deployments, run a dedicated relay instead of using the lead's proxy:",[44,1025,1029],{"className":1026,"code":1027,"language":1028,"meta":53,"style":53},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark","# Install\nnpm install @xiboplayer\u002Fproxy\n\n# Run standalone relay\nnpx xiboplayer-relay --port=9590\n","bash",[51,1030,1031,1037,1049,1055,1060],{"__ignoreMap":53},[92,1032,1033],{"class":94,"line":95},[92,1034,1036],{"class":1035},"sutJx","# Install\n",[92,1038,1039,1043,1046],{"class":94,"line":102},[92,1040,1042],{"class":1041},"sbgvK","npm",[92,1044,1045],{"class":123}," install",[92,1047,1048],{"class":123}," @xiboplayer\u002Fproxy\n",[92,1050,1051],{"class":94,"line":132},[92,1052,1054],{"emptyLinePlaceholder":1053},true,"\n",[92,1056,1057],{"class":94,"line":153},[92,1058,1059],{"class":1035},"# Run standalone relay\n",[92,1061,1062,1065,1068],{"class":94,"line":174},[92,1063,1064],{"class":1041},"npx",[92,1066,1067],{"class":123}," xiboplayer-relay",[92,1069,1071],{"class":1070},"stzsN"," --port=9590\n",[15,1073,1074],{},"Or with the RPM package:",[44,1076,1078],{"className":1026,"code":1077,"language":1028,"meta":53,"style":53},"xiboplayer-relay --port=9590\n",[51,1079,1080],{"__ignoreMap":53},[92,1081,1082,1085],{"class":94,"line":95},[92,1083,1084],{"class":1041},"xiboplayer-relay",[92,1086,1071],{"class":1070},[15,1088,1089],{},"The relay is a lightweight WebSocket hub (~100 lines) with no CMS dependency. It handles group isolation, heartbeat monitoring, and stale client cleanup.",[29,1091,1093],{"id":1092},"multiple-display-groups-one-relay","Multiple display groups, one relay",[15,1095,1096,1097,1100],{},"Configure each group's displays with the same ",[51,1098,1099],{},"syncGroup"," in the CMS. The relay isolates messages by group automatically:",[44,1102,1105],{"className":1103,"code":1104,"language":49},[47],"Group \"lobby\"    → syncGroup: \"lobby\"    → relay at relay.lan:9590\nGroup \"cafeteria\"→ syncGroup: \"cafeteria\"→ relay at relay.lan:9590\n",[51,1106,1104],{"__ignoreMap":53},[24,1108,1110],{"id":1109},"features","Features",[451,1112,1113,1119,1127,1133,1139,1145,1151,1157,1163,1168,1178,1184,1190,1196,1202],{},[284,1114,1115,1118],{},[19,1116,1117],{},"Mirror mode"," — all screens show the same layout (default)",[284,1120,1121,1124,1125],{},[19,1122,1123],{},"Wall mode"," — each screen shows a position-specific layout via ",[51,1126,196],{},[284,1128,1129,1132],{},[19,1130,1131],{},"Coordinated layout transitions"," — all screens change layout simultaneously",[284,1134,1135,1138],{},[19,1136,1137],{},"\u003C8ms sync precision"," — measured across 4 Chromium displays on LAN",[284,1140,1141,1144],{},[19,1142,1143],{},"12 choreography effects"," — dramatic cascading transitions across the wall (v0.7.0)",[284,1146,1147,1150],{},[19,1148,1149],{},"Token-authenticated relay"," — shared CMS key secures WebSocket connections (v0.7.0)",[284,1152,1153,1156],{},[19,1154,1155],{},"Synchronized video start"," — videos unpause at the same moment across all screens",[284,1158,1159,1162],{},[19,1160,1161],{},"Automatic follower discovery"," — heartbeat-based, no manual registration",[284,1164,1165,1167],{},[19,1166,475],{}," — followers route stats\u002Flogs through the lead to the CMS",[284,1169,1170,1173,1174,1177],{},[19,1171,1172],{},"Group isolation"," — multiple display groups share one relay via ",[51,1175,1176],{},"syncGroupId"," (v0.7.0)",[284,1179,1180,1183],{},[19,1181,1182],{},"Offline LAN sync"," — persisted config enables sync without CMS connectivity (v0.7.0)",[284,1185,1186,1189],{},[19,1187,1188],{},"Auto-reconnect"," — exponential backoff (1s to 30s) with automatic group re-join",[284,1191,1192,1195],{},[19,1193,1194],{},"Graceful degradation"," — lead proceeds after timeout if a follower is unresponsive",[284,1197,1198,1201],{},[19,1199,1200],{},"Transport-agnostic"," — same SyncManager API for BroadcastChannel and WebSocket",[284,1203,1204,1207],{},[19,1205,1206],{},"Works on Electron and Chromium"," — both kiosk platforms fully tested (v0.7.0)",[24,1209,1211],{"id":1210},"choreography-effects-v070","Choreography Effects (v0.7.0)",[15,1213,1214],{},"When displays transition between layouts, choreography controls the cascade pattern. Each display shows the new layout at a staggered time based on its grid position.",[327,1216,1217,1227],{},[330,1218,1219],{},[333,1220,1221,1224],{},[336,1222,1223],{},"Effect",[336,1225,1226],{},"Description",[349,1228,1229,1239,1249,1259,1269,1279,1289,1299,1309,1319,1329,1339],{},[333,1230,1231,1236],{},[354,1232,1233],{},[51,1234,1235],{},"simultaneous",[354,1237,1238],{},"All displays switch at once (no stagger)",[333,1240,1241,1246],{},[354,1242,1243],{},[51,1244,1245],{},"wave-right",[354,1247,1248],{},"Sweep left → right",[333,1250,1251,1256],{},[354,1252,1253],{},[51,1254,1255],{},"wave-left",[354,1257,1258],{},"Sweep right → left",[333,1260,1261,1266],{},[354,1262,1263],{},[51,1264,1265],{},"wave-down",[354,1267,1268],{},"Sweep top → bottom",[333,1270,1271,1276],{},[354,1272,1273],{},[51,1274,1275],{},"wave-up",[354,1277,1278],{},"Sweep bottom → top",[333,1280,1281,1286],{},[354,1282,1283],{},[51,1284,1285],{},"diagonal-tl",[354,1287,1288],{},"Cascade from top-left corner",[333,1290,1291,1296],{},[354,1292,1293],{},[51,1294,1295],{},"diagonal-tr",[354,1297,1298],{},"Cascade from top-right corner",[333,1300,1301,1306],{},[354,1302,1303],{},[51,1304,1305],{},"diagonal-bl",[354,1307,1308],{},"Cascade from bottom-left corner",[333,1310,1311,1316],{},[354,1312,1313],{},[51,1314,1315],{},"diagonal-br",[354,1317,1318],{},"Cascade from bottom-right corner",[333,1320,1321,1326],{},[354,1322,1323],{},[51,1324,1325],{},"center-out",[354,1327,1328],{},"Center displays first, edges last",[333,1330,1331,1336],{},[354,1332,1333],{},[51,1334,1335],{},"outside-in",[354,1337,1338],{},"Edges first, center last",[333,1340,1341,1346],{},[354,1342,1343],{},[51,1344,1345],{},"random",[354,1347,1348],{},"Random delay per display",[15,1350,1351],{},[19,1352,1353,1354,1356],{},"Example: 2×2 grid with ",[51,1355,1285],{}," at 200ms stagger:",[44,1358,1361],{"className":1359,"code":1360,"language":49},[47],"┌──────┬──────┐\n│ 0ms  │200ms │\n├──────┼──────┤\n│200ms │400ms │\n└──────┴──────┘\n",[51,1362,1360],{"__ignoreMap":53},[15,1364,1365,1366,116],{},"Configure per display in ",[51,1367,305],{},[44,1369,1371],{"className":86,"code":1370,"language":88,"meta":53,"style":53},"{\n  \"sync\": {\n    \"topology\": { \"x\": 0, \"y\": 0, \"orientation\": 0 },\n    \"choreography\": \"diagonal-tl\",\n    \"staggerMs\": 200,\n    \"gridCols\": 2,\n    \"gridRows\": 2\n  }\n}\n",[51,1372,1373,1377,1389,1445,1464,1480,1496,1510,1514],{"__ignoreMap":53},[92,1374,1375],{"class":94,"line":95},[92,1376,99],{"class":98},[92,1378,1379,1381,1383,1385,1387],{"class":94,"line":102},[92,1380,106],{"class":105},[92,1382,179],{"class":109},[92,1384,113],{"class":105},[92,1386,116],{"class":98},[92,1388,186],{"class":98},[92,1390,1391,1393,1396,1398,1400,1403,1405,1408,1410,1412,1415,1418,1420,1423,1425,1427,1429,1431,1433,1436,1438,1440,1442],{"class":94,"line":132},[92,1392,192],{"class":105},[92,1394,1395],{"class":195},"topology",[92,1397,113],{"class":105},[92,1399,116],{"class":98},[92,1401,1402],{"class":98}," {",[92,1404,120],{"class":105},[92,1406,1407],{"class":211},"x",[92,1409,113],{"class":105},[92,1411,116],{"class":98},[92,1413,1414],{"class":211}," 0",[92,1416,1417],{"class":98},",",[92,1419,120],{"class":105},[92,1421,1422],{"class":211},"y",[92,1424,113],{"class":105},[92,1426,116],{"class":98},[92,1428,1414],{"class":211},[92,1430,1417],{"class":98},[92,1432,120],{"class":105},[92,1434,1435],{"class":211},"orientation",[92,1437,113],{"class":105},[92,1439,116],{"class":98},[92,1441,1414],{"class":211},[92,1443,1444],{"class":98}," },\n",[92,1446,1447,1449,1452,1454,1456,1458,1460,1462],{"class":94,"line":153},[92,1448,192],{"class":105},[92,1450,1451],{"class":195},"choreography",[92,1453,113],{"class":105},[92,1455,116],{"class":98},[92,1457,120],{"class":119},[92,1459,1285],{"class":123},[92,1461,113],{"class":119},[92,1463,129],{"class":98},[92,1465,1466,1468,1471,1473,1475,1478],{"class":94,"line":174},[92,1467,192],{"class":105},[92,1469,1470],{"class":195},"staggerMs",[92,1472,113],{"class":105},[92,1474,116],{"class":98},[92,1476,1477],{"class":211}," 200",[92,1479,129],{"class":98},[92,1481,1482,1484,1487,1489,1491,1494],{"class":94,"line":189},[92,1483,192],{"class":105},[92,1485,1486],{"class":195},"gridCols",[92,1488,113],{"class":105},[92,1490,116],{"class":98},[92,1492,1493],{"class":211}," 2",[92,1495,129],{"class":98},[92,1497,1498,1500,1503,1505,1507],{"class":94,"line":205},[92,1499,192],{"class":105},[92,1501,1502],{"class":195},"gridRows",[92,1504,113],{"class":105},[92,1506,116],{"class":98},[92,1508,1509],{"class":211}," 2\n",[92,1511,1512],{"class":94,"line":224},[92,1513,265],{"class":98},[92,1515,1516],{"class":94,"line":241},[92,1517,271],{"class":98},[24,1519,1521],{"id":1520},"comparison-with-other-players","Comparison with Other Players",[327,1523,1524,1545],{},[330,1525,1526],{},[333,1527,1528,1531,1534,1537,1540],{},[336,1529,1530],{},"Feature",[336,1532,1533],{},"Xibo Windows v4",[336,1535,1536],{},"Xibo XLR",[336,1538,1539],{},"Arexibo",[336,1541,1542],{},[19,1543,1544],{},"XiboPlayer",[349,1546,1547,1563,1579,1597,1614,1631,1646,1661,1677,1692,1710,1726,1741,1757,1776],{},[333,1548,1549,1552,1555,1557,1559],{},[354,1550,1551],{},"Same-machine sync",[354,1553,1554],{},"No",[354,1556,358],{},[354,1558,1554],{},[354,1560,1561],{},[19,1562,358],{},[333,1564,1565,1568,1571,1573,1575],{},[354,1566,1567],{},"Cross-device sync",[354,1569,1570],{},"ZeroMQ",[354,1572,1554],{},[354,1574,1554],{},[354,1576,1577],{},[19,1578,374],{},[333,1580,1581,1584,1587,1590,1592],{},[354,1582,1583],{},"Sync precision",[354,1585,1586],{},"~50-100ms",[354,1588,1589],{},"N\u002FA",[354,1591,1589],{},[354,1593,1594],{},[19,1595,1596],{},"\u003C8ms",[333,1598,1599,1602,1605,1607,1609],{},[354,1600,1601],{},"Choreography effects",[354,1603,1604],{},"None",[354,1606,1604],{},[354,1608,1604],{},[354,1610,1611],{},[19,1612,1613],{},"12 effects",[333,1615,1616,1618,1621,1624,1626],{},[354,1617,1117],{},[354,1619,1620],{},"Yes",[354,1622,1623],{},"Yes (same-tab)",[354,1625,1554],{},[354,1627,1628],{},[19,1629,1630],{},"Yes (LAN + same-machine)",[333,1632,1633,1635,1637,1639,1641],{},[354,1634,1123],{},[354,1636,1620],{},[354,1638,1554],{},[354,1640,1554],{},[354,1642,1643],{},[19,1644,1645],{},"Position-specific layouts",[333,1647,1648,1650,1652,1654,1656],{},[354,1649,1172],{},[354,1651,1620],{},[354,1653,1589],{},[354,1655,1589],{},[354,1657,1658],{},[19,1659,1660],{},"syncGroupId routing",[333,1662,1663,1666,1668,1670,1672],{},[354,1664,1665],{},"Token auth",[354,1667,1554],{},[354,1669,1589],{},[354,1671,1589],{},[354,1673,1674],{},[19,1675,1676],{},"CMS key auth",[333,1678,1679,1681,1683,1685,1687],{},[354,1680,1182],{},[354,1682,1554],{},[354,1684,1554],{},[354,1686,1554],{},[354,1688,1689],{},[19,1690,1691],{},"Persisted config",[333,1693,1694,1697,1699,1701,1703],{},[354,1695,1696],{},"Standalone relay",[354,1698,1554],{},[354,1700,1589],{},[354,1702,1589],{},[354,1704,1705],{},[19,1706,1707,1709],{},[51,1708,1084],{}," CLI",[333,1711,1712,1714,1716,1719,1721],{},[354,1713,475],{},[354,1715,1554],{},[354,1717,1718],{},"Yes (BC only)",[354,1720,1554],{},[354,1722,1723],{},[19,1724,1725],{},"Yes (BC + WebSocket)",[333,1727,1728,1730,1732,1734,1736],{},[354,1729,1188],{},[354,1731,1554],{},[354,1733,1589],{},[354,1735,1589],{},[354,1737,1738],{},[19,1739,1740],{},"Exponential backoff",[333,1742,1743,1746,1748,1750,1752],{},[354,1744,1745],{},"Video start sync",[354,1747,1620],{},[354,1749,1554],{},[354,1751,1554],{},[354,1753,1754],{},[19,1755,1756],{},"Coordinated unpause",[333,1758,1759,1762,1765,1768,1771],{},[354,1760,1761],{},"Platform",[354,1763,1764],{},"Windows only",[354,1766,1767],{},"Browser (Chrome)",[354,1769,1770],{},"Android",[354,1772,1773],{},[19,1774,1775],{},"Any (Electron, Chromium, Android, webOS)",[333,1777,1778,1781,1784,1786,1788],{},[354,1779,1780],{},"Firewall friendly",[354,1782,1783],{},"ZeroMQ ports",[354,1785,1589],{},[354,1787,1589],{},[354,1789,1790],{},[19,1791,1792],{},"Uses existing HTTP port",[15,1794,1795],{},"XiboPlayer is the most capable Xibo player for multi-display deployments. It's the only player with choreography effects, sub-10ms sync precision, token auth, and cross-platform support.",[24,1797,1799],{"id":1798},"architecture","Architecture",[15,1801,1802],{},"The sync system is split across two SDK packages:",[451,1804,1805,1822],{},[284,1806,1807,1810,1811,1814,1815,1818,1819],{},[19,1808,1809],{},"@xiboplayer\u002Fsync"," — ",[51,1812,1813],{},"SyncManager"," (protocol logic), ",[51,1816,1817],{},"BroadcastChannelTransport",", ",[51,1820,1821],{},"WebSocketTransport",[284,1823,1824,1810,1827,1830,1831,1709],{},[19,1825,1826],{},"@xiboplayer\u002Fproxy",[51,1828,1829],{},"attachSyncRelay()"," (server-side relay), ",[51,1832,1084],{},[15,1834,1835],{},"The transport interface is pluggable:",[44,1837,1841],{"className":1838,"code":1839,"language":1840,"meta":53,"style":53},"language-javascript shiki shiki-themes material-theme-lighter github-light github-dark","interface SyncTransport {\n  send(msg: object): void;\n  onMessage(callback: (msg: object) => void): void;\n  close(): void;\n  readonly connected: boolean;\n}\n","javascript",[51,1842,1843,1854,1883,1919,1933,1949],{"__ignoreMap":53},[92,1844,1845,1849,1852],{"class":94,"line":95},[92,1846,1848],{"class":1847},"sbsja","interface",[92,1850,1851],{"class":1041}," SyncTransport",[92,1853,186],{"class":98},[92,1855,1856,1860,1863,1867,1870,1873,1875,1877,1880],{"class":94,"line":102},[92,1857,1859],{"class":1858},"sVXei","  send",[92,1861,1862],{"class":98},"(",[92,1864,1866],{"class":1865},"s99_P","msg",[92,1868,116],{"class":1869},"smGrS",[92,1871,1872],{"class":195}," object",[92,1874,296],{"class":98},[92,1876,116],{"class":1869},[92,1878,1879],{"class":195}," void",[92,1881,1882],{"class":98},";\n",[92,1884,1885,1888,1890,1894,1896,1898,1900,1902,1904,1906,1909,1911,1913,1915,1917],{"class":94,"line":132},[92,1886,1887],{"class":1858},"  onMessage",[92,1889,1862],{"class":98},[92,1891,1893],{"class":1892},"sGLFI","callback",[92,1895,116],{"class":1869},[92,1897,79],{"class":98},[92,1899,1866],{"class":1865},[92,1901,116],{"class":1869},[92,1903,1872],{"class":195},[92,1905,296],{"class":98},[92,1907,1908],{"class":1847}," =>",[92,1910,1879],{"class":195},[92,1912,296],{"class":98},[92,1914,116],{"class":1869},[92,1916,1879],{"class":195},[92,1918,1882],{"class":98},[92,1920,1921,1924,1927,1929,1931],{"class":94,"line":153},[92,1922,1923],{"class":1858},"  close",[92,1925,1926],{"class":98},"()",[92,1928,116],{"class":1869},[92,1930,1879],{"class":195},[92,1932,1882],{"class":98},[92,1934,1935,1938,1942,1944,1947],{"class":94,"line":174},[92,1936,1937],{"class":1847},"  readonly",[92,1939,1941],{"class":1940},"sucvu"," connected",[92,1943,116],{"class":1869},[92,1945,1946],{"class":195}," boolean",[92,1948,1882],{"class":98},[92,1950,1951],{"class":94,"line":189},[92,1952,271],{"class":98},[15,1954,1955,1956,1959],{},"Custom transports (e.g., WebRTC for ultra-low-latency) can be injected via the ",[51,1957,1958],{},"transport"," constructor option.",[1961,1962,1963],"style",{},"html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .stzsN, html code.shiki .stzsN{--shiki-light:#91B859;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sseR_, html code.shiki .sseR_{--shiki-light:#9C3EDA;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sZMiF, html code.shiki .sZMiF{--shiki-light:#E2931D;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVXei, html code.shiki .sVXei{--shiki-light:#E53935;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s99_P, html code.shiki .s99_P{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sucvu, html code.shiki .sucvu{--shiki-light:#E53935;--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":53,"searchDepth":132,"depth":132,"links":1965},[1966,1970,1971,1972,1973,1974,1981,1982,1983,1984],{"id":26,"depth":102,"text":27,"children":1967},[1968,1969],{"id":31,"depth":132,"text":32},{"id":56,"depth":132,"text":57},{"id":311,"depth":102,"text":312},{"id":324,"depth":102,"text":325},{"id":396,"depth":102,"text":397},{"id":442,"depth":102,"text":443},{"id":479,"depth":102,"text":480,"children":1975},[1976,1977,1978,1979,1980],{"id":483,"depth":132,"text":484},{"id":490,"depth":132,"text":491},{"id":671,"depth":132,"text":672},{"id":1019,"depth":132,"text":1020},{"id":1092,"depth":132,"text":1093},{"id":1109,"depth":102,"text":1110},{"id":1210,"depth":102,"text":1211},{"id":1520,"depth":102,"text":1521},{"id":1798,"depth":102,"text":1799},"Cross-device synchronized displays with mirror mode, wall mode (position-specific layouts), group isolation, and standalone relay.","md",{},"\u002Ffeatures\u002Fmulti-display",{"title":5,"description":1985},"features\u002Fmulti-display","vSgmMS8uL6RhhlS_gDGpE5BfCYgHyMU6GZ211KJUsTU",1775148105253]