Commit Graph
1005 Commits
Author SHA1 Message Date
Justice Entsie 82b41da2d8 Add Portuguese (pt-BR) dialogs to tutorial help translations 2026-05-30 14:31:48 +01:00
Justice Entsie 2aa6e90edb Refactor text animation options to use translation keys for localization 2026-05-30 13:23:15 +01:00
Justice Entsieandcoderabbitai[bot] c34a600138 Update src/i18n/locales/ko-KR/settings.json
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-05-30 12:59:11 +01:00
Justice Entsie 0b06900a9c Add textAnimation keys to ja-JP, ko-KR, and ru locales 2026-05-30 11:54:01 +00:00
Justice Entsie c0702b5e91 Add text animation i18n keys to all locale files 2026-05-30 11:48:29 +00:00
Justice Entsie 928e1c5e01 Merge branch 'siddharthvaddem:main' into font-animation 2026-05-30 11:21:34 +00:00
Justice Entsie 545c35d4cd chore: format codebase and update i18n locale files 2026-05-30 12:13:38 +01:00
Sid cf74b76d39 Merge pull request #581 from nxc-7/feat/pt-BR-translation
feat: add Brazilian Portuguese (pt-BR) translation
2026-05-28 22:05:53 -07:00
Sid afc76c368f Merge branch 'main' into feat/pt-BR-translation 2026-05-28 22:05:36 -07:00
Sid 0abe134218 Merge pull request #647 from davideme/claude/trusting-mcnulty-1089a4
Add Waveform as Background of the Trim Track - Easier to size the Trim
2026-05-28 21:17:44 -07:00
Sid 391817d648 Merge pull request #663 from enstie/font-addition
Add more built-in annotation font options
2026-05-28 21:12:33 -07:00
Sid df6c821700 Merge pull request #665 from zhenya-band/feature/keyboard-shortcut-to-open-OpenScreen
feat: add configurable global shortcut to open app
2026-05-28 21:10:25 -07:00
Sid dd2513d958 Merge pull request #667 from zhenya-band/fix/shortcuts-reset-button-hover-text
fix: remove conflicting hover style from shortcuts reset button
2026-05-28 21:07:39 -07:00
Yauheni Bandziukevich ed5ef32280 fix: remove conflicting hover style from shortcuts reset button 2026-05-28 23:42:27 +02:00
Yauheni Bandziukevich ff40a73a1b fix: keep shortcuts dialog open on registration failure 2026-05-28 23:21:41 +02:00
Yauheni Bandziukevich 59c9a19269 fix: preserve working shortcut when new registration fails 2026-05-28 23:18:35 +02:00
Yauheni Bandziukevich 902d4e4d8a fix: show error feedback when global shortcut registration fails 2026-05-28 23:09:51 +02:00
Yauheni Bandziukevich d86c17407a fix: convert special keys to valid Electron accelerators
Maps KeyboardEvent.key values (e.g., "ArrowDown", " ") to their
Electron accelerator equivalents (e.g., "Down", "Space") to prevent
global shortcut registration failures.
2026-05-28 22:11:38 +02:00
Yauheni Bandziukevich f1a8552046 refactor: update ShortcutBinding import path in main and preload scripts 2026-05-28 21:50:55 +02:00
Yauheni Bandziukevich 480890bcce feat: add configurable global shortcut to open app 2026-05-28 21:50:53 +02:00
Justice Entsie 62000c6dcf Add text animation presets for annotations 2026-05-28 20:07:03 +01:00
Justice Entsie 202c670090 Add more built-in annotation font options 2026-05-28 19:14:47 +01:00
Davide Mendolia 3d572b272d Merge branch 'siddharthvaddem:main' into claude/trusting-mcnulty-1089a4 2026-05-28 09:51:14 +02:00
Davide MendoliaandClaude Sonnet 4.6 fca17f901e revert(timeline): restore polygon waveform, remove per-column bar approach
The per-column fillRect skipped columns with amplitude < 0.5 px, causing
the waveform to disappear entirely at certain zoom levels. Revert to the
closed polygon + top-edge stroke which always renders something.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 09:50:24 +02:00
Davide MendoliaandClaude Sonnet 4.6 abb4413932 fix(timeline): correct waveform vertical alignment and silent baseline
Two fixes:
1. topInset/bottomInset both set to 3 — items are center-aligned in the
   36 px row (3 px gap top and bottom), so the drawing zone must match.
   topInset=0 was drawing 3 px above the trim box top.
