[{"data":1,"prerenderedAt":378},["ShallowReactive",2],{"docs-ca-\u002Fdocs\u002Fplayers\u002Fpwa":3},{"id":4,"title":5,"author":6,"body":7,"date":6,"description":371,"extension":372,"meta":373,"navigation":154,"path":374,"seo":375,"stem":376,"tags":6,"__hash__":377},"content_en\u002Fdocs\u002Fplayers\u002Fpwa.md","PWA Player",null,{"type":8,"value":9,"toc":359},"minimark",[10,14,18,23,64,68,75,80,177,183,187,206,210,213,217,267,271,279,283,315,329,333,355],[11,12,5],"h1",{"id":13},"pwa-player",[15,16,17],"p",{},"The PWA (Progressive Web App) is the rendering engine that powers all xiboplayer platforms. It can also run standalone in any modern browser.",[19,20,22],"h2",{"id":21},"features","Features",[24,25,26,34,40,46,52,58],"ul",{},[27,28,29,33],"li",{},[30,31,32],"strong",{},"Runs anywhere"," — Chrome, Firefox, Edge, or any Chromium-based browser",[27,35,36,39],{},[30,37,38],{},"Offline-first"," — Service Worker caches all media for offline playback",[27,41,42,45],{},[30,43,44],{},"All widget types"," — video (MP4, HLS), images, PDF, text\u002Ftickers, web pages, clock, calendar",[27,47,48,51],{},[30,49,50],{},"Interactive actions"," — touch\u002Fclick triggers, keyboard navigation, layout jumps",[27,53,54,57],{},[30,55,56],{},"Proof of play"," — per-layout and per-widget duration tracking",[27,59,60,63],{},[30,61,62],{},"Zero install"," — just open a URL",[19,65,67],{"id":66},"deployment","Deployment",[15,69,70,71,74],{},"The PWA must be served from the ",[30,72,73],{},"same origin"," as the CMS (same-origin policy for API calls). Two options:",[76,77,79],"h3",{"id":78},"option-a-deploy-to-cms-container","Option A: Deploy to CMS container",[81,82,87],"pre",{"className":83,"code":84,"language":85,"meta":86,"style":86},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark","# Build from source\ngit clone https:\u002F\u002Fgithub.com\u002Fxibo-players\u002Fxiboplayer.git\ncd xiboplayer && pnpm install\npnpm --filter @xiboplayer\u002Fpwa build\n\n# Copy to CMS web root\npodman cp packages\u002Fpwa\u002Fdist\u002F. xibo-cms-web:\u002Fvar\u002Fwww\u002Fcms\u002Fweb\u002Fchromeos\u002F\n","bash","",[88,89,90,99,113,133,149,156,162],"code",{"__ignoreMap":86},[91,92,95],"span",{"class":93,"line":94},"line",1,[91,96,98],{"class":97},"sutJx","# Build from source\n",[91,100,102,106,110],{"class":93,"line":101},2,[91,103,105],{"class":104},"sbgvK","git",[91,107,109],{"class":108},"s_sjI"," clone",[91,111,112],{"class":108}," https:\u002F\u002Fgithub.com\u002Fxibo-players\u002Fxiboplayer.git\n",[91,114,116,120,123,127,130],{"class":93,"line":115},3,[91,117,119],{"class":118},"sptTA","cd",[91,121,122],{"class":108}," xiboplayer",[91,124,126],{"class":125},"sP7_E"," &&",[91,128,129],{"class":104}," pnpm",[91,131,132],{"class":108}," install\n",[91,134,136,139,143,146],{"class":93,"line":135},4,[91,137,138],{"class":104},"pnpm",[91,140,142],{"class":141},"stzsN"," --filter",[91,144,145],{"class":108}," @xiboplayer\u002Fpwa",[91,147,148],{"class":108}," build\n",[91,150,152],{"class":93,"line":151},5,[91,153,155],{"emptyLinePlaceholder":154},true,"\n",[91,157,159],{"class":93,"line":158},6,[91,160,161],{"class":97},"# Copy to CMS web root\n",[91,163,165,168,171,174],{"class":93,"line":164},7,[91,166,167],{"class":104},"podman",[91,169,170],{"class":108}," cp",[91,172,173],{"class":108}," packages\u002Fpwa\u002Fdist\u002F.",[91,175,176],{"class":108}," xibo-cms-web:\u002Fvar\u002Fwww\u002Fcms\u002Fweb\u002Fchromeos\u002F\n",[15,178,179,180],{},"Access at: ",[88,181,182],{},"https:\u002F\u002Fyour-cms.example.com\u002Fplayer\u002F",[76,184,186],{"id":185},"option-b-via-ansible","Option B: Via Ansible",[81,188,190],{"className":83,"code":189,"language":85,"meta":86,"style":86},"ansible-playbook playbooks\u002Fservices\u002Fdeploy-pwa.yml -e target_host=h1.example.com\n",[88,191,192],{"__ignoreMap":86},[91,193,194,197,200,203],{"class":93,"line":94},[91,195,196],{"class":104},"ansible-playbook",[91,198,199],{"class":108}," playbooks\u002Fservices\u002Fdeploy-pwa.yml",[91,201,202],{"class":141}," -e",[91,204,205],{"class":108}," target_host=h1.example.com\n",[76,207,209],{"id":208},"option-c-electron-chromium-wrapper","Option C: Electron \u002F Chromium wrapper",[15,211,212],{},"The Electron and Chromium players serve the PWA via a built-in Express proxy, avoiding the same-origin constraint. This is the recommended approach for kiosk deployments.",[19,214,216],{"id":215},"keyboard-shortcuts","Keyboard shortcuts",[218,219,220,233],"table",{},[221,222,223],"thead",{},[224,225,226,230],"tr",{},[227,228,229],"th",{},"Key",[227,231,232],{},"Action",[234,235,236,247,257],"tbody",{},[224,237,238,244],{},[239,240,241],"td",{},[88,242,243],{},"D",[239,245,246],{},"Toggle download overlay (shows download progress)",[224,248,249,254],{},[239,250,251],{},[88,252,253],{},"T",[239,255,256],{},"Toggle timeline overlay (shows schedule)",[224,258,259,264],{},[239,260,261],{},[88,262,263],{},"S",[239,265,266],{},"Toggle setup overlay (CMS configuration)",[19,268,270],{"id":269},"how-it-works-with-electron-chromium","How it works with Electron \u002F Chromium",[81,272,277],{"className":273,"code":275,"language":276},[274],"language-text","Player wrapper\n  └── Express proxy (localhost:8765)\n        ├── \u002Fplayer\u002F         → serves PWA dist files\n        ├── \u002Fxmds-proxy     → forwards SOAP to CMS\n        ├── \u002Fapi\u002F*           → forwards REST to CMS\n        └── \u002Fstore\u002F*         → ContentStore filesystem\n              ↓\n        PWA loads from localhost\n        Service Worker caches everything\n        Offline playback from local store\n","text",[88,278,275],{"__ignoreMap":86},[19,280,282],{"id":281},"limitations-standalone-browser-mode","Limitations (standalone browser mode)",[24,284,285,291,297,303,309],{},[27,286,287,290],{},[30,288,289],{},"Same-origin required"," — must be hosted on CMS domain",[27,292,293,296],{},[30,294,295],{},"No kiosk mode"," — browser controls remain visible",[27,298,299,302],{},[30,300,301],{},"No GPU detection"," — uses browser defaults",[27,304,305,308],{},[30,306,307],{},"No system integration"," — no auto-start, no power management",[27,310,311,314],{},[30,312,313],{},"Storage limits"," — browser storage quotas apply (typically 50% of disk)",[15,316,317,318,323,324,328],{},"For production kiosk deployments, use the ",[319,320,322],"a",{"href":321},"\u002Fdocs\u002Fplayers\u002Felectron","Electron"," or ",[319,325,327],{"href":326},"\u002Fdocs\u002Fplayers\u002Fchromium","Chromium"," wrapper instead.",[19,330,332],{"id":331},"source","Source",[24,334,335,348],{},[27,336,337,343,344,347],{},[319,338,342],{"href":339,"rel":340},"https:\u002F\u002Fgithub.com\u002Fxibo-players\u002Fxiboplayer",[341],"nofollow","GitHub: xibo-players\u002Fxiboplayer"," (",[88,345,346],{},"packages\u002Fpwa\u002F",")",[27,349,350],{},[319,351,354],{"href":352,"rel":353},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@xiboplayer\u002Fpwa",[341],"npm: @xiboplayer\u002Fpwa",[356,357,358],"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 .sptTA, html code.shiki .sptTA{--shiki-light:#6182B8;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}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);}",{"title":86,"searchDepth":115,"depth":115,"links":360},[361,362,367,368,369,370],{"id":21,"depth":101,"text":22},{"id":66,"depth":101,"text":67,"children":363},[364,365,366],{"id":78,"depth":115,"text":79},{"id":185,"depth":115,"text":186},{"id":208,"depth":115,"text":209},{"id":215,"depth":101,"text":216},{"id":269,"depth":101,"text":270},{"id":281,"depth":101,"text":282},{"id":331,"depth":101,"text":332},"Browser-based signage player that runs anywhere — the rendering engine behind all xiboplayer platforms","md",{"order":151},"\u002Fdocs\u002Fplayers\u002Fpwa",{"title":5,"description":371},"docs\u002Fplayers\u002Fpwa","nc9LIu6NpKMkYUx3o6KlLdPW-EDhZO4760Hx3cHbmGo",1775148112736]