Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ VITE_APP_NAME=BeatDesign
VITE_APP_DESCRIPTION=The open-source, local-first AI canvas for image and video creation.
VITE_APP_LOGO=/logo.png
VITE_DEFAULT_LOCALE=en
VITE_GENERATION_PROVIDER=beatapi
GENERATION_PROVIDER=beatapi

# Local persistence
DATABASE_PROVIDER=sqlite
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/quality.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ jobs:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
# The MCP stdio probe exercises real Project queries, so CI needs the
# same local SQLite schema created by the documented quick-start flow.
- run: pnpm db:push
# The Vite build generates the gitignored Paraglide and TanStack Router
# artifacts that TypeScript needs in a clean checkout.
- run: pnpm build
Expand Down
8 changes: 8 additions & 0 deletions .mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"mcpServers": {
"beatdesign": {
"command": "pnpm",
"args": ["--silent", "mcp"]
}
}
}
41 changes: 37 additions & 4 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,59 @@ Projects
+ Home
+ Studio
+ Canvas
+ Editor
+ Assets
+ Generation history
+ Provider configuration
+ Storage configuration
```

Studio, Canvas, and Assets are three views over the same project, generation, and asset services. Switching modes never creates a second project or backend.
Studio, Canvas, Editor, and Assets are views over the same project, generation, asset, and history services. Switching modes never creates a second project or backend.

The shared product model is asset-first:

- A generation creates an `Asset`; it does not own a single UI placement.
- A Canvas node references an Asset, Generation, or Timeline.
- A Timeline clip pins a concrete Asset and never silently follows a Canvas generation's latest output.
- A Take is an alternate Asset for one clip; the original source remains recoverable.
- Canvas edges describe visual organization. Generation lineage describes real derivation and is stored separately.

## Runtime flow

The browser calls local `/api` routes. Server routes validate input and call the BeatAPI adapter. The adapter submits image/video generation tasks or the stable `/v1/video-analysis/tasks` workflow, then checks `/v1/tasks/:id`. Generation state and analysis text are stored locally, while provider result URLs are indexed as project assets.
The browser calls local `/api` routes. Server routes validate input and resolve a logical model through the active Generation Provider contract. BeatAPI is the built-in/default provider; forks can register another source-level provider without changing Canvas, Editor, MCP, or the asset-first request contract.

Provider credentials are read from environment variables or the local `config` table. Browser components never receive the raw API key.

Upload storage is a separate adapter boundary. File selection remains browser-local. A successful generation precheck creates a short-lived, one-time SQLite intent that binds the project, model, exact upload count, uploaded URLs, and final generation submission. Required references are promoted only after that point and immediately before task submission; they become project assets only after BeatAPI accepts the task. The built-in provider is fixed to the official `https://api.beatapi.io` endpoint. Official `BEATAPI_MANAGED_R2_*` secrets and self-hosted `R2_*` credentials are deliberately separate and never fall through to each other.

## Command boundary

UI actions, the local MCP server, and a future CLI call the same Command Kernel. The kernel owns validation and pure document operations for Canvas and Editor. Persistence boundaries remain responsible for revision checks, durable writes, and returning the authoritative document.

```text
UI / MCP / CLI
|
Command envelope + validation
|
Canvas / Editor / Generation commands
|
revision-checked project persistence
|
SQLite + project media files
```

MCP does not write SQLite directly or replace an entire Canvas or Timeline document. Its tools call `persistBeatDesignCommand` with a transport-controlled `origin=mcp`. The public UI route assigns `origin=ui` server-side and rejects an `origin` request field. UI-only timeline replacement exists for local autosave and undo/redo, remains revision-checked, and is rejected for MCP/CLI origins. Generation commands are asset-first and intentionally have no `placement` field; the server compiles provider media URLs from project-owned Asset IDs and the one-time generation intent before submission.

Canvas layout persistence is the deliberate exception on the UI side: drag, resize, viewport, and the complete visual arrangement are saved as a revision-checked snapshot. Semantic Canvas operations are also exposed through `canvas.apply`, and external agents must use those operations rather than snapshot replacement.

## Persistence

The SQLite/D1 schema contains ten tables:
The SQLite/D1 schema contains twelve tables:

- `project`
- `project_canvas_state`
- `project_timeline_state`
- `project_command_receipt`
- `project_workflow_state`
- `generation_history`
- `generation_upload_intent`
Expand All @@ -40,11 +71,13 @@ The SQLite/D1 schema contains ten tables:
- `project_asset_membership`
- `config`

`project_command_receipt` stores bounded, short-lived command results for retry idempotency and powers the current MCP history tool. It is not a permanent audit log; long-term Agent Activity still needs a separate durable event contract.

No user, session, role, order, subscription, payment, credit, API-key, ticket, or CMS table belongs in this repository.

## Model catalog

