[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-76271":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":15,"stars7d":16,"stars30d":17,"stars90d":15,"forks30d":15,"starsTrendScore":15,"compositeScore":18,"rankGlobal":10,"rankLanguage":10,"license":10,"archived":19,"fork":19,"defaultBranch":20,"hasWiki":21,"hasPages":19,"topics":22,"createdAt":10,"pushedAt":10,"updatedAt":35,"readmeContent":36,"aiSummary":37,"trendingCount":15,"starSnapshotCount":15,"syncStatus":38,"lastSyncTime":39,"discoverSource":40},76271,"spectral","charmlinn\u002Fspectral","charmlinn","Open-source self-hosted audio-reactive video editor. Browser preview and server-side export share the same PixiJS runtime.","",null,"TypeScript",130,13,19,0,8,35,3.44,false,"main",true,[23,24,25,26,27,28,29,30,31,32,33,34],"audio-visualization","bullmq","ffmpeg","music-visualizer","nextjs","opensource","pixi-js","pixijs","pixijs-v5","redis","self-hosted","specterr-alternative","2026-06-12 02:03:41","# Spectral\n\n> Audio-reactive video editor and rendering platform.\n\n[中文文档](docs\u002FREADME.zh-CN.md)\n\nSpectral is a monorepo for building audio-reactive visualizer videos. It combines a browser editor, canonical project documents, audio analysis, PixiJS preview rendering, Redis queues, object storage, an offline render runtime, and a background render worker.\n\n---\n\n## Preview\n\n![Spectral Home](docs\u002Fhome.png)\n\n![Spectral Editor](docs\u002Feditor.png)\n\n![Spectral Demo](docs\u002Fdemo.gif)\n\n## What Is Spectral?\n\nSpectral is an audio-reactive video editor and rendering platform. It is designed around one central rule: the browser preview and the backend renderer should consume the same project document and reuse as much render logic as possible.\n\nThe repository currently includes:\n\n- template-based project creation\n- My Videos project listing\n- browser-based realtime preview\n- media uploads for audio, images, videos, and logos\n- waveform and spectrum audio analysis\n- immutable project snapshots\n- mock JSON export for isolated renderer debugging\n- export job creation through the API\n- Redis\u002FBullMQ job dispatch\n- render worker job consumption\n- offline runtime rendering through Chromium\n- ffmpeg encoding and artifact upload\n- local PostgreSQL, Redis, and MinIO infrastructure\n\n## Tech Stack\n\n| Layer | Stack |\n| --- | --- |\n| Monorepo | pnpm workspaces, Turbo |\n| Web App | Next.js 16 App Router, React 19, TypeScript |\n| UI | Tailwind CSS v4, shadcn-style components, lucide-react |\n| State | Zustand stores |\n| Realtime Rendering | PixiJS, pixi-filters, chroma-js, fontfaceobserver |\n| Audio Analysis | Web Audio \u002F FFT, waveform and spectrum providers |\n| Database | PostgreSQL, Prisma 7 |\n| Queue | Redis, BullMQ |\n| Object Storage | Cloudflare R2-compatible API, MinIO for local development |\n| Worker | Node.js, tsx, Chromium DevTools Protocol, ffmpeg pipeline |\n| Env Loading | dotenvx |\n| Docker | Local compose for PostgreSQL, Redis, MinIO, and render worker |\n\n## Repository Layout\n\n```text\napps\u002F\n  web\u002F\n    Next.js frontend, API routes, editor, templates, My Videos, render bootstrap routes\n\n  render-worker\u002F\n    Background worker that consumes Redis jobs, loads render sessions, renders frames, and encodes videos\n\npackages\u002F\n  audio-analysis\u002F\n    Waveform and spectrum analysis, provider contracts, reusable analysis snapshots\n\n  db\u002F\n    Prisma client, repositories, preset import\u002Fseed utilities, data layer\n\n  editor-store\u002F\n    Zustand stores for project document, playback, preview, UI, and export state\n\n  media\u002F\n    R2\u002FMinIO adapter, signed uploads, object key conventions, media URL resolution\n\n  project-schema\u002F\n    Canonical VideoProject schema, normalization, and migration\n\n  queue\u002F\n    BullMQ connection, publisher, worker helpers, export job data contracts\n\n  render-core\u002F\n    Platform-independent frame\u002Ftime calculations, scene graph building, visibility, audio-driven values\n\n  render-runtime-browser\u002F\n    PixiJS render runtime shared by browser preview and offline worker rendering\n\n  render-session\u002F\n    Transport contract between the Web API and the render worker\n\n  render-encode\u002F\n    Encoding helpers for exported videos\n\n  timeline\u002F\n    Timeline UI primitives, playhead, waveform track, lyrics track\n\n  ui\u002F\n    Shared UI components\n\ninfra\u002Fdocker\u002F\n  compose.local.yml\n  compose.render-worker.local.yml\n  .env.example\n\nprisma\u002F\n  schema.prisma\n```\n\n## Architecture\n\n```mermaid\nflowchart LR\n  User[\"User\"] --> Web[\"Next.js Web App\"]\n  Web --> Store[\"Editor Store\"]\n  Store --> Runtime[\"Preview Runtime\"]\n  Runtime --> Pixi[\"PixiJS Scene\"]\n\n  Web --> API[\"API Routes\"]\n  API --> DB[\"PostgreSQL \u002F Prisma\"]\n  API --> Storage[\"R2 or MinIO\"]\n  API --> Redis[\"Redis \u002F BullMQ\"]\n\n  Redis --> Worker[\"Render Worker\"]\n  Worker --> Session[\"Render Session API\"]\n  Session --> API\n  Worker --> Offline[\"Offline Runtime Host\"]\n  Offline --> Chromium[\"Headless Chromium\"]\n  Chromium --> Frames[\"PNG Frames\"]\n  Frames --> Encode[\"ffmpeg Encode\"]\n  Encode --> Storage\n  Worker --> DB\n```\n\n### 1. Canonical VideoProject\n\n`@spectral\u002Fproject-schema` defines the canonical `VideoProject` document. It is the contract shared by the editor, API, database snapshots, browser preview, mock JSON export, render sessions, and backend worker rendering.\n\nIt covers:\n\n- viewport, aspect ratio, export resolution\n- backdrop media, reflection, filters, bounce, vignette\n- visualizer logo, wave circles, spectrum, particles\n- lyric segments\n- text layers\n- audio source, trim, gain, analysis id\n- export format, fps, duration\n\n### 2. Web App\n\n`apps\u002Fweb` contains the main product surface and the API service:\n\n- `\u002F` for templates\n- `\u002Fmy-videos` for project listing\n- `\u002Feditor\u002F[projectId]` for editing\n- `\u002Fapi\u002Fprojects` for project creation and listing\n- `\u002Fapi\u002Fassets\u002F*` for media uploads\n- `\u002Fapi\u002Faudio\u002F*` for audio analysis\n- `\u002Fapi\u002Fprojects\u002F[projectId]\u002Fexports` for export creation\n- `\u002Fapi\u002Finternal\u002Fexports\u002F*` for worker-only APIs\n- `\u002Frender\u002Fexport\u002F[exportJobId]\u002Fbootstrap` for render session bootstrap\n\nThe frontend owns interaction and state wiring. Rendering logic lives in shared runtime packages.\n\n### 3. Preview Runtime and Offline Runtime\n\n`@spectral\u002Frender-runtime-browser` serves two environments:\n\n- browser editor preview\n- worker-side offline runtime host\n\nThe goal is render parity. The preview and backend renderer should use the same PixiJS layer implementations wherever possible.\n\nImportant parts:\n\n- `createSpectralRuntimeSession`\n- preview stage bootstrap\n- render page bootstrap\n- offline runtime API\n- Pixi layers for backdrop, text, lyrics, particles, visualizer\n- media source tracking\n- audio analysis provider injection\n- frame capture API\n\n### 4. Render Worker\n\n`apps\u002Frender-worker` is an independent background service. It consumes Redis jobs and performs rendering outside the browser UI.\n\nWorker flow:\n\n1. consume export jobs from BullMQ\n2. fetch render sessions through internal Web APIs\n3. prepare a work directory and offline runtime host\n4. launch Chromium and load the offline runtime\n5. render frames and capture PNG output\n6. encode video with ffmpeg\n7. generate poster and preview artifacts\n8. upload artifacts to MinIO\u002FR2\n9. update ExportJob, ExportJobEvent, and RenderArtifact records\n\n### 5. API and Worker Boundary\n\nThe system keeps API and worker responsibilities separate:\n\n- Web API handles user requests, snapshots, export creation, and internal session endpoints\n- Queue handles asynchronous dispatch\n- Worker handles CPU\u002FChromium\u002Fffmpeg-heavy rendering\n- Storage handles media input and exported artifacts\n\nThis keeps the web app lightweight and allows render workers to scale independently.\n\n## Data Flows\n\n### Project Creation\n\n```text\nTemplate Page -> POST \u002Fapi\u002Fprojects -> Project + ProjectSnapshot -> \u002Feditor\u002F[projectId]\n```\n\n### Browser Preview\n\n```text\nVideoProject -> editor-store -> PreviewStage -> createSpectralRuntimeSession -> PixiJS canvas\n```\n\n### Media Upload\n\n```text\nRequest signed URL -> upload file to MinIO\u002FR2 -> complete asset -> VideoProject media source\n```\n\n### Audio Analysis\n\n```text\nAudio asset -> analysis API \u002F worker helper -> waveform + bass\u002Fwide spectrum -> analysis provider\n```\n\n### Export Job\n\n```text\nEditor export -> save snapshot -> create ExportJob -> enqueue Redis job -> render-worker consumes\n```\n\n### Backend Rendering\n\n```text\nWorker -> render session bootstrap -> offline runtime -> Chromium frame capture -> ffmpeg encode -> storage upload\n```\n\n## Local Development\n\n### 1. Requirements\n\n- Node.js `>= 20.18.0`\n- pnpm `10.6.0`\n- Docker Desktop\n- ffmpeg\n- Chromium or Chrome-compatible runtime\n\n### 2. Install Dependencies\n\n```bash\npnpm install\n```\n\n### 3. Prepare Environment Variables\n\nThe repo uses `dotenvx` to load `.env` and `apps\u002Fweb\u002F.env.local`.\n\nFor a new local environment:\n\n```bash\ncp infra\u002Fdocker\u002F.env.example infra\u002Fdocker\u002F.env\n```\n\nImportant groups:\n\n```text\nDATABASE_URL\nSHADOW_DATABASE_URL\n\nREDIS_URL\nREDIS_QUEUE_PREFIX\n\nWEB_BASE_URL\nINTERNAL_EXPORTS_TOKEN\n\nR2_BUCKET\nR2_ACCESS_KEY_ID\nR2_SECRET_ACCESS_KEY\nR2_ENDPOINT\nR2_PUBLIC_BASE_URL\nR2_FORCE_PATH_STYLE\n\nEXPORT_MAX_ATTEMPTS\nWORKER_CONCURRENCY\n```\n\n### 4. Start Local Infrastructure\n\n```bash\npnpm infra:up\n```\n\nThis starts:\n\n- PostgreSQL\n- Redis\n- MinIO\n\nCheck status:\n\n```bash\npnpm infra:ps\n```\n\nStop services:\n\n```bash\npnpm infra:down\n```\n\n### 5. Initialize Database\n\n```bash\npnpm db:generate\npnpm db:push\n```\n\nOr run:\n\n```bash\npnpm setup:local\n```\n\n### 6. Start Web App\n\n```bash\npnpm dev:web\n```\n\nDefault URL:\n\n```text\nhttp:\u002F\u002Flocalhost:3000\n```\n\nMain routes:\n\n```text\n\u002F             Templates\n\u002Fmy-videos    Project list\n\u002Feditor        Legacy open-project entry\n```\n\n### 7. Start Render Worker\n\nOpen another terminal:\n\n```bash\npnpm dev:worker\n```\n\nThis builds the offline runtime first and then starts the worker through dotenvx.\n\n### 8. Start Web and Worker Together\n\n```bash\npnpm dev:all\n```\n\n### 9. Smoke Export\n\nWhen both Web and Worker are running:\n\n```bash\npnpm smoke:export\n```\n\n## Common Commands\n\n```bash\npnpm dev:web          # Start Next.js web app\npnpm dev:worker       # Start render worker\npnpm dev:all          # Start web and worker\n\npnpm infra:up         # Start PostgreSQL \u002F Redis \u002F MinIO\npnpm infra:ps         # Inspect Docker services\npnpm infra:down       # Stop Docker services\n\npnpm db:generate      # Prisma generate\npnpm db:push          # Push schema to database\npnpm setup:local      # Local infra and DB setup\n\npnpm typecheck        # Typecheck all packages\npnpm lint             # Lint all packages\npnpm build            # Build all packages\npnpm smoke:export     # Local export smoke test\n```\n\n## Development Principles\n\n- Keep `VideoProject` as the single core document contract\n- Reuse the same runtime for preview and export whenever possible\n- Avoid stale rendering fallbacks in critical paths\n- Keep API routes thin; put real logic in services and repositories\n- Keep Web API and Worker as independent service boundaries\n- Optimize for local Docker development first; GPU is not required by default\n","Spectral 是一个开源的自托管音频响应视频编辑器。其核心功能包括基于浏览器的实时预览、媒体上传、波形和频谱音频分析、项目快照以及通过API创建导出任务等。技术上，Spectral 使用了Next.js构建Web应用界面，PixiJS进行实时渲染，并利用Redis\u002FBullMQ处理后台渲染任务队列，最终通过Chromium进行离线渲染与ffmpeg编码生成视频文件。此项目适用于需要将音乐可视化并与视频内容相结合的场景，如制作音乐视频、现场演出背景视觉效果或个人创意项目。",2,"2026-06-11 03:54:50","CREATED_QUERY"]