diff --git a/.gitignore b/.gitignore index b9276bc..3d87e97 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,11 @@ node_modules/ out/ dist/ *.log +.DS_Store .claude/ *.autosave.kadr +scripts/__pycache__/ +.codebase-memory/ +projects/ +scripts/build_editable_quiz.mjs +VOICEOVER_STUDIO.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..ef1dc17 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,36 @@ +# Project Instructions + +## Codebase Knowledge Graph + +This project uses codebase-memory-mcp to maintain a knowledge graph of the codebase. +Always prefer MCP graph tools over grep, glob, or file search for code discovery. + +Use the tools in this order: + +1. `search_graph` to find functions, classes, routes, and variables by pattern. +2. `trace_path` to trace callers and callees. +3. `get_code_snippet` to read specific function or class source code. +4. `query_graph` for complex Cypher queries. +5. `get_architecture` for a high-level project summary. + +Fall back to grep, glob, or file search for string literals, error messages, +configuration values, non-code files, or when graph results are insufficient. + +## Commits After Changes + +After completing requested project changes and the relevant checks, create a Git +commit without waiting for a separate request. + +- Commit only files changed for the current task. Preserve unrelated existing + changes in the working tree. +- Use a conventional commit type such as `feat`, `fix`, `docs`, `ref`, `test`, + `build`, `ci`, `chore`, `style`, `perf`, `meta`, or `license`. +- Write a meaningful bilingual commit message in Russian and English. +- Format the subject as `(): / `; + omit the scope when it does not add useful context. +- For non-trivial changes, add a body that explains what changed and why in both + Russian and English. +- Keep every message line under 100 characters and the subject under 70 + characters whenever practical. +- Do not commit when the user explicitly asks not to, when the task is read-only, + or when the requested change is not complete. diff --git a/CLAUDE.md b/CLAUDE.md index 570cd19..bf64190 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -43,7 +43,7 @@ mixes audio and muxes/transcodes per preset. black. Startup sweeps leftover helper processes; shutdown force-exits (window-all-closed → app.exit failsafe, render-process-gone → exit). - `electron/ffmpeg.ts` — ffprobe probing (+ thumbnails + peak/RMS waveform - bins), `makeProxy` (540p preview proxies), `makeReversed` (backwards + bins), `makeProxy` (validated adaptive 720p preview proxies), `makeReversed` (backwards render of a clip's source range, RAM-bounded chunks), `ExportMuxer` (per-segment `volume,atempo*,afade,adelay,apad,atrim` → `amix` with exact level compensation), `RawVideoEncoder` (fallback raw-frame @@ -56,8 +56,9 @@ mixes audio and muxes/transcodes per preset. `userData/claude-mcp.json`; `sweepStaleSessions()` clears leftovers of hard-killed runs at startup. - `electron/mcp-bridge.cjs` — MCP stdio server (SDK) that claude receives - via a generated `--mcp-config`; tools: kadr_state / kadr_eval / - kadr_export / kadr_transcribe / kadr_fragment_create. + via a generated `--mcp-config`; tools: kadr_capabilities / kadr_state / + kadr_snapshot / kadr_eval / kadr_export / kadr_transcribe / kadr_voices / + kadr_fragment_create. - `electron/transcribe.ts` + `scripts/transcribe.py` — faster-whisper runner (VAD, anti-hallucination thresholds and post-filters, NDJSON segments with word timestamps); audio comes from an ExportMuxer mixdown @@ -86,7 +87,7 @@ mixes audio and muxes/transcodes per preset. x-moz-url / DownloadURL → portal key), `importDrop` (paths → URLs → raw blobs), window-level catch-all drop in App.tsx, drop forensics to `window.__dragLog` + `userData/drop-log.jsonl`. -- Clip speed UX (`Timeline.tsx`): Ctrl-drag on either extend grip or +- Clip speed UX (`Timeline.tsx`): primary-modifier drag on either extend grip or clip edge = 0.02–100× with ~16 px snapping to round multipliers AND neighbouring clip edges/playhead; a cursor-following ×N badge lights up when snapped. Preview clamps element playbackRate to Chromium's hard diff --git a/FEATURES.md b/FEATURES.md index f39d24c..140f2cb 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -111,10 +111,10 @@ npm run typecheck # проверка типов (рендерер + main-пр | ↶ / ↷ | Отмена / повтор (в подсказке — что именно отменится) | | Новый проект | Чистый проект (несохранённые изменения теряются) | | Открыть проект | Диалог открытия `.kadr` | -| Сохранить | Ctrl+S — в текущий файл (или диалог, если не сохранялся) | -| Сохранить как… | Ctrl+Shift+S — всегда диалог; проект «переезжает» по новому пути | +| Сохранить | ⌘S на macOS / Ctrl+S на Windows и Linux — в текущий файл (или диалог, если не сохранялся) | +| Сохранить как… | ⇧⌘S на macOS / Ctrl+Shift+S на Windows и Linux — всегда диалог; проект «переезжает» по новому пути | | Экспорт | Диалог рендера | -| 🤖 Claude | Встроенная сессия Claude Code (повторное нажатие — закрыть) | +| 🤖 Claude | Встроенная сессия Claude Code (повторное нажатие — свернуть без завершения сессии) | | RU/EN | Переключение языка интерфейса | ### Зоны можно растягивать @@ -152,12 +152,21 @@ npm run typecheck # проверка типов (рендерер + main-пр дорожки, клипы, ссылки на медиафайлы (по абсолютным путям), ключевые кадры, эффекты, тексты, фрагменты. Медиафайлы в проект не копируются. +Установленная macOS-версия регистрирует `.kadr` в LaunchServices. Двойной +клик по проекту в Finder или перенос проекта на иконку Kadr в Dock открывает +его сразу в редакторе. Каждый новый файл получает отдельное независимое окно; +повторное открытие уже открытого пути переводит фокус на существующее окно. + +**⌘N / «Файл → Новое окно» / меню Kadr в Dock** создаёт пустое окно для +параллельного проекта. **⇧⌘N / «Новый проект»** очищает активное окно. + ### Сохранение -- **Ctrl+S / «Сохранить»** — в текущий файл; если проект ещё не имеет +- **⌘S на macOS / Ctrl+S на Windows и Linux / «Сохранить»** — в текущий файл; если проект ещё не имеет файла, откроется диалог. -- **Ctrl+Shift+S / «Сохранить как…»** — всегда диалог; после сохранения - проект продолжает жить по новому пути (последующие Ctrl+S — туда). +- **⇧⌘S на macOS / Ctrl+Shift+S на Windows и Linux / «Сохранить как…»** — + всегда диалог; после сохранения проект продолжает жить по новому пути + (последующие ⌘S / Ctrl+S — туда). - Все диалоги (проекты, импорт, экспорт) запоминают последнюю папку; первый запуск открывается в «Видео»/«Загрузки». @@ -167,7 +176,8 @@ npm run typecheck # проверка типов (рендерер + main-пр - **раз в 5 минут**, и только если проект менялся с прошлого раза; - файл `<имя>.autosave.kadr` **в той же папке, что и основной** (для ещё - не сохранённых проектов — в «Загрузках»), перезаписывается; + не сохранённых проектов — уникальный для окна файл в «Загрузках»), + перезаписывается; - запись **атомарная** (временный файл + переименование) — сбой в момент записи не может оставить битый автосейв; - **пропускается**, пока идёт экспорт или открыта сессия встроенного @@ -182,7 +192,8 @@ npm run typecheck # проверка типов (рендерер + main-пр - История на 50 шагов, каждый шаг подписан («перемещение клипа», «разрезание», «выбор перехода»…) — подпись видна в подсказке кнопок ↶/↷. -- Ctrl+Z — отмена, Ctrl+Shift+Z или Ctrl+Y — повтор. +- ⌘Z на macOS / Ctrl+Z на Windows и Linux — отмена; повтор — ⇧⌘Z на + macOS, Ctrl+Shift+Z или Ctrl+Y на Windows и Linux. - Откатывается всё: правки клипов, ключевые кадры, эффекты, переходы, тексты, применение пресетов. @@ -203,7 +214,8 @@ npm run typecheck # проверка типов (рендерер + main-пр оно скачается (кэш по URL в `userData/imported`) и встанет клипом. Понимаются и `data:`-миниатюры, и перетаскивания из песочных приложений через XDG-портал, и файлы из панели загрузок Chrome. -- **Ctrl+V — вставка из буфера обмена** (когда внутри редактора ничего +- **⌘V на macOS / Ctrl+V на Windows и Linux — вставка из буфера обмена** + (когда внутри редактора ничего не скопировано): скопированные файлы или скопированное изображение (например, «Копировать изображение» в Telegram — перетаскиванием tdesktop фото не отдаёт). Изображение сохраняется как PNG и ложится @@ -239,7 +251,8 @@ npm run typecheck # проверка типов (рендерер + main-пр - `⚙ 47%` — строится прокси; - `P` — прокси готов, превью идёт через него; - `📝` — кнопка транскрибации (для медиа со звуком). -- **Выделение и удаление**: клик выделяет карточку, Ctrl+клик добавляет, +- **Выделение и удаление**: клик выделяет карточку, ⌘+клик на macOS или + Ctrl+клик на Windows/Linux добавляет, Shift+клик — диапазон. Крестик на карточке (при наведении) удаляет файл из проекта, кнопка «✕ N» в шапке — всю выборку. Клипы на таймлайне, использующие удаляемые файлы (включая связанные AV-пары), @@ -258,9 +271,13 @@ npm run typecheck # проверка типов (рендерер + main-пр Тяжёлые исходники тормозили бы превью, поэтому: -- каждое видео с коротком стороной **≥720p** автоматически получает - фоновую облегчённую копию: H.264 540p + AAC 96k; +- каждое видео с короткой стороной **≥720p** автоматически получает + фоновую облегчённую копию: H.264 CRF 22 + AAC 96k; горизонтальные + ролики вписываются в 1280×720, вертикальные — в 720×1280; - прокси строятся **по одному** (очередь), прогресс виден на карточке; +- готовый файл проверяется по длительности и декодированию кадров в начале, + середине и конце; битый или недостроенный кэш автоматически пересобирается + (до трёх попыток), а на карточке появляется кнопка повторной сборки; - кэш: `userData/proxies/`, ключ — путь+размер+mtime файла (изменился исходник — прокси перестроится); - превью декодирует прокси, **экспорт всегда читает оригинал** — качество @@ -270,6 +287,12 @@ npm run typecheck # проверка типов (рендерер + main-пр ## 6. Таймлайн и дорожки +Внутри видеоклипов показывается адаптивная «плёнка» кадров. При увеличении +масштаба кадров становится больше, при уменьшении остаётся один или несколько +опорных. Генерируется только видимая область с небольшим запасом; запросы идут +в фоновой очереди, используют прокси, дисковый и оперативный кэш. Для +Remotion-фрагментов кэш привязан к хешу исходников и обновляется после правок. + ### Тулбар таймлайна | Кнопка | Действие | @@ -305,7 +328,8 @@ npm run typecheck # проверка типов (рендерер + main-пр жёлтая зона. Диапазон используется экспортом, транскрипцией, авто-субтитрами, копированием/удалением фрагмента. - **Esc** — снять диапазон. -- **Ctrl+клик по пустому месту дорожки** — сомкнуть клипы (закрыть дыру +- **⌘+клик на macOS / Ctrl+клик на Windows и Linux по пустому месту + дорожки** — сомкнуть клипы (закрыть дыру слева от места клика). ### Маркеры @@ -352,13 +376,14 @@ npm run typecheck # проверка типов (рендерер + main-пр `inPoint` (откуда играть исходник). - **Верхние уголки** — ручки **фейдов**: потяните внутрь — плавное появление/затухание (видео — прозрачность, звук — громкость). -- **Перетаскивание края с зажатым Ctrl** — изменение **скорости** клипа +- **Перетаскивание края с зажатым ⌘ на macOS или Ctrl на Windows/Linux** — + изменение **скорости** клипа (растяжение/сжатие по времени с пересчётом темпа). Работает за **оба** края: правый якорит начало, левый — конец клипа. Диапазон ×0.02–×100; значение прилипает к круглым множителям (×0.5, ×1, ×2…) и к краям соседних клипов/плейхеду, рядом с курсором — живой бейдж «×N» (подсвечивается в момент прилипания). Синие ручки на середине обоих - краёв делают то же самое; без Ctrl левая ручка подрезает клип + краёв делают то же самое; без модификатора левая ручка подрезает клип (контент остаётся на месте), правая — растягивает/зацикливает. - **Нижние фиолетовые уголки** — «кончики» торцевых переходов (§16). - **Двойной клик** — открыть редактор анимации (§9). @@ -405,24 +430,28 @@ npm run typecheck # проверка типов (рендерер + main-пр - **D / Delete / Backspace** — удалить выделенные клипы; если выделения нет, но есть диапазон — **вырезать диапазон** из всех дорожек со смыканием. -- **Ctrl+C / Ctrl+V** — копирование клипов (или содержимого диапазона) и +- **⌘C / ⌘V на macOS, Ctrl+C / Ctrl+V на Windows и Linux** — + копирование клипов (или содержимого диапазона) и вставка на плейхед. --- ## 8. Горячие клавиши +В таблице первое сочетание указано для macOS, второе — для Windows/Linux. +На macOS основной модификатор — ⌘, на остальных системах — Ctrl. + | Клавиша | Действие | |---|---| | **Space** | Воспроизведение / пауза | | **S** | Разрезать по плейхеду | -| **Ctrl+S** | Сохранить проект | -| **Ctrl+Shift+S** | Сохранить как… | +| **⌘S / Ctrl+S** | Сохранить проект | +| **⇧⌘S / Ctrl+Shift+S** | Сохранить как… | | **D / Delete / Backspace** | Удалить выделение (или вырезать диапазон) | -| **Ctrl+Z** | Отменить | -| **Ctrl+Shift+Z / Ctrl+Y** | Повторить | -| **Ctrl+C** | Копировать выделение / диапазон | -| **Ctrl+V** | Вставить на плейхеде | +| **⌘Z / Ctrl+Z** | Отменить | +| **⇧⌘Z / Ctrl+Shift+Z; также Ctrl+Y на Windows/Linux** | Повторить | +| **⌘C / Ctrl+C** | Копировать выделение / диапазон | +| **⌘V / Ctrl+V** | Вставить на плейхеде | | **M** | Поставить маркер на плейхеде | | **U** | Связать/развязать видео+аудио | | **← / →** | Шаг на кадр назад/вперёд | @@ -611,7 +640,7 @@ Remotion-фрагментах — и в превью, и в рендере од именем; - **Применить** — клик по имени заменяет эффекты выделенного клипа набором из пресета (с новыми внутренними id); ложится в историю — - отменяется Ctrl+Z; + отменяется ⌘Z / Ctrl+Z; - **Удалить** — ✕; - хранение: `fx-presets.json` в данных приложения, общее для всех проектов, переживает перезапуск. @@ -847,7 +876,7 @@ Whisper отдаёт время **каждого слова**. Реплики н - **перетаскивание рамки** — позиция; - **уголок** или **колесо мыши** — масштаб; -- каждый жест — шаг истории (Ctrl+Z работает). +- каждый жест — шаг истории (⌘Z / Ctrl+Z работает). Гизмо работает для **любых** Remotion-фрагментов, не только субтитров. @@ -960,7 +989,10 @@ WYSIWYG-конвейер. Рендеры кэшируются **по хешу с не забыв `NO_PROXY=localhost` для локального MCP-моста; - при первом запуске Claude спросит «Do you trust this folder?» — Enter; - рабочая папка — папка `.kadr`-файла (или домашняя); -- повторное нажатие 🤖 или ✕ — сессия и мост убиваются; +- повторное нажатие 🤖 сворачивает панель без завершения сессии; следующее + нажатие возвращает её с сохранённым контекстом; +- ✕ показывает подтверждение; «Да» закрывает панель и завершает сессию и мост, + «Нет» возвращает в активный терминал; - окно панели **перетаскивается за заголовок и растягивается за края и нижние углы**; позиция и размер запоминаются между запусками; - переопределение запуска: `~/.config/kadr/claude-env.json` — @@ -995,12 +1027,44 @@ WYSIWYG-конвейер. Рендеры кэшируются **по хешу с Полный список инструментов сервера `kadr`: +### kadr_capabilities + +Авторитетный контракт текущей версии редактора. Возвращает все разделы +сразу или один раздел: модель и файлы проекта, таймлайн, анимация, трансформации, +маски, эффекты, переходы, звук и речь, субтитры, фрагменты, озвучка, +экспорт и действия store. Списки переходов и пресетов строятся из тех же +runtime-реестров, что использует интерфейс, поэтому агенту не нужно +угадывать имена полей, диапазоны и допустимые значения. + ### kadr_state Снимок живого состояния: проект целиком (дорожки → клипы со всеми параметрами; ассеты с абсолютными путями; texts — транскрипты с путями к файлам), путь проекта, выделение, плейхед, доступные пресеты экспорта. +### kadr_tasks / kadr_task_start / kadr_task_complete + +Очередь аннотаций-задач на специальных нерендерящихся дорожках. Агент +получает актуальные тайминги, берёт задачу в работу по постоянному случайному +id, применяет финальную пачку правок одним undo-шагом, записывает результат и +закрывает задачу. MCP не принимает тайминг при обновлении: если пользователь +передвинул аннотацию во время работы агента, её новая позиция не затирается. + +### kadr_snapshot + +Сохранить WYSIWYG-кадр проекта в PNG на выбранном времени. Используется +агентом для визуальной проверки композиции, эффектов, переходов и +анимации; при необходимости кадр можно сразу добавить в медиатеку. + +### kadr_storyboard + +Создать раскадровку диапазона без ручной выгрузки PNG: один контактный лист +с таймкодами и до 24 отдельных полноразмерных кадров (по умолчанию 9). +Захват временно использует оригиналы вместо прокси, включает Remotion и затем +восстанавливает плейхед и воспроизведение. Результат повторно используется +только пока точный визуальный fingerprint проекта, медиа и фрагментов не +изменился; `refresh: force` принудительно обновляет кадры. + ### kadr_eval Выполнить JavaScript в странице редактора (тело async-функции, @@ -1220,13 +1284,15 @@ vsync-меткам кадров, дрожание таймера не накап | `~/.config/kadr/last-dirs.json` | последние папки диалогов | | `~/.config/kadr/claude-env.json` | переопределение запуска Claude (опц.) | | `~/.config/kadr/proxies/` | кэш превью-прокси | +| `~/.config/kadr/timeline-thumbnails/` | кэш кадров-плёнки таймлайна | +| `~/.config/kadr/storyboards/` | управляемый кэш раскадровок агента | | `~/.config/kadr/fragment-renders/` | кэш рендеров фрагментов | | `~/.config/kadr/decoded/` | промежуточные файлы для быстрого декода (лимит 10 ГБ) | | `~/kadr-fragments/` | workspace Remotion-композиций (ссылки на папки проектов) | | `<папка проекта>/kadr-fragments/` | исходники фрагментов этого проекта | | `/tmp/kadr-export-*.mp4` | временные файлы экспорта (удаляются) | -Кэши можно безболезненно чистить: прокси и рендеры фрагментов +Кэши можно безболезненно чистить: прокси, кадры таймлайна и рендеры фрагментов перестроятся при необходимости. --- diff --git a/README.en.md b/README.en.md index 8874f7e..2008f88 100644 --- a/README.en.md +++ b/README.en.md @@ -17,13 +17,15 @@ captions to this part», watch it happen live in the preview. - 🎬 **Real multi-track editing** — video/audio/text tracks, trimming, looping, fades, linked AV clips, ripple delete, full undo history. - Clip speed from ×0.02 to ×100 by Ctrl-dragging **either** clip edge + Clip speed from ×0.02 to ×100 by ⌘-dragging on macOS or Ctrl-dragging + on Windows/Linux over **either** clip edge (the left one anchors the right boundary), snapping to round multipliers and to neighbouring clips' edges, with a live ×N badge. - 📥 **Media from anywhere** — drop files onto any spot of the window (onto a track they land as clips back-to-back at the drop point, audio routes to an audio track), drag a picture straight out of a browser - (fetched by URL), or hit Ctrl+V — clipboard paste understands both + (fetched by URL), or hit ⌘V on macOS / Ctrl+V on Windows and Linux — + clipboard paste understands both copied files and "Copy image" (e.g. from Telegram, which won't let photos be dragged out at all). XDG-portal drags from sandboxed apps are supported too. The media bin gets multi-select and deletion that @@ -65,26 +67,22 @@ captions to this part», watch it happen live in the preview. terminal panel, wired to the live project over MCP: it reads the timeline, edits clips, transcribes, creates and iterates Remotion fragments while you watch the preview update. The panel is draggable, - resizable and remembers its place across launches. + resizable and remembers its place across launches; pressing Claude again + minimizes it without losing the session context. - 📍 **Timeline markers** — press **M** to drop a numbered marker at the - playhead: drag it, right-click to remove it, it lives in the project - file and the embedded Claude can see and place them too ("retime - everything between marker 3 and marker 4"). + playhead: drag it, right-click to remove it, and use it from Claude too. - 📤 **Uncompromised export** — video is encoded by ffmpeg x264 at the preset's true bitrate (Chromium's built-in encoder ignored the bitrate and softened the picture — measured and replaced; frames reach ffmpeg - with zero copies), 8-sample motion blur, automatic frame blending for - fps-mismatched sources, presets for YouTube/Shorts/WebM/MP3, and a + with zero copies), mp4box-based fast decode (~8× over element seeks, + with graceful fallback), 8-sample motion blur, automatic frame blending + for fps-mismatched sources, presets for YouTube/Shorts/WebM/MP3, and a short chime when the render is done. -- 🚀 **Fast on every source** — seeking a `