Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
28c833f
project name formatter, new util moment_format_to_chrono with test
ItsEeleeya Nov 7, 2025
19ee096
use LazyLock and lazy_static instead
ItsEeleeya Nov 8, 2025
7127d9f
Add command `format_project_name`
ItsEeleeya Nov 8, 2025
b1e4a60
Add UI + update collapsible animations with a little blur
ItsEeleeya Nov 10, 2025
c5a2878
Make the new DefaultProjectNameCard more consistent with ExcludedWind…
ItsEeleeya Nov 10, 2025
aceefc8
remove unused + sanitize using default options
ItsEeleeya Nov 10, 2025
e665245
Merge remote-tracking branch 'upstream/main' into custom-default-proj…
ItsEeleeya Nov 10, 2025
a42da8c
Add project filename migration from UUID to project name
ItsEeleeya Nov 10, 2025
f72e79a
Fix rustdoc for format_project_name
ItsEeleeya Nov 10, 2025
56996e2
Update rustdoc for format_project_name (again)
ItsEeleeya Nov 10, 2025
1cfe4a3
Merge branch 'CapSoftware:main' into custom-default-project-name
ItsEeleeya Nov 10, 2025
2ae52b8
Update to main
ItsEeleeya Nov 19, 2025
925927d
Update tauri.ts
ItsEeleeya Nov 19, 2025
eb12d2f
Remove needless borrowing
ItsEeleeya Nov 19, 2025
ffbf6b8
Measure project name migration times
ItsEeleeya Nov 19, 2025
81d395c
format
ItsEeleeya Nov 19, 2025
2f5a267
Avoid race condition (TOCTOU) is multiple files have the same pretty …
ItsEeleeya Nov 19, 2025
c147e8b
cargo fmt
ItsEeleeya Nov 19, 2025
03d737b
Use NonZero
ItsEeleeya Nov 19, 2025
0902535
don't use static ref for in_flight_bases + cleanup and update comments
ItsEeleeya Nov 19, 2025
9331f84
More tests for cap-utils
ItsEeleeya Nov 19, 2025
bd32090
Don't propagate migration error
ItsEeleeya Nov 19, 2025
897f777
use tauri::command(async) on cap_desktop::format_project_name
ItsEeleeya Nov 19, 2025
c8756eb
Merge remote-tracking branch 'upstream/main' into custom-default-proj…
ItsEeleeya Nov 29, 2025
e3f777a
Add match arm for screenshot mode
ItsEeleeya Nov 29, 2025
cba5cb3
feat: Add circle cursor option and improve cursor rendering
cursoragent Dec 1, 2025
0246852
Merge remote-tracking branch 'upstream/main' into custom-default-proj…
ItsEeleeya Dec 3, 2025
259c4e8
Merge branch '0.4.0-bits' into custom-default-project-name
ItsEeleeya Dec 3, 2025
bdbeb1b
Screenshot project name now uses the formatted filename template
ItsEeleeya Dec 3, 2025
a1fd6cb
Merge pull request #1429 from CapSoftware/0.4.0-bits
richiemcilroy Dec 4, 2025
b753ce4
Update VSCode extension recommendations
richiemcilroy Dec 4, 2025
dd51fcc
Support different minimum crop sizes for screenshot mode
richiemcilroy Dec 4, 2025
0187998
Format VSCode extensions.json file
richiemcilroy Dec 4, 2025
acdd6cc
Add bottom margin to ViewAllButton in TargetMenuGrid
richiemcilroy Dec 4, 2025
97ad9ea
Refactor annotation config UI and remove presets dropdown
richiemcilroy Dec 4, 2025
35eefb3
fix: update Windows API imports for windows crate 0.60.0 compatibility
Jaimin25 Dec 4, 2025
9222156
try add clippy for windows
richiemcilroy Dec 4, 2025
eed3f76
Merge pull request #1431 from Jaimin25/fix/windows-crate-0.60-compat
richiemcilroy Dec 4, 2025
2b0195c
Add LayersPanel and improve crop dialog logic
richiemcilroy Dec 4, 2025
1c349ea
Refactor crop dialog state in Header component
richiemcilroy Dec 4, 2025
c306d9e
Add keyboard shortcuts and focus pan to Preview
richiemcilroy Dec 4, 2025
0152089
Add layers panel toggle and improve aspect ratio constraints
richiemcilroy Dec 4, 2025
2a63eb0
Merge branch 'main' into screenshot-ux
richiemcilroy Dec 4, 2025
74816b6
Add prettyName to screenshot editor
richiemcilroy Dec 4, 2025
96aac80
Refactor popover state management in screenshot editor
richiemcilroy Dec 4, 2025
c52dcb6
Remove rounded class from PreviewCanvas element
richiemcilroy Dec 4, 2025
8245640
Set default border color to transparent black
richiemcilroy Dec 4, 2025
7d5371a
clippy + coderabbit
richiemcilroy Dec 4, 2025
cbbf665
clippy
richiemcilroy Dec 4, 2025
06d5dc8
Improve UI button hover/active styles and window shadow
richiemcilroy Dec 4, 2025
11daa79
Use clamp for output latency hint calculation
richiemcilroy Dec 4, 2025
293be48
Sync camera preview shape with project config
richiemcilroy Dec 4, 2025
6e87871
Return 0.0 for unsupported sample formats
richiemcilroy Dec 4, 2025
30254ed
Add support for more pixel formats on macOS and Windows
richiemcilroy Dec 4, 2025
d8a452f
Refactor Windows platform code for conciseness and clarity
richiemcilroy Dec 4, 2025
2b5d4bd
Add support for unsigned and 8-bit sample formats
richiemcilroy Dec 4, 2025
dd137a6
Refactor useScreenshotExport to use editorCtx object
richiemcilroy Dec 4, 2025
b6b7975
Refactor static slice and icon extraction logic
richiemcilroy Dec 4, 2025
5fde381
Remove UYVY422 mapping to DXGI_FORMAT_YUY2
richiemcilroy Dec 4, 2025
283e8ef
Remove incorrect mappings in ffmpeg_sample_format_for
richiemcilroy Dec 4, 2025
38a865c
Fix pixel format and plane count handling for frames
richiemcilroy Dec 4, 2025
cf869bc
Refactor memory and time handling in SinkFilter and AMMediaType
richiemcilroy Dec 5, 2025
a97d19e
Refactor frame data access and improve dimension checks
richiemcilroy Dec 5, 2025
cfd4d08
Fix memory handling in AMMediaType::into_inner
richiemcilroy Dec 5, 2025
3e24267
Refactor empty check to use is_empty()
richiemcilroy Dec 5, 2025
13986b5
Add recent items submenu to tray and improve image handling
richiemcilroy Dec 7, 2025
d2df462
Remove background overlay from target select screen
richiemcilroy Dec 7, 2025
cfd360e
clippy
richiemcilroy Dec 7, 2025
75c3a68
Document Rust Clippy workspace lint rules
richiemcilroy Dec 7, 2025
32401db
Fix Unicode truncation and fallback for file creation time
richiemcilroy Dec 7, 2025
1de769f
Refactor error handling with let-else chains
richiemcilroy Dec 7, 2025
187bc33
clippy
richiemcilroy Dec 7, 2025
6edcee7
clippy
richiemcilroy Dec 7, 2025
1506972
Merge pull request #1432 from CapSoftware/screenshot-ux
richiemcilroy Dec 7, 2025
30222ce
Merge branch 'main' into pr/1372
richiemcilroy Dec 7, 2025
ead1b32
Run project name migration asynchronously
richiemcilroy Dec 7, 2025
fabd186
Merge pull request #1372 from ItsEeleeya/custom-default-project-name
richiemcilroy Dec 7, 2025
fdad15c
Add camera preview timeout and improve camera cleanup
richiemcilroy Dec 7, 2025
ae8bd29
Merge pull request #1436 from CapSoftware/camera-fix
richiemcilroy Dec 7, 2025
2a26ea1
Merge branch 'main' into cursor/add-circle-cursor-option-to-settings-…
richiemcilroy Dec 7, 2025
adf0428
Close camera window when opening editor windows
richiemcilroy Dec 7, 2025
8da8c9d
Update cursor type and improve circle cursor rendering
richiemcilroy Dec 7, 2025
cea939a
Update captions tab to use new gray and blue color classes
richiemcilroy Dec 7, 2025
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
5 changes: 2 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,8 @@ jobs:
settings:
- target: aarch64-apple-darwin
runner: macos-latest
# Windows can't take the disk usage lol
# - target: x86_64-pc-windows-msvc
# runner: windows-latest
- target: x86_64-pc-windows-msvc
runner: windows-latest
runs-on: ${{ matrix.settings.runner }}
permissions:
contents: read
Expand Down
2 changes: 1 addition & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"recommendations": ["tauri-apps.tauri-vscode", "rust-lang.rust-analyzer"]
"recommendations": ["biomejs.biome", "rust-lang.rust-analyzer"]
}
20 changes: 20 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,26 @@
- Runtime: Node 20, pnpm 10.x, Rust 1.88+, Docker for MySQL/MinIO.
- **NO COMMENTS**: Never add comments to code (`//`, `/* */`, `///`, `//!`, `#`, etc.). Code must be self-explanatory through naming, types, and structure. This applies to all languages (TypeScript, Rust, JavaScript, etc.).

