Keyloom

Slack Messages

An animated Slack-style channel conversation with avatars, sender names, and a typing indicator.

Preview

Open editor

Usage

A flat Slack-channel feel — no chat bubbles, just a rounded-square avatar, bold sender name, timestamp, and message text per row. contactName becomes the channel name in the header (slugified to #kebab-case) and the displayed sender for side: "left". side: "right" is shown as you.

A "X is typing" indicator pulses at the bottom while the latest message is in its typingFrames window.

Props

NameTypeDefault
contactNamestring"design"
messagesChatMessage[][4 items]
theme"light" | "dark""light"
orientation"landscape" | "portrait""landscape"
scalenumber2.5
leftAvatarstring (url)"images/logos/aryan-avatar.png"
rightAvatarstring (url)"gaia-glow.png"

Composition

ID
SlackMessages
Resolution
1280×720
FPS
60
Duration
6.0s

Source

Copy or download the React source — drop it into your own Remotion project. The only runtime dependency is remotion.

"use client";
import { type ClipStyle, resolveClipStyle } from "../../clip-style";
import type { ChatMessage } from "../../editors/types";
import { useDesignFrame } from "../../use-design-frame";
import { ChatDemo, type ChatMessageItem } from "../_chat-demo/ChatDemo";
import { ChatFill } from "../_chat-demo/ChatFill";

export type SlackMessagesProps = {
  contactName: string;
  messages: ChatMessage[];
  theme: "light" | "dark";
  orientation?: "landscape" | "portrait";
  scale?: number;
  leftAvatar?: string;
  rightAvatar?: string;
  /** Universal Style — background (chat screen), text, font, accent. */
  clipStyle?: ClipStyle;
};

const DEFAULT_LEFT_AVATAR = "images/logos/aryan-avatar.png";
const DEFAULT_RIGHT_AVATAR = "gaia-glow.png";

function buildItems(
  messages: ChatMessage[],
  frame: number,
  leftAvatar: string,
  rightAvatar: string,
): ChatMessageItem[] {
  const out: ChatMessageItem[] = [];
  for (let i = 0; i < messages.length; i++) {
    const m = messages[i]!;
    if (frame < m.delay) continue;
    const local = frame - m.delay;
    const isTyping = local < m.typingFrames;
    const isGaia = m.side === "right";
    out.push({
      id: i,
      // Slack is a channel — every message is left-aligned next to its
      // author's avatar, regardless of who sent it. `from` here only drives
      // bubble alignment, so it's always "them".
      from: "them",
      author: isGaia ? "GAIA" : "Aryan",
      avatar: isGaia ? rightAvatar : leftAvatar,
      text: m.text,
      typing: isTyping,
      enterFrames: local,
    });
  }
  return out;
}

export const SlackMessages: React.FC<SlackMessagesProps> = ({
  contactName,
  messages,
  theme,
  orientation = "landscape",
  scale = 2.5,
  leftAvatar = DEFAULT_LEFT_AVATAR,
  rightAvatar = DEFAULT_RIGHT_AVATAR,
  clipStyle,
}) => {
  const frame = useDesignFrame();
  const items = buildItems(messages, frame, leftAvatar, rightAvatar);

  // Slack is a channel view (no outgoing bubble). theme decides the DEFAULT
  // background/text; a clipStyle override wins. Accent has no single clean
  // element here, so the aubergine brand color is left to authentic chrome.
  const themeBg = theme === "dark" ? "#1A1D21" : "#FFFFFF";
  const s = resolveClipStyle(clipStyle, {
    background: themeBg,
    color: theme === "dark" ? "#D1D2D3" : "#1D1C1D",
    fontFamily:
      '"Slack-Lato", "Lato", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
    accent: "#4a154b",
  });

  return (
    <ChatFill
      backdrop={s.background}
      chromeColor={themeBg}
      scale={scale}
      orientation={orientation}
    >
      <ChatDemo
        platform="slack"
        title={contactName}
        theme={theme}
        messages={items}
        clipBackground={s.background}
        clipColor={s.color}
        clipFontFamily={s.fontFamily}
      />
    </ChatFill>
  );
};
Save as SlackMessages/SlackMessages.tsx