{"id":49455449,"url":"https://github.com/crisng95/flowboard","last_synced_at":"2026-05-23T07:04:39.442Z","repository":{"id":353827611,"uuid":"1216594612","full_name":"crisng95/flowboard","owner":"crisng95","description":"Flowboard — open-source infinite canvas for AI product videos. Drag nodes for model, product, scene, video — connect them, click Generate. Auto-prompts write themselves. Runs locally; powered by Google Flow + Claude CLI. ","archived":false,"fork":false,"pushed_at":"2026-05-21T16:48:34.000Z","size":33358,"stargazers_count":249,"open_issues_count":0,"forks_count":146,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-05-22T01:13:38.253Z","etag":null,"topics":["ai","claude-cli","google-flow","video"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/crisng95.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":null,"patreon":null,"open_collective":null,"ko_fi":"crisnguyen95","tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":null,"thanks_dev":null,"custom":null}},"created_at":"2026-04-21T03:57:17.000Z","updated_at":"2026-05-21T16:48:44.000Z","dependencies_parsed_at":null,"dependency_job_id":"4d87bd48-ce21-4921-885c-2595dd17b657","html_url":"https://github.com/crisng95/flowboard","commit_stats":null,"previous_names":["crisng95/flowboard"],"tags_count":29,"template":false,"template_full_name":null,"purl":"pkg:github/crisng95/flowboard","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crisng95%2Fflowboard","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crisng95%2Fflowboard/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crisng95%2Fflowboard/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crisng95%2Fflowboard/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/crisng95","download_url":"https://codeload.github.com/crisng95/flowboard/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crisng95%2Fflowboard/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33386079,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-23T04:15:53.637Z","status":"ssl_error","status_checked_at":"2026-05-23T04:15:53.242Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","claude-cli","google-flow","video"],"created_at":"2026-04-30T05:01:40.957Z","updated_at":"2026-05-23T07:04:39.436Z","avatar_url":"https://github.com/crisng95.png","language":"Python","funding_links":["https://ko-fi.com/crisnguyen95"],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/assets/logo-wordmark.svg\" alt=\"Flowboard\" width=\"480\" /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"#license\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-MIT-blue.svg\" alt=\"License: MIT\"/\u003e\u003c/a\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Python-3.11+-3776AB?logo=python\u0026logoColor=white\" alt=\"Python 3.11+\"/\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Node-20+-339933?logo=node.js\u0026logoColor=white\" alt=\"Node 20+\"/\u003e\n  \u003cimg src=\"https://img.shields.io/badge/FastAPI-0.115-009688?logo=fastapi\u0026logoColor=white\" alt=\"FastAPI\"/\u003e\n  \u003cimg src=\"https://img.shields.io/badge/React-18-61DAFB?logo=react\u0026logoColor=white\" alt=\"React 18\"/\u003e\n  \u003cimg src=\"https://img.shields.io/badge/TypeScript-strict-3178C6?logo=typescript\u0026logoColor=white\" alt=\"TypeScript\"/\u003e\n  \u003cimg src=\"https://img.shields.io/badge/React%20Flow-12-8A2BE2?logo=react\u0026logoColor=white\" alt=\"React Flow\"/\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Chrome-MV3-4285F4?logo=googlechrome\u0026logoColor=white\" alt=\"Chrome MV3\"/\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Veo%203.1-i2v-FF6F00?logo=google\u0026logoColor=white\" alt=\"Veo 3.1\"/\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Flow-Pro%20%2F%20Ultra%20only-EA4335?logo=google\u0026logoColor=white\" alt=\"Flow Pro / Ultra only\"/\u003e\n  \u003cimg src=\"https://img.shields.io/badge/LLM-Claude%20%C2%B7%20Gemini%20%C2%B7%20Codex-D97757\" alt=\"Claude / Gemini / OpenAI Codex\"/\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Tests-333%20passing-success?logo=pytest\u0026logoColor=white\" alt=\"333 passing\"/\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Status-personal%20local--only-orange\" alt=\"Status\"/\u003e\n\u003c/p\u003e\n\n---\n\n### ☕ Sponsor this project\n\n\u003ctable align=\"center\"\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\" width=\"50%\"\u003e\n      \u003ca href=\"docs/assets/sponsor-qr-vn.jpg\"\u003e\n        \u003cimg src=\"docs/assets/sponsor-qr-vn.jpg\" alt=\"Vietnam QR — MoMo / VietQR / napas247\" width=\"240\" /\u003e\n      \u003c/a\u003e\u003cbr/\u003e\n      \u003csub\u003e📱 \u003cb\u003eVietnam\u003c/b\u003e\u003cbr/\u003eMoMo · VietQR · napas247\u003c/sub\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\" width=\"50%\"\u003e\n      \u003ca href=\"docs/assets/sponsor-qr-binance.png\"\u003e\n        \u003cimg src=\"docs/assets/sponsor-qr-binance.png\" alt=\"Binance Pay QR — Cris Ng\" width=\"240\" /\u003e\n      \u003c/a\u003e\u003cbr/\u003e\n      \u003csub\u003e💰 \u003cb\u003eBinance Pay\u003c/b\u003e\u003cbr/\u003eCrypto / cross-border\u003c/sub\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003cp align=\"center\"\u003e\n  🌍 \u003cb\u003eInternational (card):\u003c/b\u003e\n  \u003ca href=\"https://ko-fi.com/crisnguyen95\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Ko--fi-Buy%20me%20a%20coffee-FF5E5B?logo=kofi\u0026logoColor=white\" alt=\"Ko-fi\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003csub\u003e\u003ci\u003e(yes — I moved this up here on purpose. Was afraid nobody scrolls past the badges 😅)\u003c/i\u003e\u003c/sub\u003e\n\u003c/p\u003e\n\n---\n\n\u003cp align=\"center\"\u003e\n  \u003cb\u003eA local-only, single-user infinite-canvas workspace for AI media workflows.\u003c/b\u003e\u003cbr/\u003e\n  Compose characters, products, scenes, and videos as a directed graph. Drive generation through a Chrome extension that proxies requests to Google Flow (Veo 3.1 / GEM_PIX_2).\u003cbr/\u003e\n  Every node is reusable, every edge is a real data-dependency, every variant is independently regenerable.\n\u003c/p\u003e\n\n\u003e **⚠ Hard requirements — read this before cloning:**\n\u003e\n\u003e 1. **Google Flow plan: `Pro` or `Ultra` only.** Veo 3.1 i2v + GEM_PIX_2\n\u003e    are gated to paid tiers. The free tier and trial accounts cannot\n\u003e    drive video generation, so Flowboard cannot work on them. Confirm\n\u003e    your plan at [labs.google/fx](https://labs.google/fx/tools/flow)\n\u003e    before installing.\n\u003e 2. **Chrome extension is mandatory.** All generation requests are\n\u003e    proxied through `extension/` (Chrome MV3) so the agent can ride\n\u003e    your authenticated Flow session + reCAPTCHA token. Without the\n\u003e    extension loaded and connected to `labs.google/fx/tools/flow`, the\n\u003e    `▶ Generate` button does nothing.\n\u003e 3. **One LLM CLI on `PATH` for auto-prompt / vision / planner.**\n\u003e    Flowboard ships a swappable provider layer — pick one in\n\u003e    `Settings → AI Providers`:\n\u003e\n\u003e    - **Claude Code** (default, recommended) —\n\u003e      [`@anthropic-ai/claude-code`](https://docs.claude.com/claude-code/install) ·\n\u003e      OAuth via your Claude subscription · fully tested in production.\n\u003e    - **Gemini CLI** — [`@google/gemini-cli`](https://github.com/google-gemini/gemini-cli) ·\n\u003e      OAuth via Google AI · tested live; ~15 s slower per call than\n\u003e      Claude due to subprocess cold-start.\n\u003e    - **OpenAI Codex** —\n\u003e      [`@openai/codex`](https://github.com/openai/codex) · OAuth via\n\u003e      ChatGPT Plus/Pro · provider class implemented + auto-detected\n\u003e      but **not yet smoke-tested end-to-end**; treat as beta.\n\u003e\n\u003e    Flowboard does not call any cloud LLM API directly — every\n\u003e    auto-prompt / vision / planner round-trip shells out to the CLI\n\u003e    you've connected, so the cost lives on your existing AI\n\u003e    subscription.\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"#why\"\u003eWhy\u003c/a\u003e ·\n  \u003ca href=\"#showcase\"\u003eShowcase\u003c/a\u003e ·\n  \u003ca href=\"#how-it-works\"\u003eHow it works\u003c/a\u003e ·\n  \u003ca href=\"#architecture\"\u003eArchitecture\u003c/a\u003e ·\n  \u003ca href=\"#quickstart\"\u003eQuickstart\u003c/a\u003e ·\n  \u003ca href=\"#features\"\u003eFeatures\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## Demo\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"docs/assets/flowboard-intro.mp4\"\u003e\n    \u003cimg src=\"docs/assets/flowboard-intro.gif\" alt=\"Flowboard end-to-end walkthrough\" width=\"720\" /\u003e\n  \u003c/a\u003e\u003cbr/\u003e\n  \u003csub\u003eEnd-to-end walkthrough — refs → composed image → multi-source i2v. Click for full-quality MP4.\u003c/sub\u003e\n\u003c/p\u003e\n\n---\n\n## Why\n\nE-commerce video creative is repetitive: same model, same product, many\nscenes, many short clips. Building it by hand in a generic Veo / Imagen UI\nmeans re-uploading the same character ref every time, re-typing the same\n\"young Korean woman in the cream cropped tee\" prompt every time, and\nlosing track of which 4-variant generation came from which source still.\n\nFlowboard treats the workflow as a graph:\n\n- **Refs are nodes** — upload a character once, upload a product once.\n- **Composed shots are nodes** — `(Character) + (Product) → Image`.\n- **Videos are nodes** — `(Image) → Video` via i2v, with multi-source batch\n  so a 4-variant image spawns 4 videos in one click.\n- **Prompts are auto-synthesised** from upstream context (the configured\n  LLM CLI's vision pass describes each ref → a downstream generator\n  gets the brief spliced into a fashion-editorial prompt). Switch\n  provider in `Settings → AI Providers`; defaults to Claude Code.\n\nThe result: one source-of-truth canvas for an entire campaign.\n\n---\n\n## Showcase\n\nThe graph below is a real export from a board in this project — two ref\nnodes (`#op4v` product, `#0p1u` model) feeding three scene compositions\nand three downstream videos. Every image and clip below was rendered by\nthe pipeline in this repo.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/assets/canvas-overview.png\" alt=\"Flowboard canvas — real board export\" width=\"100%\" /\u003e\u003cbr/\u003e\n  \u003csub\u003eThe actual canvas in the app: 2 refs (left) → studio composition \u003ccode\u003e#qowj\u003c/code\u003e (centre) → scene-variant images (autumn / Seoul / Myeongdong) → 3 video nodes with 4-up i2v variant grids (right).\u003c/sub\u003e\n\u003c/p\u003e\n\n```mermaid\ngraph LR\n    A[#op4v Visual asset\u003cbr/\u003ecream The Famous tee]:::ref\n    B[#0p1u Character\u003cbr/\u003eKorean female model]:::ref\n    C[#qowj Image\u003cbr/\u003estudio composition]\n    D[#nkov Image\u003cbr/\u003eautumn road · 4 variants]\n    E[#l7qd Image\u003cbr/\u003eSeoul street · 4 variants]\n    F[#xky5 Image\u003cbr/\u003eMyeongdong dusk · 4 variants]\n    G[#sncj Video\u003cbr/\u003estudio motion]:::video\n    H[#bwr4 Video\u003cbr/\u003eautumn motion · 4 variants]:::video\n    I[#uv1p Video\u003cbr/\u003eSeoul motion · 4 variants]:::video\n\n    A --\u003e C\n    B --\u003e C\n    C --\u003e D\n    C --\u003e E\n    C --\u003e F\n    D --\u003e H\n    E --\u003e I\n    C --\u003e G\n\n    classDef ref fill:#1d4d2e,stroke:#5db97a,color:#fff;\n    classDef video fill:#2b1d4d,stroke:#7c5cff,color:#fff;\n```\n\n### Layer 0 — references (one-time setup)\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\" width=\"50%\"\u003e\n  \u003cimg src=\"docs/assets/visual-asset-tshirt.webp\" alt=\"Visual asset — t-shirt\" width=\"320\" /\u003e\u003cbr/\u003e\n  \u003csub\u003e\u003cb\u003e#op4v · Visual asset\u003c/b\u003e\u003cbr/\u003eCropped boxy short-sleeve tee in cream ribbed cotton with brown \"The Famous\" centre-chest embroidery.\u003c/sub\u003e\n\u003c/td\u003e\n\u003ctd align=\"center\" width=\"50%\"\u003e\n  \u003cimg src=\"docs/assets/character-model.jpg\" alt=\"Character — Korean female model\" width=\"320\" /\u003e\u003cbr/\u003e\n  \u003csub\u003e\u003cb\u003e#0p1u · Character\u003c/b\u003e\u003cbr/\u003eStudio portrait headshot, neutral closed-mouth expression — generated from gender + nationality presets, anchored for downstream identity consistency.\u003c/sub\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n### Layer 1 — composed studio shot\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/assets/composition-base.jpg\" alt=\"Image #qowj — composition\" width=\"640\" /\u003e\u003cbr/\u003e\n  \u003csub\u003e\u003cb\u003e#qowj · Image\u003c/b\u003e — auto-prompt from upstream briefs: \"Editorial photo, model engaging the camera with direct eye contact, both hands tucked in pockets, knees-up framing, neutral studio backdrop.\" 4 pose-distinct variants generated in one batch.\u003c/sub\u003e\n\u003c/p\u003e\n\n### Layer 2 — environment-aware variants\n\nThe synth detects scene context from each new image's brief and switches\nmotion vocabulary (street / studio / café / outdoor). Same character + same\nproduct, three different worlds:\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\" width=\"33%\"\u003e\n  \u003cimg src=\"docs/assets/composition-autumn.jpg\" alt=\"Autumn variant\" width=\"280\" /\u003e\u003cbr/\u003e\n  \u003csub\u003e\u003cb\u003e#nkov\u003c/b\u003e · autumn mountain road, traditional Korean pavilion, red maple foliage\u003c/sub\u003e\n\u003c/td\u003e\n\u003ctd align=\"center\" width=\"33%\"\u003e\n  \u003cimg src=\"docs/assets/composition-seoul-street.jpg\" alt=\"Seoul street\" width=\"280\" /\u003e\u003cbr/\u003e\n  \u003csub\u003e\u003cb\u003e#l7qd\u003c/b\u003e · Seoul street, food stalls, Korean signage\u003c/sub\u003e\n\u003c/td\u003e\n\u003ctd align=\"center\" width=\"33%\"\u003e\n  \u003cimg src=\"docs/assets/composition-myeongdong.jpg\" alt=\"Myeongdong dusk\" width=\"280\" /\u003e\u003cbr/\u003e\n  \u003csub\u003e\u003cb\u003e#xky5\u003c/b\u003e · Myeongdong dusk, red-canopied stalls, Olive Young signage\u003c/sub\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n### Layer 3 — image-to-video (Veo 3.1 i2v)\n\nCamera is locked-off (e-commerce default — keeps the product fully framed\nthe whole clip); the model performs a **time-coded 2–3 beat editorial\npose-shift** within the 8 seconds. (GitHub renders MP4 inline only when\nhosted on its CDN, so we ship looping GIFs in the README — full-quality\nMP4s live in [`docs/assets/`](docs/assets/).)\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\" width=\"33%\"\u003e\n  \u003cimg src=\"docs/assets/video-base.gif\" alt=\"Studio motion video\" width=\"280\" /\u003e\u003cbr/\u003e\n  \u003csub\u003e\u003cb\u003e#sncj\u003c/b\u003e · studio motion · half-step → glance → hair-tuck\u003cbr/\u003e\u003ca href=\"docs/assets/video-base.mp4\"\u003e▶ MP4\u003c/a\u003e\u003c/sub\u003e\n\u003c/td\u003e\n\u003ctd align=\"center\" width=\"33%\"\u003e\n  \u003cimg src=\"docs/assets/video-autumn.gif\" alt=\"Autumn motion video\" width=\"280\" /\u003e\u003cbr/\u003e\n  \u003csub\u003e\u003cb\u003e#bwr4\u003c/b\u003e · autumn road · pivot → pocket → camera smirk\u003cbr/\u003e\u003ca href=\"docs/assets/video-autumn.mp4\"\u003e▶ MP4\u003c/a\u003e\u003c/sub\u003e\n\u003c/td\u003e\n\u003ctd align=\"center\" width=\"33%\"\u003e\n  \u003cimg src=\"docs/assets/video-seoul.gif\" alt=\"Seoul motion video\" width=\"280\" /\u003e\u003cbr/\u003e\n  \u003csub\u003e\u003cb\u003e#uv1p\u003c/b\u003e · Seoul daylight · half-step → over-shoulder glance → hand in pocket\u003cbr/\u003e\u003ca href=\"docs/assets/video-seoul.mp4\"\u003e▶ MP4\u003c/a\u003e\u003c/sub\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n\u003e All three videos were synthesised from a single click each: the\n\u003e auto-prompt reads the upstream image's `aiBrief`, picks scene-matched\n\u003e motion vocab, and locks the camera to keep the cropped tee in frame for\n\u003e the full clip.\n\n---\n\n## How it works\n\nThe mental model — read this once and the rest of the UI is obvious.\n\n### 1. Refs are nodes you set up once\n\nTwo node types act as **anchors** for the rest of the graph:\n\n| Node | Purpose | How to populate |\n|------|---------|-----------------|\n| **Character** | A person whose identity you want to keep stable across many shots. | Generate from gender + nationality presets (Nam / Nữ × VN / JP / KR / CN / TH / US / FR), or upload your own portrait. The synth hard-anchors it to a frontal, closed-mouth, neutral-expression studio headshot — Veo i2v can't keep identity stable from a smiling-with-teeth source. |\n| **Visual asset** | A product / garment / object that needs to appear in scenes. | Upload (file or URL) or generate from a prompt. Inline `Refine` button uses Flow's `edit_image` to iterate without losing the original. |\n\nEach ref node gets an `aiBrief` automatically (the configured Vision\nprovider describes the image once, persists the description on the\nnode). Downstream auto-prompt walks upstream and pulls these briefs as\ncontext. Toggle off in `Settings → AI Providers` if you'd rather\nsynthesise from typed prompts.\n\n### 2. Composition is just connecting nodes\n\nTo build a composed image, drop an **Image** node and wire upstream refs\ninto it. Click `Generate` (or just press Enter with the prompt empty):\n\n```\n[Character #ujr1]  ───►\n                        \\\n[Visual asset #sqpi] ───► [Image #target]\n                        /\n[Image #other-ref] ───►\n```\n\nAll upstream `mediaId`s are fed to Flow as `IMAGE_INPUT_TYPE_REFERENCE`\ninputs. The auto-prompt synth (`/api/prompt/auto-batch`) asks the\nconfigured LLM to compose **N pose-distinct prompts** in a single\ncall when you ask for multiple variants — so 4 variants don't all\ncollapse to the same \"hand-on-hip\" stance. The prompt template is fashion-editorial style:\ndirect gaze, neutral closed-mouth, three-quarter angle, hand gesturing\ntoward the garment, knees-up framing.\n\n### 3. Image → Video via Veo i2v\n\nA **Video** node takes a single upstream Image. Connect it, click\n`Generate`, pick:\n\n- **Camera** = `Static` (default, e-commerce-safe — locked-off frame, no\n  zoom or pan, product never crops out) or `Dynamic` (synth picks\n  subtle dolly / pan based on scene).\n- **Source variants** = checkbox per upstream variant + `All / None`\n  bulk action. If the upstream image has 4 variants and you tick all 4,\n  the dispatcher batches **one i2v op per variant** in a single Flow\n  call — 4 source stills → 4 distinct videos.\n\nThe motion synth uses time-coded beats (`0–3s: …`, `3–6s: …`, `6–8s: …`)\nso the model performs an editorial pose-shift sequence inside the 8 s\nclip — never a frozen statue, never an open-mouth smile.\n\n### 4. Auto-prompt is environment-aware\n\nThe synth reads the source still's `aiBrief` and switches motion\nvocabulary based on detected scene:\n\n| Scene type | Motion vocab |\n|------------|-------------|\n| Studio / plain backdrop | hand-on-hip, brush sleeve, head tilt, engage camera |\n| Street / city / sidewalk | half-step forward, hair tuck, glance over shoulder, hand in pocket, smirk |\n| Café / interior | sip from cup, lean back, glance toward window |\n| Beach / nature / outdoor | hair flutter in breeze, slow exhale, look toward horizon |\n\nA studio shot gets editorial poses; a NYC-street shot gets walk-and-glance\nmotion. No code branches — the LLM detects the keyword and picks the\nmatching vocab from the system prompt.\n\n---\n\n## Architecture\n\n```\n┌──────────────────────┐    ┌────────────────────┐    ┌──────────────────────┐\n│  Chrome MV3 ext      │◄───┤  FastAPI agent     ├───►│  SQLite (storage/)   │\n│  - content script    │ WS │  127.0.0.1:8101    │    │  Board, Node, Edge,  │\n│  - injected MAIN     │ ws │  + worker queue    │    │  Request, Asset,     │\n│  - CDN URL allow     │9223│  + WS server :9223 │    │  Plan, ChatMessage,  │\n│  - Captcha bridge    │    │  + LLM CLI bridge  │    │  BoardFlowProject    │\n└──────────────────────┘    └─────────┬──────────┘    └──────────────────────┘\n        ▲                             │\n        │                             ▼\n        │                   ┌────────────────────┐\n        └───── Google Flow  │  React + Vite      │\n              labs.google   │  ReactFlow canvas  │\n              (i2v / image) │  Zustand store     │\n                            │  127.0.0.1:5173    │\n                            └────────────────────┘\n```\n\n- **Frontend** — Vite + React 18 + ReactFlow 12 + Zustand 5 + TypeScript\n  strict. Renders the infinite canvas, dialogs, sidebars. No direct\n  calls to Google Flow.\n- **Agent** — FastAPI + SQLModel + SQLite. Owns the board state, runs\n  an in-process worker queue that proxies all generation requests\n  through the extension, and shells out to the configured LLM CLI\n  (Claude / Gemini / Codex — see *AI Providers* below) for vision +\n  auto-prompt + planner synthesis.\n- **Extension** — Chrome MV3. Lives on `labs.google/fx/tools/flow`,\n  intercepts Flow's API calls (multimodal-fetch in MAIN world for the\n  reCAPTCHA token), proxies them over a localhost WebSocket so the\n  agent never has to touch the browser cookie jar directly.\n- **Storage** — local-only. SQLite for graph + history, a\n  `storage/media/` folder for cached image / video bytes (lazy-fetched\n  from Flow's signed CDN URLs and re-served from the agent so they\n  outlive the 1-hour signed URL TTL).\n\n---\n\n## Quickstart\n\n### Requirements\n\n| Dependency | Why |\n|------------|-----|\n| **Python 3.11** | Agent runtime (FastAPI + SQLModel) |\n| **Node 20+** | Frontend dev server (Vite) |\n| **Chrome / Chromium** | **Mandatory** — hosts the MV3 extension that proxies every Google Flow API call. The agent has zero direct path to Flow without it. |\n| **One LLM CLI** on `PATH` | Vision describe + auto-prompt + planner. Pick one — defaults to **Claude Code** ([`@anthropic-ai/claude-code`](https://docs.claude.com/claude-code/install)); also supports **Gemini CLI** ([`@google/gemini-cli`](https://github.com/google-gemini/gemini-cli)) and **OpenAI Codex** ([`@openai/codex`](https://github.com/openai/codex), provider implemented but not yet smoke-tested). All use OAuth against your existing AI subscription — no API key needed. |\n| **Google Flow `Pro` or `Ultra` plan** at [`labs.google/fx/tools/flow`](https://labs.google/fx/tools/flow) | **Free tier and trial accounts will not work.** Veo 3.1 i2v + GEM_PIX_2 image gen are gated to paid plans. |\n\n\u003e **Windows:** Use [WSL2](https://learn.microsoft.com/en-us/windows/wsl/install). All commands assume a Unix shell.\n\n### One-line setup (optional)\n\nIf you have `make` installed, the repo ships shortcut targets that wrap\nSteps 2 + 3:\n\n```bash\nmake install        # agent venv + frontend deps (uses uv if available, else pip)\nmake install-dev    # same, but adds ruff + pytest extras\nmake update         # upgrade agent + frontend deps in place\nmake agent          # run FastAPI on :8101\nmake frontend       # run Vite on :5173\n```\n\n`uv` is auto-detected (~10× faster installs). Install it once with\n`curl -LsSf https://astral.sh/uv/install.sh | sh`, or skip it and the\nMakefile falls back to stdlib `venv` + `pip`. Step 1 (loading the Chrome\nextension) still has to be done manually.\n\n### Step 1 — load the Chrome extension\n\n```bash\ngit clone https://github.com/\u003cyour-fork\u003e/flowboard.git\ncd flowboard\n```\n\n1. Open `chrome://extensions/` → enable **Developer mode** (top-right).\n2. Click **Load unpacked** → pick the `extension/` folder in this repo.\n3. Open a tab to \u003chttps://labs.google/fx/tools/flow\u003e and sign in.\n4. The extension's icon should turn coloured once it captures a fresh\n   Flow auth token (~5 s).\n\n### Step 2 — start the agent\n\n```bash\ncd agent\npython3.11 -m venv .venv\n.venv/bin/pip install -r requirements.txt\n\n# `--timeout-graceful-shutdown 2` keeps `--reload` snappy when you save\n# a Python file — without it, uvicorn waits forever for the WS to drain.\n.venv/bin/uvicorn flowboard.main:app --reload --port 8101 \\\n  --timeout-graceful-shutdown 2\n```\n\nSmoke-test:\n\n```bash\ncurl http://127.0.0.1:8101/api/health\n# {\"ok\":true,\"extension_connected\":true,\"ws_stats\":{\"connected\":true,\"flow_key_present\":true,...}}\n```\n\n### Step 3 — start the frontend\n\n```bash\ncd frontend\nnpm install\nnpm run dev\n# → http://localhost:5173\n```\n\nOpen the URL. The first board (\"Untitled\") auto-creates if the DB is\nempty. Add a Character node, generate it, drop a Visual asset, drop an\nImage, wire them up, click **▶ Generate** — the full demo above is\nabout 15 minutes of clicking.\n\n### Run tests\n\n```bash\n# Agent\ncd agent \u0026\u0026 .venv/bin/python -m pytest -q\n# 333 passed\n\n# Frontend\ncd frontend \u0026\u0026 npx tsc -p . --noEmit \u0026\u0026 npx vite build\n```\n\n---\n\n## Features\n\n### Ref-style nodes\n\n- **Character** — generate via gender + nationality preset chips, or\n  upload your own headshot. Hard-anchored to a frontal, closed-mouth,\n  neutral-expression portrait so Veo i2v keeps identity stable across\n  every downstream clip.\n- **Visual asset** — upload (file / URL) or generate. Refine in-place\n  with a different prompt (Flow `edit_image`, BASE_IMAGE preserved,\n  optional reference list).\n\n### Composition nodes\n\n- **Image** — multi-ref aware. Connect any number of upstream\n  characters, visual assets, or other images; all of them flow in as\n  Flow's `IMAGE_INPUT_TYPE_REFERENCE` inputs.\n  - 1–4 variants per gen, each with its own pose-distinct prompt\n    (the LLM rotates through an 8-stance pool per variant — never two\n    \"hand-on-hip\" variants in the same gen).\n  - Default aspect ratio inherits from upstream node; mismatched\n    upstream aspects fall back to 9:16.\n- **Storyboard** — sequenced 1–8 narrative shots in one node. The\n  planner LLM emits per-beat prompts AND a continuity tree: each beat\n  declares whether it's a fresh root (`gen_image`) or continues from\n  an earlier beat (`edit_image` from that beat's mediaId). Roots\n  dispatch in parallel batches of 4; continuations BFS through the\n  tree, siblings parallel. Refs from upstream edges apply to every\n  shot. Failed shots stay `partial` and can be retried per-tile —\n  blocked descendants surface a 🔒 until their parent is retried.\n  Useful for unbox → try-on → going-out arcs, scene chains, and\n  e-commerce shot lists.\n- **Video** — image-to-video via Veo. **Multi-source i2v**: a 4-variant\n  upstream image dispatches a single batch with one item per variant →\n  one video per source. Or pick a subset (toggleable thumbnails +\n  All / None bulk action).\n  - Camera = `Static` (locked-off, e-commerce default) or `Dynamic`\n    (synth picks dolly / pan / micro-shift to fit the scene).\n  - Motion synth uses time-coded beats so the model performs an\n    editorial 2–3 pose-shift sequence inside the 8s clip — never a\n    frozen statue.\n\n### Auto-prompt synthesis\n\n- Vision describes each new asset (configured CLI's multimodal\n  attachment path — `@\u003cpath\u003e` for Claude / Gemini, `--image` for Codex\n  when available) → saved as `aiBrief` on the node.\n- Downstream gen with empty prompt → `/api/prompt/auto` walks upstream\n  edges, gathers briefs, asks the configured LLM to compose a prompt\n  that matches the scene + showcases the product.\n- For multi-variant gens, `/api/prompt/auto-batch` returns N\n  pose-distinct prompts in a single LLM call.\n- **Vision toggle** in `Settings → AI Providers`: when OFF, the\n  synthesiser falls back to each upstream node's typed `prompt`\n  instead of a vision-derived brief. Manual upload paths still run\n  vision automatically (the user explicitly added bytes) — only the\n  gen-completion auto-brief is gated.\n\n### AI Providers (multi-LLM)\n\nA **🤖 Provider** chip in the top-right toolbar opens a dialog where\nyou switch which LLM powers Flowboard. One provider serves all three\nfeatures (Auto-Prompt / Vision / Planner) — switching is one decision,\nnot three. Per-feature test buttons run a small ping per feature and\ngate the **Apply changes** button until all three pass green, so you\nnever apply a switch that's silently broken.\n\n| Provider | Auth | Status |\n|---|---|---|\n| **Claude Code** | OAuth via `claude` CLI · Anthropic browser sign-in | ✅ Default · production-tested |\n| **Gemini CLI** | OAuth via `gemini` CLI · Google AI Ultra plan | ✅ Tested · ~15 s slower than Claude |\n| **OpenAI Codex** | OAuth via `codex` CLI · ChatGPT Plus/Pro | ⚠ Provider implemented but not yet smoke-tested |\n\nBackend keeps a Grok REST provider class for power users who edit\n`~/.flowboard/secrets.json` directly, but the UI doesn't surface it\nbecause xAI hasn't shipped an end-user CLI.\n\n### Activity feed\n\nA **🔔 bell** sits in the toolbar next to the AI Provider chip. Click\nit to see every backend operation in DESC order: gen image / gen\nvideo / edit image / auto-prompt / vision / planner — each with its\nstatus pill (✓ done · ⟳ running · ✗ failed) and how long it ran. Click\na row to open a detail modal with the full input params, output\nresult, and error JSON (with copy buttons), so you can diagnose a\nfailed gen without tailing agent logs.\n\nThe bell badge counts running + recently-failed-unread items, with a\nred tint when any failure is unread. Polling is 5 s while the dropdown\nis open, 30 s while closed, and pauses when the tab is backgrounded.\n\n### Workflow ergonomics\n\n- **Drop-add popover** — drag an edge into empty canvas, popover at the\n  drop point with `Image` / `Video` quick-add → new node + auto-wired\n  edge.\n- **Easy edge editing** — click an edge to select (accent ring + glow),\n  Backspace / Delete to remove. 24 px transparent hit-slop so edges are\n  forgiving to grab.\n- **Clone variant** — `New variant +` in the result viewer creates a\n  sibling node with identical upstream connections, prefills the\n  prompt, opens the gen dialog.\n- **Project sidebar** — multiple boards on the same agent, each with\n  its own Flow project mapping. Rename / delete with cascade (clears\n  all child rows: nodes, edges, requests, assets, plans, runs).\n\n---\n\n## Repo layout\n\n```\nagent/                  FastAPI service (Python 3.11)\n  flowboard/\n    routes/             HTTP endpoints (boards, nodes, edges, requests,\n                        upload, vision, prompt, plans, llm, activity, …)\n    services/           Flow SDK, prompt synth, vision describe,\n                        pipeline executor, activity logger\n      llm/              Multi-LLM provider layer (registry, secrets,\n                        Claude / Gemini / OpenAI Codex / Grok)\n      claude_cli.py     Subprocess detail behind ClaudeProvider\n    worker/             In-process queue (gen_image, gen_video,\n                        edit_image, upload_image)\n    db/                 SQLModel definitions\n  tests/                333+ pytest tests\n\nfrontend/               Vite + React + ReactFlow\n  src/\n    canvas/             Board.tsx, NodeCard.tsx, AddNodePalette.tsx\n    components/\n      activity/         ActivityBell + dropdown + detail modal\n      settings/         AiProvidersSection + ProviderCard + setup modal\n      AiProviderBadge.tsx · AiProviderDialog.tsx · GenerationDialog · ResultViewer · ProjectSidebar · ChatSidebar · Toolbar · Toaster\n    store/              Zustand: board, generation, pipeline, settings\n    api/                client.ts, autoBrief.ts\n\nextension/              Chrome MV3 (content script + injected MAIN)\ndocs/                   Static assets (this README, screenshots, demo media)\nstorage/                Local cache + SQLite (gitignored)\n```\n\n---\n\n## Status\n\nPersonal local-only tool. **333 / 333 tests passing** (agent), tsc\nclean (frontend). Caveats:\n\n- ⚠ **Google Flow plan must be `Pro` or `Ultra`.** Free tier and trial\n  accounts have no access to Veo 3.1 i2v / GEM_PIX_2 — every generation\n  call will fail.\n- ⚠ **Chrome extension must be loaded and connected.** The agent does\n  not talk to Flow directly — all i2v / image / edit requests are\n  proxied through `extension/` over a localhost WebSocket. No\n  extension → no generation.\n- ⚠ HMAC-secured WS (`X-Callback-Secret` per agent boot) — single\n  loopback only, not multi-user.\n- ⚠ Google Flow rate limits still apply within your paid tier.\n- ⚠ Veo / Imagen content filters\n  (`PUBLIC_ERROR_PROMINENT_PEOPLE_FILTER_FAILED`,\n  `PUBLIC_ERROR_AUDIO_FILTERED`) — surfaced verbatim in the activity\n  feed + failed-request error so the user can diagnose / iterate.\n- ⚠ Auto-prompt + vision + planner require **one** LLM CLI on `PATH`\n  (Claude Code recommended; Gemini CLI tested; OpenAI Codex provider\n  implemented but not yet smoke-tested). Without any CLI, the\n  `Generate` button still works if you type your own prompt — only\n  the auto-prompt-from-empty path is unavailable.\n\n## Related\n\n- [`crisng95/flowkit`](https://github.com/crisng95/flowkit) — the same\n  Chrome-extension-bridge approach to Google Flow, but for **YouTube\n  story videos** (multi-scene, narration, thumbnails). Flowboard\n  borrows the bridge architecture.\n\n## License\n\nMIT (proposed — license file pending).\n\n---\n\n## Credits\n\nGenerated media in this README was produced through the pipeline using\n[Google Flow](https://labs.google/flow). Auto-prompt + vision synthesis\ndefaults to [Claude](https://claude.ai) via the local CLI; multi-LLM\nsupport adds Google's [Gemini CLI](https://github.com/google-gemini/gemini-cli)\nand OpenAI's [Codex CLI](https://github.com/openai/codex) as alternative\nproviders — pick one in `Settings → AI Providers`.\n\n---\n\n## Community \u0026 Support\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.facebook.com/groups/flowkit.flowboard.community\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Join%20the%20Community-FlowKit%20%26%20Flowboard%20on%20Facebook-1877F2?style=for-the-badge\u0026logo=facebook\u0026logoColor=white\" alt=\"Join the FlowKit \u0026 Flowboard Facebook Group\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\nThe shared community for both **FlowKit** and **Flowboard**. Drop in to:\n\n- Post the shots and clips you've generated\n- Share node-graph patterns, vibe presets, and prompt recipes that work for you\n- Ask for help when an output isn't matching what you imagined\n- Request features and report bugs you've hit in the wild\n- Trade tips on Google Flow plan limits, Veo i2v behaviour, and LLM CLI setup (Claude / Gemini / Codex)\n\n→ **[facebook.com/groups/flowkit.flowboard.community](https://www.facebook.com/groups/flowkit.flowboard.community)**\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrisng95%2Fflowboard","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcrisng95%2Fflowboard","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrisng95%2Fflowboard/lists"}