
Security News
upm Launches as a Fast, Tiny Package Manager Written in TypeScript
upm uses Node.js to deliver fast npm installs in about 250 KB, with a JavaScript API and security defaults.
@xiboplayer/renderer
Advanced tools
Fast, memory-efficient XLF layout rendering engine for digital signage.
Parses Xibo Layout Format (XLF) files and builds a live DOM with element reuse, instant transitions, and a 2-layout preload pool:
XLF XML -> RendererLite
+- parseXlf() -> Layout object {width, height, regions: []}
+- renderLayout()
+- createRegion() for each region
| +- createWidgetElement() for each widget
| +- renderImage() [<img>]
| +- renderVideo() [<video>] (HLS/DASH)
| +- renderAudio() [<audio> + visual]
| +- renderTextWidget() [<iframe>] (GetResource)
| +- renderPdf() [<canvas>] (multi-page)
| +- renderWebpage() [<iframe>]
| +- renderVideoIn() [<video>] (webcam)
| +- renderGenericWidget() [<iframe>] (clock, etc.)
|
+- attachActionListeners() for touch/click/keyboard
+- startRegion() -> _startRegionCycle()
| +- renderWidget() / stopWidget() cycling
|
+- startLayoutTimerWhenReady()
+- Waits for all initial widgets to load
+- Starts layout duration timer
Layout Pool (2 entries max):
+- Hot entry (visible, currently playing)
+- Warm entry (preloaded, hidden, ready for instant swap)
npm install @xiboplayer/renderer
import { RendererLite } from '@xiboplayer/renderer';
const renderer = new RendererLite(
{ cmsUrl: 'https://cms.example.com', hardwareKey: 'DISPLAY-001' },
document.getElementById('player')
);
renderer.on('layoutStart', (layoutId, layout) => {
console.log(`Layout ${layoutId} started (${layout.duration}s)`);
});
renderer.on('layoutEnd', (layoutId) => {
console.log(`Layout ${layoutId} ended`);
});
await renderer.renderLayout(xlfXmlContent, 42);
// At 75% of current layout duration, renderer emits:
renderer.on('request-next-layout-preload', async () => {
const nextLayout = await getNextLayoutFromSchedule();
if (nextLayout && !renderer.hasPreloadedLayout(nextLayout.id)) {
await renderer.preloadLayout(nextLayout.xlf, nextLayout.id);
}
});
// When it's time to show next layout, swap is INSTANT if preloaded
await renderer.renderLayout(nextXlfXml, nextLayoutId);
// Render an overlay on top of the main layout
await renderer.renderOverlay(alertXlfXml, 101, 10);
renderer.on('overlayEnd', (overlayId) => console.log('Overlay done'));
// Stop overlay
renderer.stopOverlay(101);
| Type | Element | Source | Notes |
|---|---|---|---|
| image | <img> | Media file | Object-fit: center/stretch/fit. objectPosition: top/middle/bottom, left/center/right |
| video | <video> | Media file | HLS via native (Safari) + hls.js fallback. Pause-on-last-frame. Duration detection |
| audio | <audio> + visual | Media file | Gradient visualization + music note icon. Volume control. Loop option |
| videoin | <video> | getUserMedia() | Webcam/mic capture with mirror mode |
| text | <iframe> | GetResource | CMS-rendered HTML. Parses NUMITEMS/DURATION comments |
| ticker | <iframe> | GetResource | Data feeds with dynamic cycling |
<canvas> | Media file | PDF.js multi-page cycling. Page indicator. Time-per-page = duration / pages | |
| webpage | <iframe> | Direct URL | modeId=1 (URL), modeId=0 (GetResource) |
| clock | <iframe> | GetResource | Digital/analogue variants |
| calendar | <iframe> | GetResource | Calendar widget HTML |
| weather | <iframe> | GetResource | Weather service HTML |
| global | Stacked iframes | GetResource | Canvas region auto-detect for multi-layer content |
| all others | <iframe> | GetResource | Generic CMS widget HTML |
XLF XML
|
+- parseXlf() -> {width, height, regions: [{widgets: [...]}]}
|
+- calculateScale() -> fit layout to screen
|
+- createRegion() for each region
| +- Filter widgets (fromDt/toDt time-gating)
| +- Apply sub-playlist cycling
|
+- createWidgetElement() for each widget (pre-creation)
| +- Create DOM element, position absolute, hidden
| +- Track blob URLs for cleanup
|
+- startRegion() for each region
| +- Canvas: show ALL widgets at once, timer = max duration
| +- Normal: cycle widgets with transitions
|
+- startLayoutTimerWhenReady()
| +- Wait for video.playing / img.load (or 10s timeout)
| +- Start layout duration timer
|
+- At 75%: emit 'request-next-layout-preload'
|
+- Layout duration expires
+- emit('layoutEnd', layoutId)
renderLayout() -- hidden, opacity 0renderWidget() shows current, stopWidget() hides (same elements)Layout timer starts only when all initial widgets are loaded:
playing eventload eventDefined per-widget in XLF options:
Fade: fade, fadein, fadeout -- opacity animation
Fly: fly, flyin, flyout -- translate animation with compass direction:
N, NE, E, SE, S, SW, W, NW<media duration="5">
<options>
<transIn>fly</transIn>
<transInDuration>1000</transInDuration>
<transInDirection>NE</transInDirection>
<transOut>fade</transOut>
<transOutDuration>500</transOutDuration>
</options>
</media>
Actions defined in XLF at layout, region, or widget level:
Trigger types: touch (click), keyboard:KEY (e.g., keyboard:n, keyboard:Enter)
Action types: navWidget (jump to widget), nextWidget, previousWidget, shellCommand
renderer.on('action-trigger', (actionData) => {
console.log(`Action: ${actionData.actionType}`, actionData);
});
// Programmatic navigation
renderer.navigateToWidget('target-widget-id');
renderer.nextWidget('region-id');
renderer.previousWidget('region-id');
| Event | Args | Description |
|---|---|---|
layoutStart | (layoutId, layout) | Layout DOM built and playback started |
layoutEnd | (layoutId) | Layout duration expired |
layoutDurationUpdated | (layoutId, newDuration) | Video metadata revealed actual duration |
widgetStart | ({ widgetId, regionId, layoutId, type, duration, enableStat }) | Widget now visible |
widgetEnd | ({ widgetId, regionId, layoutId, type, enableStat }) | Widget hidden/cycled |
widgetCommand | ({ commandCode, commandString, widgetId, regionId, layoutId }) | Shell command triggered |
widgetAction | ({ type, widgetId, layoutId, regionId, url }) | Widget webhook URL |
videoError | ({ storedAs, fileId, errorCode, errorMessage }) | Video playback error |
overlayStart | (overlayId, layout) | Overlay rendered |
overlayEnd | (overlayId) | Overlay finished |
action-trigger | ({ actionType, triggerType, targetId, commandCode }) | Touch/keyboard action fired |
request-next-layout-preload | () | 75% through layout -- preload next |
error | ({ type, error, layoutId, widgetId }) | Generic error |
new RendererLite(config, container, options?)
| Parameter | Type | Description |
|---|---|---|
config | Object | { cmsUrl, hardwareKey } |
container | HTMLElement | DOM element to render into |
options.getWidgetHtml | Function? | (widget) => htmlString -- fetch widget HTML from cache |
options.fileIdToSaveAs | Map? | Map of fileId to storedAs filename |
| Method | Returns | Description |
|---|---|---|
renderLayout(xlfXml, layoutId) | Promise | Parse, build, and start layout. Instant swap if preloaded. |
preloadLayout(xlfXml, layoutId) | Promise | Pre-build layout as hidden warm entry |
hasPreloadedLayout(layoutId) | boolean | Check if layout is in preload pool |
renderOverlay(xlfXml, layoutId, priority) | Promise | Render overlay on top |
stopCurrentLayout() | void | Stop main layout |
stopOverlay(layoutId) | void | Stop and remove overlay |
stopAllOverlays() | void | Stop all active overlays |
navigateToWidget(widgetId) | void | Jump to specific widget |
nextWidget(regionId?) | void | Advance to next widget |
previousWidget(regionId?) | void | Go back to previous widget |
pause() | void | Pause media and widget cycling |
resume() | void | Resume playback |
cleanup() | void | Stop all, clear pool, revoke blob URLs |
@xiboplayer/utils -- logger, eventspdfjs-dist -- PDF rendering (dynamic import)hls.js -- HLS streaming (dynamic import)xiboplayer.org · Part of the XiboPlayer SDK
FAQs
RendererLite - Fast, efficient XLF layout rendering engine
The npm package @xiboplayer/renderer receives a total of 9 weekly downloads. As such, @xiboplayer/renderer popularity was classified as not popular.
We found that @xiboplayer/renderer demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
upm uses Node.js to deliver fast npm installs in about 250 KB, with a JavaScript API and security defaults.

Company News
Socket is joining the OpenJS Security Stewardship Program to fund Node.js vulnerability research, maintainer remediation, and security releases.

Security News
Two compromised GitHub Actions were re-enabled with malicious tags intact, exposing thousands of downstream repositories to Mini Shai-Hulud.