## Rust Clippy Rules (Workspace Lints)
All Rust code must respect these workspace-level lints defined in `Cargo.toml`:

**Rust compiler lints:**
- `unused_must_use = "deny"` — Always handle `Result`/`Option` or types marked `#[must_use]`; never ignore them.

**Clippy lints (all denied):**
- `dbg_macro` — Never use `dbg!()` in code; use proper logging instead.
- `let_underscore_future` — Never write `let _ = async_fn()` which silently drops futures; await or explicitly handle them.
- `unchecked_duration_subtraction` — Use `saturating_sub` instead of `-` for `Duration` to avoid panics.
- `collapsible_if` — Merge nested `if` statements: use `if a && b { }` instead of `if a { if b { } }`.
- `clone_on_copy` — Don't call `.clone()` on `Copy` types; just copy them directly.
- `redundant_closure` — Use function references directly: `iter.map(foo)` instead of `iter.map(|x| foo(x))`.
- `ptr_arg` — Accept `&[T]` or `&str` instead of `&Vec<T>` or `&String` in function parameters.
- `len_zero` — Use `.is_empty()` instead of `.len() == 0` or `.len() > 0`.
- `let_unit_value` — Don't assign `()` to a variable: write `foo();` instead of `let _ = foo();` when return is unit.
- `unnecessary_lazy_evaluations` — Use `.unwrap_or(val)` instead of `.unwrap_or_else(|| val)` for cheap values.
- `needless_range_loop` — Use `for item in &collection` instead of `for i in 0..collection.len()` when index isn't needed.
- `manual_clamp` — Use `.clamp(min, max)` instead of manual `if` chains or `.min().max()` patterns.

