readme: show the Cutting Room - hero screenshots + gallery section

'What it looks like' section right under the intro: a clean full-workspace
hero shot plus Composer and Engine Settings side by side, generated from
the mocked tour demo (no ComfyUI/GPU needed) by a new
tools/showcase/capture_clean.mjs (npm run capture:clean) - same scaffolding
as capture.mjs but with the tour overlay stripped, so shots are undimmed
and card-free. Images committed under docs/images/.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
digital-garbage
2026-07-02 07:01:30 +03:00
co-authored by Claude Fable 5
parent 78b1d001c9
commit 08333b6958
6 changed files with 100 additions and 1 deletions
+12
View File
@@ -13,6 +13,18 @@ A set of ComfyUI nodes for experimenting with video generation workflows based o
>
> With this said - FunPack is provided "as is". Stable, uninterrupted work is NOT guaranteed even on main branch. But that doesn't mean bugs won't be fixed - you are free to file a bug report and I will most likely fix it in the nearest time.
## What it looks like
FunPack 3.x ships the **Cutting Room** - a full non-linear video editor living in your browser, inside ComfyUI. A real timeline with per-scene prompts, ratings and audio lanes, a program monitor, a media bin, and one-click generation driving FunPack Studio + the Scene Chain Sampler - no graph wiring required.
![FunPack Cutting Room - timeline, preview monitor, media bin, and scene inspector](docs/images/cutting-room.png)
| The Composer - global prompt, shortcuts, split markers, `$variables` | Engine Settings - Studio + Chain Sampler knobs without touching a graph |
| --- | --- |
| ![Composer window](docs/images/composer.png) | ![Engine Settings dialog](docs/images/engine-settings.png) |
Want a guided look at every panel? Open the editor and press **Help ▸ Welcome tour** - the same tour also auto-generates a full annotated gallery and walkthrough video via [`tools/showcase`](tools/showcase).
## Dev and other non-main branches
The `dev` branch is intended for testing unfinished changes, implementing new logic and basically, flipping everything just because I can. It can be broken, renamed, or changed without warning.
Binary file not shown.

After

Width:  |  Height:  |  Size: 495 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 688 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 KiB

+86
View File
@@ -0,0 +1,86 @@
// Clean (no tour card, no spotlight dim) hero shots of the Cutting Room, using the
// same ?mode=tour mocked demo boot as capture.mjs — no ComfyUI, no models, no GPU.
// Output: out/hero-*.png. Run after capture.mjs (or standalone): `npm run capture:clean`.
import { chromium } from "playwright";
import http from "node:http";
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const FRONTEND = path.resolve(__dirname, "../../movie_editor/frontend");
const OUT = path.resolve(__dirname, "out");
const VIEW = { width: 1440, height: 900 };
const MIME = {
".html": "text/html", ".js": "text/javascript", ".css": "text/css",
".json": "application/json", ".svg": "image/svg+xml", ".png": "image/png",
".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif",
".woff": "font/woff", ".woff2": "font/woff2", ".ttf": "font/ttf", ".map": "application/json",
};
function serve(dir) {
const server = http.createServer((req, res) => {
const urlPath = decodeURIComponent((req.url || "/").split("?")[0]);
const fp = path.normalize(path.join(dir, urlPath === "/" ? "/index.html" : urlPath));
if (!fp.startsWith(dir)) { res.writeHead(403); return res.end("forbidden"); }
fs.readFile(fp, (err, data) => {
if (err) { res.writeHead(404); return res.end("not found"); }
res.writeHead(200, { "content-type": MIME[path.extname(fp).toLowerCase()] || "application/octet-stream" });
res.end(data);
});
});
return new Promise((resolve) => server.listen(0, "127.0.0.1", () => resolve(server)));
}
async function main() {
fs.mkdirSync(OUT, { recursive: true });
const server = await serve(FRONTEND);
const { port } = server.address();
const browser = await chromium.launch();
const page = await browser.newPage({ viewport: VIEW, deviceScaleFactor: 2 });
await page.goto(`http://127.0.0.1:${port}/index.html?mode=tour`, { waitUntil: "load" });
await page.waitForFunction(
() => window.Store && document.getElementById("workspace"),
null, { timeout: 30000 },
);
await page.waitForTimeout(1800);
// If the tour auto-opened, strip its overlay — the mocked demo data stays.
const strip = () => page.evaluate(() => document.getElementById("tour-root")?.remove());
await strip();
// 1. Hero: the full workspace with the first generative clip selected.
await page.evaluate(() => {
const first = (window.Store.get().project?.scenes || [])[0];
if (first) window.Store.selectScene(first.id);
});
await page.waitForTimeout(600);
await strip();
await page.screenshot({ path: path.join(OUT, "hero-cutting-room.png") });
console.log("hero-cutting-room.png");
// 2. Composer: global prompt + shortcut/split libraries in the floating window.
await page.evaluate(() => { if (!window.Composer.isOpen()) window.Composer.toggle(); });
await page.waitForTimeout(700);
await strip();
await page.screenshot({ path: path.join(OUT, "hero-composer.png") });
console.log("hero-composer.png");
// 3. Engine Settings: Studio + Chain Sampler knobs without touching a graph.
await page.evaluate(() => {
if (window.Composer.isOpen()) window.Composer.toggle();
window.EngineSettingsModal.open();
});
await page.waitForTimeout(700);
await strip();
await page.screenshot({ path: path.join(OUT, "hero-engine-settings.png") });
console.log("hero-engine-settings.png");
await browser.close();
server.close();
console.log(`Done — clean shots in ${OUT}`);
}
main().catch((e) => { console.error(e); process.exit(1); });
+2 -1
View File
@@ -5,7 +5,8 @@
"version": "1.0.0",
"description": "Auto-generate the FunPack Cutting Room feature showcase (annotated gallery + walkthrough video) by driving the built-in in-app tour. No models or GPU required.",
"scripts": {
"capture": "node capture.mjs"
"capture": "node capture.mjs",
"capture:clean": "node capture_clean.mjs"
},
"dependencies": {
"playwright": "^1.50.0"