`src/core/effects/effect-registry.ts` is the canonical user-facing catalog. `src/core/adapters/beatapi-adapter.ts` maps that catalog to BeatAPI request bodies. Do not add a second database-backed model registry.
`src/core/effects/effect-registry.ts` is the canonical user-facing logical catalog. `src/core/generation-providers/` maps those logical IDs to provider bindings and adapters. `src/core/adapters/beatapi-adapter.ts` contains BeatAPI request mapping. Do not leak upstream effect IDs or field names into MCP tools, and do not add a second database-backed model registry.

## Deployment boundary

Expand Down
32 changes: 32 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Changelog

All notable changes to BeatDesign are documented in this file.

## [0.2.0] - 2026-08-30

### Added

- A local stdio MCP server with 20 Project, Asset, Canvas, Generation, and Editor tools.
- A shared Command Kernel with runtime schemas, revision checks, stable IDs, idempotent receipts, and project Asset validation.
- Canvas-to-Editor workflows: tail-frame extraction, continuation generation nodes, Timeline nodes, and multi-asset timeline creation.
- Local image, video, and audio import through both the UI and MCP.
- Image clips, audio tracks, non-destructive Takes, split/trim/move/delete, undo/redo, timeline diagnostics, and browser-native MP4 export.
- BeatAPI model capability discovery and asset-first generation contracts.
- Codex plugin packaging plus generic MCP configuration for Claude Code, Cursor, OpenCode, and other stdio hosts.

### Changed

- Canvas and Editor now check for Agent/MCP revisions every two seconds and whenever the page regains focus.
- Canvas rebases pending local layout edits onto newer Agent revisions instead of blocking visible MCP updates; snapshot restoration also removes stale shapes before rebuilding the current document.
- Editor autosave adopts the canonical saved document and ignores timestamp-only differences, preventing repeated save echoes from blocking MCP updates.
- Generated and imported media are persisted in project-owned local storage and indexed in SQLite.
- External Canvas media writes require project-owned Asset IDs, and local image/video/audio imports validate type and size before reading file contents.
- GitHub documentation now includes a product-first English/Chinese README and a BeatDesign release cover.

### Current boundaries

- Editor snapshots are semantic rather than pixel-rendered.
- MP4 export remains browser-driven and is not yet available as a headless MCP tool.
- Captions, transitions, speed controls, multiple named timelines, and native desktop packaging remain follow-up work.

[0.2.0]: https://github.com/BeatAPI/BeatDesign/releases/tag/v0.2.0
8 changes: 5 additions & 3 deletions PROVIDERS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Provider configuration

BeatAPI is the fixed built-in generation and analysis provider implemented by this repository. The upstream URL is intentionally fixed to `https://api.beatapi.io`; users only provide their own BeatAPI API key.
BeatAPI is the built-in and default generation/analysis provider. The official BeatAPI adapter keeps its upstream URL fixed to `https://api.beatapi.io`; users only provide their own BeatAPI API key.

Configure it in either place:

Expand All @@ -17,13 +17,15 @@ The adapter uses:
- `GET /v1/tasks/:id`
- `POST /v1/files` for supported reference files

Model support is defined in `src/core/effects/effect-registry.ts`, not discovered dynamically. This keeps Canvas and Studio behavior deterministic. When adding a model, update the registry, request mapping, media capability rules, and tests together.
User-facing model capabilities are defined in `src/core/effects/effect-registry.ts`. Provider bindings live in `src/core/generation-providers/`; MCP and UI use the logical model id and capability schema, not BeatAPI `effectId` or raw upstream fields.

Kling 2.6 and Kling 3.0 Motion Control are exposed as BeatAPI models. Each run requires exactly one character image and one MP4/MOV motion video uploaded through the connected BeatAPI account. The Workspace never asks users for a KIE key; BeatAPI owns the upstream provider route, billing, polling, and output persistence.

Video Analysis is exposed as a stable BeatAPI workflow with Standard and Deep depth controls. The Workspace uploads one MP4/MOV input, submits the analysis task, polls `GET /v1/tasks/:id`, and stores the returned report text and usage in the local project history. Provider-specific Gemini routing remains private to BeatAPI.

An API with a different request or polling contract still needs its own adapter. This repository does not ship placeholder KIE, Vidu, Evolink, Gemini, Fal, Replicate, or payment-provider integrations.
An API with a different request or polling contract needs its own adapter. Forks can register one in `src/config/generation-providers.ts`, bind only the logical models they support, and set server-side `GENERATION_PROVIDER=<id>`. BeatAPI is the default only when no custom provider is selected; an unknown configured id fails explicitly so it cannot accidentally submit a task to another provider. This repository does not ship placeholder KIE, Vidu, Evolink, Gemini, Fal, Replicate, or payment-provider integrations.

A custom provider definition owns adapter construction, readiness checks, parameter validation, model bindings, upstream model names, and upload paths. Provider credentials must stay server-side. Switching providers does not change Canvas nodes, Editor clips, Asset IDs, or MCP requests; each submitted task also records its provider/model identity so polling does not silently follow a later default-provider change.

## Storage

Expand Down
Loading
Loading