Getting started
Create your first Ludicord Activity and understand the development loop.
Ludicord is a full-stack React framework for Discord Activities. It connects the Activity UI, Discord identity, trusted HTTP handlers, and realtime connections in one project. This guide takes you from an empty folder to a running Activity.
iNoteBefore you begin: Install Node.js 20.19 or newer and create a Discord application. You can preview the UI in a normal browser, but real guild, channel, user, and Activity-instance data only exists when Discord launches the Activity.
#Create a project
Run the generator and choose a project name. Tailwind CSS is enabled by default; answer n if you prefer plain CSS.
1npx create-ludicord-app@latest my-activity2cd my-activity
For a repeatable non-interactive setup, pass the choices as flags:
1npx create-ludicord-app@latest my-activity --tailwind --package-manager npm --git
The generator installs Ludicord, React, TypeScript, and the selected styling tools. It also creates working examples for an embed, a protected API route, and a realtime audience counter.
#Add your Discord credentials
Copy .env.example to .env.local, then add the application values from the Discord Developer Portal.
1LUDICORD_DISCORD_CLIENT_ID=your_application_id2LUDICORD_DISCORD_CLIENT_SECRET=your_client_secret3LUDICORD_SESSION_SECRET=use_a_random_value_at_least_32_characters4LUDICORD_DISCORD_PUBLIC_KEY=your_public_key
Never commit .env.local. Only the Client ID is safe to expose to the Activity browser. The Client Secret and Session Secret are read by the Ludicord server.
#Start development
1npm run dev
Ludicord prints the local URL and compiles the files under app/. Open the URL for a browser preview. Edit app/embeds/home/embed.tsx; a successful client update uses Fast Refresh, while API and WebSocket route edits reload without restarting the development server.
The browser preview is intentionally limited. outsideDiscord: "allow" lets the page render, but Discord hooks return unavailable data until the Activity is launched inside Discord.
#Understand the first render
app/pages.tsx is the persistent shell. EmbedOutlet renders the active screen from app/embeds, starting with home.
1import { EmbedOutlet, LudicordActivity } from "ludicord";2import "./globals.css";34export default function Pages() {5 return (6 <LudicordActivity defaultEmbed="home">7 <EmbedOutlet />8 </LudicordActivity>9 );10}
The framework discovers the root and embed files, generates route types, initializes Discord, and supplies loading or error boundaries around the active screen.
#Your development loop
#Next step
Continue to Installation for every generator option, or jump to Discord setup when the local UI is already running.