## Testing
- TS/JS: Vitest where present (e.g., desktop). Name tests `*.test.ts(x)` near sources.
- Rust: `cargo test` per crate; tests in `src` or `tests`.
Expand Down
60 changes: 60 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,66 @@ Minimize `useEffect` usage: compute during render, handle logic in event handler
- Strict TypeScript; avoid `any`; leverage shared types
- Use Biome for linting/formatting; match existing formatting

## Rust Clippy Rules (Workspace Lints)
All Rust code must respect these workspace-level lints defined in `Cargo.toml`. Violating any of these will fail CI:

**Rust compiler lints:**
- `unused_must_use = "deny"` — Always handle `Result`/`Option` or types marked `#[must_use]`; never ignore them.

**Clippy lints (all denied — code MUST NOT contain these patterns):**
- `dbg_macro` — Never use `dbg!()` in code; use proper logging (`tracing::debug!`, etc.) instead.
- `let_underscore_future` — Never write `let _ = async_fn()` which silently drops futures; await or explicitly handle them.
- `unchecked_duration_subtraction` — Use `duration.saturating_sub(other)` instead of `duration - other` to avoid panics on underflow.
- `collapsible_if` — Merge nested `if` statements: write `if a && b { }` instead of `if a { if b { } }`.
- `clone_on_copy` — Don't call `.clone()` on `Copy` types (integers, bools, etc.); just copy them directly.
- `redundant_closure` — Use function references directly: `iter.map(foo)` instead of `iter.map(|x| foo(x))`.
- `ptr_arg` — Accept `&[T]` or `&str` instead of `&Vec<T>` or `&String` in function parameters for flexibility.
- `len_zero` — Use `.is_empty()` instead of `.len() == 0` or `.len() > 0` / `.len() != 0`.
- `let_unit_value` — Don't assign `()` to a variable: write `foo();` instead of `let _ = foo();` or `let x = foo();` when return is unit.
- `unnecessary_lazy_evaluations` — Use `.unwrap_or(val)` instead of `.unwrap_or_else(|| val)` when the default is a simple/cheap value.
- `needless_range_loop` — Use `for item in &collection` or `for (i, item) in collection.iter().enumerate()` instead of `for i in 0..collection.len()`.
- `manual_clamp` — Use `value.clamp(min, max)` instead of manual `if` chains or `.min(max).max(min)` patterns.

