English | νκ΅μ΄
Thanks for your interest in SoundBadge! Bug reports, feature requests, new themes/templates β all contributions are welcome.
- Node.js 18+
- bun (do not use npm/yarn)
- YouTube Data API v3 key
# 1. Fork & clone
git clone https://github.com/<your-username>/SoundBadge.git
cd SoundBadge
# 2. Install dependencies
bun install
# 3. Set up environment variables
cp .env.example .env.local
# Add your YOUTUBE_API_KEY to .env.local
# 4. Start dev server
bun devbun dev # Dev server (Turbopack)
bun run build # Production build
bun run lint # ESLint
bun run typecheck # TypeScript type check- Create a new branch from
maingit checkout -b feat/my-feature
- Make your changes and commit
- Ensure lint & type check pass
bun run lint && bun run typecheck - Push and open a PR
git push origin feat/my-feature
| Prefix | Purpose |
|---|---|
feat/ |
New feature |
fix/ |
Bug fix |
theme/ |
New theme/template |
docs/ |
Documentation |
refactor/ |
Refactoring |
Classic themes are card styles with thumbnail + title + channel info.
src/themes/presets/your-theme.ts:
import type { Theme } from "../types";
export const yourTheme: Theme = {
name: "your-theme", // Must be added to ThemeName type
label: "Your Theme",
tokens: {
bg: "#ffffff", // Background (solid color or CSS gradient)
fg: "#1a1a1a", // Main text
muted: "#6b7280", // Sub text
accent: "#3b82f6", // Accent color
border: "#e5e7eb", // Border ("none" is also valid)
shadow: "none", // Shadow (CSS box-shadow or "none")
radius: 12, // Border radius (px)
pattern: "none", // Background pattern: "none" | "noise" | "grid" | "dots"
},
};Add to the ThemeName union in src/themes/types.ts:
export type ThemeName =
| "minimal"
// ...
| "your-theme";Import and register in src/themes/index.ts.
Templates have a freer SVG layout than classic themes (badge, stream, terminal, etc.).
src/templates/your-template.ts:
import type { Template, TemplateRenderOptions } from "./types";
import { truncate, esc } from "./utils";
export const yourTemplate: Template = {
meta: {
id: "your-template",
displayName: "Your Template",
description: "Template description",
category: "simple", // "simple" | "player" | "visual" | "developer"
supportsLayout: false,
supportsMultiTrack: false,
maxTracks: 1,
variants: [], // Add color variants if needed
previewDimensions: { width: 480, height: 180 },
},
render(options: TemplateRenderOptions): string {
const { track, tracks, variant } = options;
return `<svg xmlns="http://www.w3.org/2000/svg" width="480" height="180" viewBox="0 0 480 180">
<!-- Your SVG rendering logic -->
</svg>`;
},
};Import and register in src/templates/index.ts.
Available in src/templates/utils.ts:
truncate(text, maxLen)β Truncate text with ellipsisesc(text)β SVG/XML escapefetchImageAsBase64(url)β Convert image to base64
- Components: PascalCase (
CardPreview.tsx) - Utils/functions: camelCase (
parseYouTubeUrl) - File names: kebab-case (
card-renderer.ts) - Path alias:
@/*βsrc/* - API Routes: Edge Runtime
When creating an issue, please use the provided issue templates. Include:
- Steps to reproduce
- Expected vs actual behavior
- Theme/template/parameters used
- Screenshots (if possible)