Skip to content
Open
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: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ out/
dist/
*.log
.claude/
.antigravity/
grok_answer.md
*.autosave.kadr
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
legacy-peer-deps=true
9 changes: 9 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ mixes audio and muxes/transcodes per preset.
- Optional: `python3` + `faster-whisper` (speech-to-text), the `claude`
CLI (embedded AI assistant), network access for the one-time Remotion
workspace install
- **MCP (Claude Code):** When working with Claude Code, ensure `context7` MCP
server is configured in `~/.claude/settings.json` with `CONTEXT7_API_KEY` env
var set (get key from context7.com). This enables library/API lookups for
dependencies used in the project. **You must consult the actual documentation
for each library version used in this project** — do not rely on training data
or assumptions about APIs. Always fetch current docs for: Electron, React, Zustand,
TypeScript, WebGL, WebCodecs, mp4box.js, and any other dependencies before
coding or debugging.

## Architecture
- `shared/types.ts` — the entire project model (Project/Track/Clip/Anim/
Expand Down Expand Up @@ -88,3 +96,4 @@ non-empty live project before reloading the page, and back up/restore
- Mutations never auto-push history; see the store convention above.
- `electron-vite dev` does NOT hot-restart the main process — main/preload
edits need a full app restart.
- React 19 + Zustand 5 optimization: avoid calling object-constructing functions like `findClip` inside `useEditor` selectors to prevent infinite rendering loops. Extract primitive keys/IDs, and execute lookups during component render.
8 changes: 7 additions & 1 deletion README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,16 @@ captions to this part», watch it happen live in the preview.

```bash
git clone https://github.com/HelpFreedom/kadr.git && cd kadr
npm install # postinstall rebuilds node-pty for Electron
npm install # Installs dependencies (.npmrc resolves React 19 peer conflicts automatically)
npm run dev
```

*Note: If your system configuration blocks automatic install scripts (`npm warn allow-scripts`), the Electron binary and native modules may not be downloaded or built. In this case, run the setup manually:*
```bash
node node_modules/electron/install.js
npm run postinstall
```

Import media, edit, press Export. For the AI assistant press 🤖 (the
`claude` CLI must be installed and logged in). If your network needs a
proxy for Claude/npm, create `~/.config/kadr/claude-env.json`:
Expand Down
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,16 @@ Kadr — многодорожечный видеоредактор (Electron + R

```bash
git clone https://github.com/HelpFreedom/kadr.git && cd kadr
npm install # postinstall пересоберёт node-pty под Electron
npm install # Установит зависимости (конфликты React 19 автоматически разрешаются через .npmrc)
npm run dev
```

*Примечание: Если ваша система блокирует автоматический запуск скриптов при установке (`npm warn allow-scripts`), исполняемый файл Electron и нативные модули могут не скачаться/не собраться. В этом случае выполните сборку вручную:*
```bash
node node_modules/electron/install.js
npm run postinstall
```

Импортируйте медиа, монтируйте, жмите «Экспорт». Для ИИ-ассистента
нажмите 🤖 (CLI `claude` должен быть установлен и залогинен). Если для
Claude/npm нужен прокси — создайте `~/.config/kadr/claude-env.json`:
Expand Down
91 changes: 91 additions & 0 deletions docs/notes/library-updates-ru.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Заметки по обновлению библиотек и известным ограничениям

## Адаптация к новым версиям

При обновлении ключевых зависимостей (Electron, React, Chromium, TypeScript) всегда проверяйте:

1. **Удалённые и изменённые API:** Смотрите предупреждения об устаревании и changelog'и. Примеры:
- Electron 42 удалил `webContents.on('crashed')` — заменён на `'render-process-gone'`.
- Старые версии Chromium позволяли использовать `<video>` на протоколе `kadr://` без заголовка `Content-Type`; Electron 42+ требует его для выбора декодера.

2. **Новые требования к привилегиям:** Пользовательские URL-схемы часто требуют новых флагов в `protocol.registerSchemesAsPrivileged()`:
- `standard: true` — включает host-based URL'ы и потоковые Range-запросы
- `corsEnabled: true` — разрешает кросс-origin запросы (например, dev-сервер `http://localhost` → `kadr://media`)
- Документируйте, почему нужна каждая привилегия; примеры смотрите в `electron/main.ts`.

3. **Тестируйте полностью:** Всегда запускайте полный e2e-тест после обновлений:
```bash
npm run typecheck
npm run dev -- --remote-debugging-port=9777 &
node scripts/e2e.mjs
```

## SwiftShader и программный GL: ограничения upstream

**Статус:** SwiftShader (программный WebGL2 fallback в Electron) **не умеет компонать декодированные видеокадры**. Это фундаментальное ограничение Chromium, а не ошибка в Kadr.

### Суть проблемы

Когда элемент `<video>` декодирует под SwiftShader, пайплайн обработки кадра (`HTMLVideoElement` → `VideoDecoder` → GPU-процесс) пытается обернуть кадр в **platform GpuMemoryBuffer SharedImage** через `MailboxVideoFrameConverter`. У SwiftShader нет фабрики для platform-GMB формата (`BGRA_8888, gmb_type: platform`), поэтому:

```
ERROR: Could not find SharedImageBackingFactory with params:
usage: Gles2Read|RasterRead|DisplayRead, format: BGRA_8888,
gmb_type: platform, size: 1280x720, debug_label: MailboxVideoFrameConverter
ERROR: GPU process crashed / Context was lost
```

Это случается **до** нашего вызова `texImage2D` — workaround с 2D-canvas в компоновщике это не спасает.

### Почему не исправить в приложении?

Краш происходит в ядре пайплайна Chromium. Возможные облегчения и почему они не работают:

- **`--disable-gpu-memory-buffer-video-frames`** — Не влияет на zero-copy путь видео→GPU, который декодер использует до нашего кода.
- **Canvas 2D blit fallback в компоновщике** — Краш происходит до того, как кадры достигнут нашей загрузки в текстуру; blitting краш-нувшегося кадра ничего не решает.
- **Режим программного H.264-декодера** — Выбор видеокодека и аппаратное ускорение в Chromium тесно связаны; переключение кодеков без GPU-поддержки не представлено для embedder'ов.

### Workaround для CI

Headless CI (без сервера дисплея), которому нужно тестировать видео-превью, должна предоставить **реальный или виртуальный GPU**:

```bash
# Вариант 1: xvfb-run с реальным Mesa OpenGL
xvfb-run -a npm run dev -- --remote-debugging-port=9777 &
xvfb-run -a node scripts/e2e.mjs

# Вариант 2: Docker с pass-through GPU (NVIDIA/AMD)
docker run --gpus all ...

# Вариант 3: Wayland/X11 в GitHub Actions с virgl (эмуляция GPU)
# (смотрите документацию runner'а вашего CI-провайдера)
```

**Не** полагайтесь на `KADR_SOFTWARE_GL=1` для видео-тестов; видео-превью будет чёрным и тест упадёт.

### Ссылки на источники

- **Документация Chromium по SwiftShader:** [Using Chromium with SwiftShader](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/gpu/swiftshader.md) — SwiftShader разработан для графических API (WebGL, WebGPU), не для видео-декода. В документации видео-воспроизведение не рассматривается.
- **Upstream-баг:** [qutebrowser#8908 — MailboxVideoFrameConverter crash under SwiftShader](https://github.com/qutebrowser/qutebrowser/issues/8908) — Открыт с марта 2026 года без upstream-фикса. Тот же краш, workaround не найден.

### Текущая конфигурация (Electron 42)

В `electron/main.ts`:

```typescript
const headless = !process.env.WAYLAND_DISPLAY && !process.env.DISPLAY
if (process.env.KADR_SOFTWARE_GL || headless) {
// SwiftShader: только при явном запросе или в условиях headless
app.commandLine.appendSwitch('use-gl', 'angle')
app.commandLine.appendSwitch('use-angle', 'swiftshader')
app.commandLine.appendSwitch('enable-unsafe-swiftshader')
}
// Иначе используется реальный GPU (NVIDIA, Intel, AMD и т.д.)
```

На машинах с сервером дисплея (Wayland, X11) всегда используется реальный GPU, избегая ограничения программного GL для видео.

## Ключевые файлы

- `electron/main.ts` — обработчик протокола, конфиг GPU, настройка привилегий
- `CLAUDE.md` — требование использовать context7 MCP и консультироваться с актуальной документацией библиотек
91 changes: 91 additions & 0 deletions docs/notes/library-updates.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Notes on Library Updates and Known Limitations

## Adapting to New Versions

When updating core dependencies (Electron, React, Chromium, TypeScript), always verify:

1. **Removed/changed APIs:** Check deprecation warnings and changelogs. Example:
- Electron 42 removed `webContents.on('crashed')` — replaced by `'render-process-gone'`.
- Older Chromium let `<video>` on `kadr://` protocol work without `Content-Type` header; Electron 42+ requires it for decoder selection.

2. **New privilege requirements:** Custom URL schemes often need new flags in `protocol.registerSchemesAsPrivileged()`:
- `standard: true` — enables host-based URLs and streaming Range requests
- `corsEnabled: true` — allows cross-origin requests (e.g., dev server `http://localhost` → `kadr://media`)
- Document why each privilege is needed; see `electron/main.ts` for examples.

3. **Test comprehensively:** Always run full e2e tests after updates:
```bash
npm run typecheck
npm run dev -- --remote-debugging-port=9777 &
node scripts/e2e.mjs
```

## SwiftShader and Software GL: Upstream Limitations

**Status:** SwiftShader (Electron's software WebGL2 fallback) **cannot composite decoded video frames**. This is a fundamental Chromium limitation, not a bug in Kadr.

### The Problem

When a `<video>` element decodes under SwiftShader, the frame pipeline (`HTMLVideoElement` → `VideoDecoder` → GPU process) tries to wrap the frame in a **platform GpuMemoryBuffer SharedImage** via `MailboxVideoFrameConverter`. SwiftShader has no backing factory for platform-GMB format (`BGRA_8888, gmb_type: platform`), so:

```
ERROR: Could not find SharedImageBackingFactory with params:
usage: Gles2Read|RasterRead|DisplayRead, format: BGRA_8888,
gmb_type: platform, size: 1280x720, debug_label: MailboxVideoFrameConverter
ERROR: GPU process crashed / Context was lost
```

This happens **before** our `texImage2D` call — a CPU 2D-canvas workaround in the compositor cannot fix it.

### Why Not Fix It In-App?

The crash is in Chromium's core decode pipeline. Possible mitigations and why they don't work:

- **`--disable-gpu-memory-buffer-video-frames`** — Does not affect the zero-copy video→GPU path the decoder takes before our code sees it.
- **Canvas 2D blit fallback in compositor** — The crash happens before frames reach our texture upload; blitting a crashed frame does nothing.
- **Software H.264 decoder mode** — Chromium's video codec selection and HW acceleration are tightly coupled; switching codecs without GPU support is not exposed to embedders.

### Workaround for CI

Headless CI (no display server) that needs to test video preview must provide a **real or virtual GPU**:

```bash
# Option 1: xvfb-run with real Mesa OpenGL
xvfb-run -a npm run dev -- --remote-debugging-port=9777 &
xvfb-run -a node scripts/e2e.mjs

# Option 2: Docker with GPU pass-through (NVIDIA/AMD)
docker run --gpus all ...

# Option 3: Wayland/X11 in GitHub Actions with virgl (GPU emulation)
# (see runner documentation for your CI provider)
```

Do **not** rely on `KADR_SOFTWARE_GL=1` for video tests; video preview will be black and the test will fail.

### References

- **Chromium SwiftShader Docs:** [Using Chromium with SwiftShader](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/gpu/swiftshader.md) — SwiftShader is designed for graphics API (WebGL, WebGPU), not video decode. Docs do not address video playback.
- **Upstream Issue:** [qutebrowser#8908 — MailboxVideoFrameConverter crash under SwiftShader](https://github.com/qutebrowser/qutebrowser/issues/8908) — Open since March 2026 with no upstream fix. Same crash, no workaround found.

### Current Configuration (Electron 42)

In `electron/main.ts`:

```typescript
const headless = !process.env.WAYLAND_DISPLAY && !process.env.DISPLAY
if (process.env.KADR_SOFTWARE_GL || headless) {
// SwiftShader: only when explicitly requested or truly headless
app.commandLine.appendSwitch('use-gl', 'angle')
app.commandLine.appendSwitch('use-angle', 'swiftshader')
app.commandLine.appendSwitch('enable-unsafe-swiftshader')
}
// Otherwise, use real GPU (NVIDIA, Intel, AMD, etc.)
```

On machines with a display server (Wayland, X11), the real GPU is always used, avoiding the software-GL video limitation.

## Key Files

- `electron/main.ts` — Protocol handler, GPU config, privilege setup
- `CLAUDE.md` — Requirement to use context7 MCP and consult current library docs
Loading