**Examples of violations to avoid:**

```rust
dbg!(value);
let _ = some_async_function();
let duration = duration_a - duration_b;
if condition {
if other_condition {
do_something();
}
}
let x = 5.clone();
vec.iter().map(|x| process(x))
fn example(v: &Vec<i32>) { }
if vec.len() == 0 { }
let _ = returns_unit();
option.unwrap_or_else(|| 42)
for i in 0..vec.len() { println!("{}", vec[i]); }
value.min(max).max(min)
```

**Correct alternatives:**

```rust
tracing::debug!(?value);
some_async_function().await;
let duration = duration_a.saturating_sub(duration_b);
if condition && other_condition {
do_something();
}
let x = 5;
vec.iter().map(process)
fn example(v: &[i32]) { }
if vec.is_empty() { }
returns_unit();
option.unwrap_or(42)
for item in &vec { println!("{}", item); }
value.clamp(min, max)
```

## Security & Privacy Considerations

### Data Handling
Expand Down
19 changes: 17 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
[workspace]
resolver = "2"
members = ["apps/cli", "apps/desktop/src-tauri", "crates/*", "crates/workspace-hack"]
members = [
"apps/cli",
"apps/desktop/src-tauri",
"crates/*",
"crates/workspace-hack",
]

[workspace.dependencies]
anyhow = { version = "1.0.86" }
Expand All @@ -22,6 +27,7 @@ specta = { version = "=2.0.0-rc.20", features = [
"derive",
"serde_json",
"uuid",
"chrono"
] }
serde = { version = "1", features = ["derive"] }

Expand All @@ -40,6 +46,7 @@ sentry = { version = "0.42.0", features = [
] }
tracing = "0.1.41"
futures = "0.3.31"
aho-corasick = "1.1.4"