2. Replace closed polygon with per-column fillRect so silent sections
   (barH < 0.5 px) produce no pixels instead of a flat green baseline.
   The top-edge stroke lifts the pen across silent gaps.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 09:45:14 +02:00
Davide MendoliaandClaude Sonnet 4.6 d8ab206b80 fix(timeline): draw waveform within item bounds, not CSS canvas bounds
Replace the single `verticalInset` CSS prop (which tried to shrink the
canvas element) with `topInset`/`bottomInset` drawing-space offsets.
The canvas remains `absolute inset-0` (full row height); the polygon
baseline is drawn at `H - bottomInset` and the amplitude is scaled to
`drawHeight * 0.9` — so the waveform is guaranteed to stay within
[topInset, H - bottomInset] regardless of sub-pixel CSS rounding.

Trim row: topInset=0, bottomInset=6 (row minHeight 36 − item height 30)
eliminates the faint green line that was visible below the trim box.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 09:38:06 +02:00
Davide MendoliaandClaude Sonnet 4.6 489f157eef fix(timeline): align waveform bounds with trim box height
The trim item content is 30 px tall inside a 36 px row, leaving 3 px of
vertical padding top and bottom. Previously the canvas used `inset-0` so
the waveform filled the full row height. A new `verticalInset` prop
(defaulting to 0) offsets the canvas top/bottom edges; the trim row
passes `verticalInset={3}` so the waveform top and bottom align exactly
with the trim box bounds.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 09:33:59 +02:00
Davide MendoliaandClaude Sonnet 4.6 60cbb449e8 feat(timeline): rectified (half) waveform style
Replace the bipolar ±center polygon with a rectified half-waveform:
amplitude per column is max(|min|, |max|) and the filled shape rises
from the bottom of the row upward, matching the single-sided waveform
display common in audio/video editors.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 09:30:30 +02:00
Davide MendoliaandClaude Sonnet 4.6 0d39f65af1 feat(timeline): green filled polygon waveform style
Switch the trim-row waveform from faint white vertical strokes to a
green filled polygon (upper max edge left→right, lower min edge
right→left) with crisp edge strokes — matching the look of Final Cut
Pro / DaVinci Resolve waveform displays.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 09:22:56 +02:00
Sid 8117d4826f Merge pull request #657 from aaravshirpurkar/main
fix: increase rounding snap tolerance to 4px to prevent background line bleed when padding is 0
2026-05-26 22:35:42 -07:00
Sid b70994b079 Merge pull request #658 from neurot1cal/fix/streaming-recording-duration
Fix: stream long recordings to disk and patch WebM duration on save (#616)
2026-05-26 22:27:09 -07:00
neurot1calandClaude Opus 4.7 5c5cab6903 fix: don't stream when the append IPC is unavailable
Codex re-review: if openRecordingStream exists but appendRecordingChunk
does not (renderer/main version skew), the recorder would open the stream
and switch to streaming mode, but every append silently no-ops and the
save ends up empty. Require both IPC methods before streaming; otherwise
fall back to in-memory buffering. Adds a regression test.

Verified: tsc --noEmit clean; biome clean; vitest 183/183.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 16:39:53 -07:00
neurot1calandClaude Opus 4.7 36d7d2bdd0 fix: tighten streaming failure handling from re-review
Addresses the CodeRabbit + Codex re-review of the prior commit.

- Normalize a rejected append (channel/handler error, not just a
  { success: false } result) into appendError, so the write queue never
  rejects and isStreaming() stays consistent after a failure (CodeRabbit).
- Handle a rejected open-stream IPC the same as a failed open: fall back
  to in-memory buffering instead of leaving the recorder stuck "pending"
  with an unhandled rejection (CodeRabbit).
- Discard a streamed webcam whose write failed even when the screen save
  succeeds. The cleanup gate is now per-recorder, so a webcam omitted from
  a successful screen-only save no longer leaks its stream and partial
  file (Codex).

Adds tests for the rejected-append and rejected-open paths.

Verified: tsc --noEmit clean; biome clean; vitest 182/182.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 16:28:50 -07:00
neurot1calandClaude Opus 4.7 f3c5b8a65d fix: harden streaming lifecycle and lift it out of the IPC god-module
Addresses the review feedback on #658 (CodeRabbit + Codex) and the
structural notes from the quality pass.

Correctness:
- Compute the recorder's streaming state at finalize time, not at
  construction. A stream that fails to open is now reported as
  not-streamed, so its buffered chunks are saved as a complete in-memory
  fallback instead of being dropped (was total data loss on open failure).
- Await every in-flight chunk write before onstop resolves, so the main
  process never closes the write stream while a final chunk is still in
  flight (was truncating the tail of a recording under load).
- Open the disk write stream by awaiting its 'open' event, so a bad path
  or permission error rejects up front instead of being acknowledged as
  success and then silently dropping bytes.
- Close the stream and remove the partial file when a streamed recording
  is discarded or fails, so cancelled/failed runs don't leak descriptors
  or orphan partial recordings.
- Surface a mid-stream write failure as a rejected recording rather than
  saving a silently truncated file.

Structure:
- Extract the streaming concern into electron/ipc/recordingStream.ts
  (RecordingStreamRegistry) and src/hooks/recorderHandle.ts, out of the
  2.8k-line handlers.ts and the screen-recorder hook.
- Key write streams by output file name, removing the implicit
  recordingId/+1 contract that spanned the IPC boundary.
- Collapse the duplicated screen/webcam finalize blocks into one helper
  and the repeated duration-validity guard into one check; patch the
  screen and webcam durations in parallel.

Adds unit tests for the registry (real temp-dir fs) and the recorder
handle state machine (open-failure fallback, in-order writes awaited
before stop, mid-stream failure). Extends the vitest include glob to
collect electron-side tests.

Verified: tsc --noEmit clean; biome clean; vitest 180/180.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 16:09:39 -07:00
aaravshirpurkar 8c7ea939ab fix: increase rounding snap tolerance to 4px to prevent background line bleed when padding is 0 2026-05-26 13:43:57 +05:30
727e395fcf fix: stream long recordings to disk and patch WebM duration on save
Recordings longer than ~10 minutes silently fail to save (#616). The
renderer buffers the whole WebM as a Blob[], then on stop makes several
in-memory copies (fixWebmDuration -> arrayBuffer -> Buffer.from) before
writing. A long 1080p recording duplicates hundreds of MB several times
in the renderer, exceeds Electron's memory limit, and the renderer
crashes silently with no file saved.

Two changes:

1. Stream chunks to disk (originally @Amanuel2x's contribution in #617).
   Open an fs.WriteStream in the main process at recording start and send
   each ~1s ondataavailable chunk straight to disk over two new IPC calls
   (open-recording-stream, append-recording-chunk), so the renderer never
   holds more than a single chunk. A full in-memory fallback is preserved
   for environments where the IPC stream cannot open.

2. Patch the WebM Duration header on disk after the stream closes. Browser
   MediaRecorder writes WebM with no Duration element, so streamed files
   save with duration=N/A and the editor's seek bar, timeline, and any
   scrub/trim break. A new electron/recording/webm-duration.ts module
   rewrites the Duration element, writing to a temp file and renaming in
   place so a crash mid-write cannot corrupt the recording.

Streaming is opt-in: the screen recorder and the browser-only webcam
recorder stream to disk; native-capture webcam sidecars (Windows, macOS)
keep buffering in-memory, since their finalize path reads the recorder
blob directly to attach the webcam track.

Verified: tsc --noEmit clean; biome clean; vitest 166/166.

Closes #616
Supersedes #617

Co-Authored-By: Amanuel <amanuel@localboostnetworking.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 17:53:22 -07:00
Sid 54677960d0 Merge pull request #645 from auberginewly/fix/export-panel-hidden-after-zoom-select
fix(export): clear timeline selection when opening export panel
2026-05-25 10:59:13 -07:00
Sid 7f73f9089f Merge pull request #646 from AjTheSpidey/codex/editor-settings-scroll
Fix stale speed controls in the editor
2026-05-25 10:56:14 -07:00
Sid f6b0bbd3ed Merge pull request #653 from nachobh/roundingIncreased
Rounding increased
2026-05-25 10:52:56 -07:00
Ignacio Benito Herrero d32bb00959 Increased max rounding to 64 2026-05-25 10:42:43 +02:00
Ignacio Benito Herrero 3d129f85cd Added .import files to .gitignore 2026-05-25 10:38:26 +02:00
Davide MendoliaandClaude Sonnet 4.6 3a2f90722c chore: restore original VideoFrame formatting in streamingDecoder.ts
Biome had reformatted two pre-existing VideoFrame constructor calls from
single-line to multi-line style when --write was run on the file. Restore
them to match main so the diff only reflects our intentional refactoring.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 12:08:55 +02:00
Davide Mendolia c0b929d4b2 refactor: simplify function signatures and reduce line breaks for readability 2026-05-24 11:53:44 +02:00
Davide MendoliaandClaude Sonnet 4.6 db1d6bfe96 refactor: rewrite loadFileAsArrayBuffer using static loadLocalSourceFile/loadRemoteSourceFile
Make loadLocalSourceFile and loadRemoteSourceFile static so they can be
called without an instance. loadSourceFile applies withTimeout around
each static call. loadFileAsArrayBuffer delegates to the same static
methods and extracts ArrayBuffer + contentType from the blob, eliminating
the duplicated IPC/fetch branching logic.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 11:47:51 +02:00
Davide MendoliaandClaude Sonnet 4.6 69d0aa4d30 refactor: split loadSourceFile into loadLocalSourceFile and loadRemoteSourceFile
Restore loadSourceFile as a thin router (local vs remote) and extract
the IPC and fetch paths into dedicated private methods, each containing
the original logic from main.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 11:43:22 +02:00
Davide MendoliaandClaude Sonnet 4.6 d06bf37471 fix: propagate Content-Type from fetch through loadFileAsArrayBuffer
Change return type to { data, contentType } so the fetched Content-Type
header is available to callers. loadSourceFile uses it to set the Blob
MIME type for https:/blob: URLs instead of always falling back to
application/octet-stream. useAudioPeaks destructures only { data }.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 11:30:06 +02:00
Davide MendoliaandClaude Sonnet 4.6 928cabc68d fix: add AbortSignal to worker, fix data: URL filename in loadSourceFile
- computePeaksInWorker now accepts an AbortSignal; terminates the worker
  immediately on abort and rejects with AbortError so orphaned workers
  cannot outlive the effect cleanup
- useAudioPeaks wires an AbortController into the effect; controller.abort()
  fires alongside the existing cancelled flag on URL change or unmount
- loadSourceFile handles data: URLs by parsing the MIME type, deriving a
  safe filename (e.g. video.mp4), and setting Blob type correctly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 19:04:35 +02:00
Davide MendoliaandClaude Sonnet 4.6 9a72f31148 docs: add missing JSDoc to satisfy docstring coverage threshold
Add docstrings to all undocumented functions and methods across the
files touched in this branch: getAudioCtx, Row component, and all
StreamingVideoDecoder methods (loadSourceFile, computeSegments,
getExportMetrics, splitBySpeed, getDemuxer, cancel, destroy, withTimeout).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 18:33:27 +02:00
Davide MendoliaandClaude Sonnet 4.6 9f55611f72 fix: always clear canvas before bailing on empty peaks
Move the peaks null-check after clearRect so a previously drawn
waveform is erased when peaks transitions to null (e.g. on URL change
or decode failure) rather than lingering on screen.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 18:12:54 +02:00
Davide MendoliaandClaude Sonnet 4.6 87f7268de7 i18n(zh-TW): align waveform label with existing trim terminology
Use 剪輯 (editing/clip) instead of 修剪 (trimming) to match the term
already used in the trim section throughout zh-TW strings.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 18:11:44 +02:00