Skip to main content
Version: 1.x.x

Reactions during Live Stream - JavaScript

To enhance interaction between viewers and speakers during a livestream, a creative approach is to display viewers' reactions to everyone. This can be achieved by creating a lively atmosphere with flying emojis, similar to the experience seen in livestreams on platforms like Instagram.

This guide explains how to implement this engaging feature using the VideoSDK PubSub mechanism.

Step 1: Creating a button to send reactionโ€‹

To implement this functionality, start by creating a button that sends reactions to all users. When this button is clicked, publish a message with the emoji name to all participants using the VideoSDK PubSub mechanism. Additionally, dispatch browser CustomEvents to notify the local participant about the reaction.

function sendEmoji(emoji) {
// Let the local user see their own emoji
window.dispatchEvent(
new CustomEvent("reaction_added", { detail: { emoji } })
);
}

// Create the ๐ŸŽ‰ button
const confettiBtn = document.createElement("button");
confettiBtn.innerText = "Send ๐ŸŽ‰ Reaction";
confettiBtn.onclick = async () => {
sendEmoji("confetti");
try {
await liveStream?.pubSub.publish("REACTION", "confetti");
} catch (error) {
console.log("Error while publishing REACTION:", error);
}
};

// Create the ๐Ÿ‘ button
const clapBtn = document.createElement("button");
clapBtn.innerText = "Send ๐Ÿ‘ Reaction";
clapBtn.onclick = async () => {
sendEmoji("clap");
try {
await liveStream?.pubSub.publish("REACTION", "clap");
} catch (error) {
console.log("Error while publishing REACTION:", error);
}
};

// Append to DOM
document.body.appendChild(confettiBtn);
document.body.appendChild(clapBtn);

Step 2: Displaying the Reactions to all the usersโ€‹

FlyingEmojiOverlay.js will be utilized to display the reactions on the screen. Listen to the browser event sent on the button click to show the flying emoji and display all reactions sent by other participants

  • Listening to local event and adding the FlyingEmojiOverlay component to the ILSView;
async function FlyingEmojisOverlay() {
const EMOJI_MAP = {
confetti: "๐ŸŽ‰",
clap: "๐Ÿ‘",
};

const overlay = document.createElement("div");
overlay.className = "flying-emojis";
document.body.appendChild(overlay);

function showFlyingEmoji(emojiKey) {
const emoji = EMOJI_MAP[emojiKey];
if (!emoji) return;

const span = document.createElement("span");
span.innerText = emoji;
span.className = "emoji-fly"; // Add some CSS animation
overlay.appendChild(span);

// Remove emoji after animation (2s example)
setTimeout(() => {
overlay.removeChild(span);
}, 2000);
}

async function handleSendFlyingEmoji(e) {
const { emoji } = e.detail;
if (emoji) {
showFlyingEmoji(emoji); // Show for local user
try {
await liveStream?.pubSub.publish("REACTION", emoji); // Send to others
} catch (error) {
console.log("Error while publishing REACTION:", error);
}
}
}

window.addEventListener("reaction_added", handleSendFlyingEmoji);

// Also listen for others' emojis
const listeners = {
onMessageReceived: ({ message }) => {
showFlyingEmoji(message);
},
};
try {
await liveStream?.pubSub.subscribe("REACTION", listeners);
} catch (error) {
console.log("Error while subscribing to REACTION:", error);
}

return overlay;
}
  • Next, implement the display and removal of flying emojis using simple CSS animations.
async function FlyingEmojisOverlay() {
const EMOJI_MAP = {
confetti: "๐ŸŽ‰",
clap: "๐Ÿ‘",
};

const overlay = document.createElement("div");
overlay.className = "flying-emojis";
document.body.appendChild(overlay);

// ๐Ÿงน Handler to remove flying emoji after animation
function handleRemoveFlyingEmoji(node) {
if (overlay.contains(node)) {
overlay.removeChild(node);
}
}

// โœจ Handler to display emoji with random animations
function handleDisplayFlyingEmoji(emojiKey) {
const emoji = EMOJI_MAP[emojiKey];
if (!emoji) return;

const node = document.createElement("div");
node.appendChild(document.createTextNode(emoji));

// Random animation and style
node.className = Math.random() > 0.5 ? "emoji wiggle-1" : "emoji wiggle-2";
node.style.position = "absolute";
node.style.left = `${Math.random() * 100}%`;
node.style.transform = `rotate(${-30 + Math.random() * 60}deg)`;

overlay.appendChild(node);

// Remove after animation ends
node.addEventListener("animationend", () => {
handleRemoveFlyingEmoji(node);
});
}

// ๐Ÿš€ Local user emoji trigger
async function handleSendFlyingEmoji(e) {
const { emoji } = e.detail;
if (emoji) {
handleDisplayFlyingEmoji(emoji);
try {
await liveStream?.pubSub.publish("REACTION", emoji);
} catch (error) {
console.log("Error while publishing REACTION:", error);
}
}
}

// ๐Ÿ‘‚ Setup event listeners
window.addEventListener("reaction_added", handleSendFlyingEmoji);

const listeners = {
onMessageReceived: ({ message }) => {
handleDisplayFlyingEmoji(message);
},
};
try {
await liveStream?.pubSub.subscribe("REACTION", listeners);
} catch (error) {
console.log("Error while subscribing to REACTION:", error);
}

// ๐Ÿงน Cleanup on unload
window.addEventListener("beforeunload", async () => {
window.removeEventListener("reaction_added", handleSendFlyingEmoji);
try {
await liveStream?.pubSub.unsubscribe("REACTION", listeners);
} catch (err) {
console.log("Error in unsubscribe", err);
}
});

return overlay;
}
  • Add the animations for the emojis in the index.css file.