cidre = { git = "https://github.com/CapSoftware/cidre", rev = "bf84b67079a8", features = [
"macos_12_7",
Expand Down
29 changes: 16 additions & 13 deletions apps/desktop/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ swift-rs = { version = "1.0.6", features = ["build"] }

[dependencies]
tauri = { workspace = true, features = [
"macos-private-api",
"protocol-asset",
"tray-icon",
"image-png",
"devtools",
"macos-private-api",
"protocol-asset",
"tray-icon",
"image-png",
"devtools",
] }
tauri-specta = { version = "=2.0.0-rc.20", features = ["derive", "typescript"] }
tauri-plugin-dialog = "2.2.0"
Expand Down Expand Up @@ -60,6 +60,7 @@ tracing.workspace = true
tempfile = "3.9.0"
ffmpeg.workspace = true
chrono = { version = "0.4.31", features = ["serde"] }
regex = "1.10.4"
rodio = "0.19.0"
png = "0.17.13"
device_query = "4.0.1"
Expand Down Expand Up @@ -106,22 +107,24 @@ tauri-plugin-sentry = "0.5.0"
thiserror.workspace = true
bytes = "1.10.1"
async-stream = "0.3.6"
sanitize-filename = "0.6.0"
tracing-futures = { version = "0.2.5", features = ["futures-03"] }
tracing-opentelemetry = "0.32.0"
opentelemetry = "0.31.0"
opentelemetry-otlp = "0.31.0" #{ version = , features = ["http-proto", "reqwest-client"] }
opentelemetry-otlp = "0.31.0" #{ version = , features = ["http-proto", "reqwest-client"] }
opentelemetry_sdk = { version = "0.31.0", features = ["rt-tokio", "trace"] }
posthog-rs = "0.3.7"
workspace-hack = { version = "0.1", path = "../../../crates/workspace-hack" }
aho-corasick.workspace = true


[target.'cfg(target_os = "macos")'.dependencies]
core-graphics = "0.24.0"
core-foundation = "0.10.0"
objc2-app-kit = { version = "0.3.0", features = [
"NSWindow",
"NSResponder",
"NSHapticFeedback",
"NSWindow",
"NSResponder",
"NSHapticFeedback",
] }
cocoa = "0.26.0"
objc = "0.2.7"
Expand All @@ -131,10 +134,10 @@ cidre = { workspace = true }

[target.'cfg(target_os= "windows")'.dependencies]
windows = { workspace = true, features = [
"Win32_Foundation",
"Win32_System",
"Win32_UI_WindowsAndMessaging",
"Win32_Graphics_Gdi",
"Win32_Foundation",
"Win32_System",
"Win32_UI_WindowsAndMessaging",
"Win32_Graphics_Gdi",
] }
windows-sys = { workspace = true }

Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src-tauri/src/audio_meter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,6 @@ fn samples_to_f64(samples: &MicrophoneSamples) -> impl Iterator<Item = f64> + us
SampleFormat::F64 => f64::from_ne_bytes([
data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
]),
_ => todo!(),
_ => 0.0,
})
}
29 changes: 25 additions & 4 deletions apps/desktop/src-tauri/src/camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ use tokio::{
runtime::Runtime,
sync::{broadcast, oneshot},
task::LocalSet,
time::{Duration, Instant},
};
use tracing::{error, info, trace};
use tracing::{error, info, trace, warn};
use wgpu::{CompositeAlphaMode, SurfaceTexture};

static TOOLBAR_HEIGHT: f32 = 56.0; // also defined in Typescript
Expand All @@ -43,9 +44,9 @@ pub enum CameraPreviewShape {

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
pub struct CameraPreviewState {
size: f32,
shape: CameraPreviewShape,
mirrored: bool,
pub size: f32,
pub shape: CameraPreviewShape,
pub mirrored: bool,
}

impl Default for CameraPreviewState {
Expand Down Expand Up @@ -496,8 +497,23 @@ impl Renderer {
return;
};

let start_time = Instant::now();
let startup_timeout = Duration::from_secs(5);
let mut received_first_frame = false;

let mut state = default_state;
while let Some(event) = loop {
let timeout_remaining = if received_first_frame {
Duration::MAX
} else {
startup_timeout.saturating_sub(start_time.elapsed())
};

if timeout_remaining.is_zero() {
warn!("Camera preview timed out waiting for first frame, closing window");
break None;
}

tokio::select! {
frame = camera_rx.recv_async() => break frame.ok().map(Ok),
result = reconfigure.recv() => {
Expand All @@ -507,10 +523,15 @@ impl Renderer {
continue;
}
},
_ = tokio::time::sleep(timeout_remaining) => {
warn!("Camera preview timed out waiting for first frame, closing window");
break None;
}
}
} {
match event {
Ok(frame) => {
received_first_frame = true;
let aspect_ratio = frame.inner.width() as f32 / frame.inner.height() as f32;
self.sync_ratio_uniform_and_resize_window_to_it(&window, &state, aspect_ratio);

Expand Down
Loading
Loading