Skip to content

Slot system

The MUF Engine prebuilt pages (broadcaster.html, viewer.html) include named slot mount points — DOM containers where you drop in your own widgets. Slot names are part of the public API and won’t be renamed without a major-version bump.

The 17 slots, by region

Slot nameWhereCustomer typically fills
header.actionPillRight of the host info pillFollow button, badge
header.promoChipsBelow the topbarDaily Ranking, Gift Goal, Campaigns
header.topRightActionsTop-right, left of viewer countCustom CTAs

Viewport (overlays the video)

SlotWhereUse
viewport.sideCardsFloating right columnRecommended cohost cards
viewport.floatingFxFree overlayHearts, gifts, reactions
viewport.bannerTopBelow header”We’re notifying viewers…”
viewport.bannerBottomAbove chatWelcome banners

Action bar

SlotWhereUse
actionBar.bottomLeftLeft clusterQuick reactions, custom shortcuts
actionBar.bottomRightRight clusterGift, custom CTAs

Sheet (bottom-up modals)

SlotWhereUse
sheet.interact”Interact” sheetPolls, votes, draw-and-guess
sheet.effects”Effects” sheetBeauty filter, AR, music
sheet.moreSettingsSettings dropdownFan Club, About Me, Campaigns
sheet.guests”Go LIVE with guests” sheetFriends list for Quick Invites

End screen (post-stream)

SlotWhereUse
endScreen.statsCardsStats gridGifters, followers, $ earned
endScreen.recommendations”Watch next”Recommended creators
endScreen.ctaBottom button rowCustom CTAs

Pre-live setup

SlotWhereUse
setup.topChipsTop of pre-liveReward / promo chips
setup.iconRowIcon row in bottom panelEffects, Fan Club, Music tiles

Three integration depths

Layer 1 — config (simplest)

manager.fillSlot('header.actionPill', '<button>+ Follow</button>');
manager.fillSlot('actionBar.bottomRight', myCustomElement);
manager.fillSlot('endScreen.statsCards', (ctx) => {
return `<div>💎 ${ctx.broadcasters[0]?.displayName}'s gifts: 0</div>`;
});
manager.fillSlot('header.promoChips', [
'<span class="chip">🔥 Daily Ranking</span>',
'<span class="chip">🎁 Gift Goal</span>',
]);

fillSlot accepts: HTML string, HTMLElement, function (ctx) => Node | string, or array of any of the above.

Layer 2 — events + reactive components

manager.on('SLOT_RENDER', ({ name, mount, ctx }) => {
if (name === 'header.actionPill') {
ReactDOM.render(<FollowButton ctx={ctx} />, mount);
}
if (name === 'actionBar.bottomRight') {
const root = createRoot(mount);
root.render(<GiftDrawer />);
}
});

The event fires once per slot when it’s first registered with the manager. For dynamic content that re-renders on state changes, your component listens to manager.on('viewerCount', ...) etc. itself.

Layer 3 — imperative escape hatch

const node = manager.getSlotMount('header.actionPill');
if (node) {
node.appendChild(myCustomElement);
}

Use case: integrating with a framework that wants to manage its own DOM lifecycle (Web Components, Lit, Stencil, etc.).

Context object

Every render callback + the SLOT_RENDER event payload includes a ctx with the relevant room state:

type SlotContext = {
roomId: string | null;
role: 'broadcaster' | 'viewer' | null;
myPeerId: string | null;
myIdentity: { displayName?: string; avatarUrl?: string };
isLive?: boolean;
broadcasters?: Array<{
peerId: string;
displayName?: string;
avatarUrl?: string;
}>;
};

Stability

  • Adding a slot — non-breaking, ships in any minor version.
  • Renaming a slot — major-version-only. Old name stays as a deprecated alias for one minor version before removal.
  • Removing a slot — major-version-only. Marked deprecated for one minor version first.
  • Changing context fields — adding fields is non-breaking; changing types or removing fields is major-version-only.

When a slot is deprecated, both names fire SLOT_RENDER simultaneously during the deprecation window. Console logs warn on deprecated-name use. Migrate before the next major.

What’s NOT a slot

These are intentionally NOT customer-extensible:

  • Video grid layout (mediasoup-driven, fixed)
  • Mic / cam / flip / mirror / pause-LIVE controls
  • Chat message rendering (chat-engine consistency)
  • Permission recovery modal
  • 3-2-1 countdown

If you need one of these, file a feature request — some may move to slots in a future version after design review.