.flying-emojis {
position: fixed;
top: 0px;
bottom: 0px;
left: 0px;
right: 0px;
overflow: hidden;
pointer-events: none;
user-select: none;
z-index: 99;
}
.emoji {
position: absolute;
bottom: 0px;
left: 50%;
font-size: 48px;
line-height: 1;
width: 48px;
height: 48px;
}
.emoji.wiggle-1 {
animation: emerge 3s forwards, wiggle-1 1s ease-in-out infinite alternate;
}
.emoji.wiggle-2 {
animation: emerge 3s forwards, wiggle-2 1s ease-in-out infinite alternate;
}
@keyframes emerge {
to {
bottom: 85%;
opacity: 0;
}
}
@keyframes wiggle-1 {
from {
margin-left: -50px;
}
to {
margin-left: 50px;
}
}
@keyframes wiggle-2 {
from {
margin-left: 50px;
}
to {
margin-left: -50px;
}
}
  • Finally add the listener to the PubSub topic so reactions from other participants can also be shown.
async function FlyingEmojisOverlay() {
const EMOJI_MAP = {
confetti: "๐ŸŽ‰",
clap: "๐Ÿ‘",
};

const overlay = document.createElement("div");
overlay.className = "flying-emojis";
document.body.appendChild(overlay);

// ๐Ÿงน Handler to remove flying emoji after animation
function handleRemoveFlyingEmoji(node) {
if (overlay.contains(node)) {
overlay.removeChild(node);
}
}

// โœจ Handler to display emoji with random animations
function handleDisplayFlyingEmoji(emojiKey) {
const emoji = EMOJI_MAP[emojiKey];
if (!emoji) return;

const node = document.createElement("div");
node.appendChild(document.createTextNode(emoji));

// Random animation and style
node.className = Math.random() > 0.5 ? "emoji wiggle-1" : "emoji wiggle-2";
node.style.position = "absolute";
node.style.left = `${Math.random() * 100}%`;
node.style.transform = `rotate(${-30 + Math.random() * 60}deg)`;

overlay.appendChild(node);

// Remove after animation ends
node.addEventListener("animationend", () => {
handleRemoveFlyingEmoji(node);
});
}

// ๐Ÿš€ Local user emoji trigger
async function handleSendFlyingEmoji(e) {
const { emoji } = e.detail;
if (emoji) {
handleDisplayFlyingEmoji(emoji);
try {
await liveStream?.pubSub.publish("REACTION", emoji); // Publish the reaction
} catch (error) {
console.log("Error while publishing REACTION:", error);
}
}
}

// ๐Ÿ‘‚ Setup event listeners for the local user to trigger emoji reactions
window.addEventListener("reaction_added", handleSendFlyingEmoji);

// ๐Ÿง‘โ€๐Ÿคโ€๐Ÿง‘ Listen for reactions from other participants
const listeners = {
onMessageReceived: ({ message }) => {
handleDisplayFlyingEmoji(message); // Display the received emoji from others
},
};
try {
await liveStream?.pubSub.subscribe("REACTION", listeners);
} catch (error) {
console.log("Error while subscribing to REACTION:", error);
}

// ๐Ÿงน Cleanup on unload (to avoid memory leaks)
window.addEventListener("beforeunload", async () => {
window.removeEventListener("reaction_added", handleSendFlyingEmoji);
try {
await liveStream?.pubSub.unsubscribe("REACTION", listeners);
} catch (err) {
console.log("Error in unsubscribe", err);
}
});

return overlay;
}

API Referenceโ€‹

The API references for all the methods and events utilized in this guide are provided below.

Got a Question? Ask us on discord