A modern camera application for Linux, built for desktops and phones alike.
- Photo, video and timelapse modes, with a self timer, composition guides and aspect ratios
- Manual controls for exposure, ISO, shutter, focus, white balance and colour, plus pan and tilt on motorised cameras
- GPU accelerated preview, filters and debayering via wgpu, with hardware video encoding (VA-API, NVENC, QSV, AMF, V4L2) and software fallback
- 14 creative filters applied live to the preview, photos, recordings and the virtual camera
- QR code scanner that opens links and connects to WiFi through NetworkManager
- Virtual camera over PipeWire, so other apps see your filtered feed in video calls
- JPEG, PNG and DNG output, including true sensor raw where libcamera exposes a raw stream
- Multi-camera and multi-microphone switching with hotplug support
- Rebindable keyboard shortcuts, plus an insights panel and bug report generator for diagnostics
Built with libcosmic. It runs on any Wayland or X11 desktop, following the system light/dark preference through the XDG portal, and integrates natively with COSMIC where available.
This is a personal project by Frederic Laing. It is not affiliated with or endorsed by System76. The application may be contributed to System76 or the COSMIC project in the future if there is interest.
# Install from Flathub
flatpak install flathub io.github.cosmic_utils.camera
# Or install from a downloaded .flatpak bundle
flatpak install klikka-x86_64.flatpak- Rust (stable)
- cosmic-icons
- GStreamer 1.0 with plugins (base, good, bad, ugly)
- libcamera (>= 0.4.0)
- cmake (for building embedded libjpeg-turbo)
- libwayland
- libxkbcommon
- libinput
- libudev
- libseat
# Install just command runner
cargo install just
# Build release binary
just build-release
# Install to system
sudo just installKlikka supports several command-line modes for headless operation:
klikka # Launch GUI (default)
klikka --help # Show help
klikka list # List available cameras
klikka photo # Take a photo
klikka video # Record a video
klikka process # Run a computational photography pipeline
klikka terminal # Terminal mode viewerklikka listShows available cameras with their supported formats:
Available cameras:
[0] Laptop Webcam Module (V4L2)
Formats: 1920x1080@30fps, 1280x720@30fps, 640x480@30fps
klikka photo [OPTIONS]Options:
-c, --camera <INDEX>- Camera index fromklikka list(default: 0)-o, --output <PATH>- Output file path (default: ~/Pictures/Camera/IMG_TIMESTAMP.jpg)
Examples:
klikka photo # Quick photo with defaults
klikka photo -o ~/snapshot.jpg # Custom output path
klikka photo -c 1 # Use second cameraklikka video [OPTIONS]Options:
-c, --camera <INDEX>- Camera index fromklikka list(default: 0)-d, --duration <SECONDS>- Recording duration (default: 10)-o, --output <PATH>- Output file path (default: ~/Videos/Camera/video_TIMESTAMP.mp4)-a, --audio- Enable audio recording
Examples:
klikka video # 10 second video
klikka video -d 30 # 30 second video
klikka video -d 60 -a # 1 minute with audio
klikka video -c 1 -d 30 -o out.mp4 # Camera 1, custom outputPress Ctrl+C to stop recording early.
Process images through computational photography pipelines.
klikka process <MODE> [OPTIONS] <INPUT>...Multi-frame denoising and HDR+ pipeline for low-light photography.
klikka process burst-mode [OPTIONS] <INPUT>...Arguments:
<INPUT>...- One or more image files (PNG, DNG) or a directory containing images
Options:
-o, --output <DIR>- Output directory for processed images (default:<input>/outputor~/Pictures/Camera)
Examples:
klikka process burst-mode /path/to/burst/ # Process all images in directory
klikka process burst-mode img1.png img2.png img3.png # Process specific files
klikka process burst-mode /path/to/burst/ -o /output/ # Custom output directoryThe pipeline automatically:
- Selects the sharpest frame as reference
- Aligns all frames to the reference using GPU-accelerated pyramid alignment
- Merges frames using FFT-based frequency domain denoising
- Applies tone mapping with shadow recovery
- Outputs as DNG
Ever wanted to see your face rendered in glorious Unicode? Wonder what you'd look like as a half-block character? Well, wonder no more!
klikka terminalControls:
s- Switch camera (cycle through available cameras)qorCtrl+C- Return to the real world
Why does this exist?
- SSH into your server and check if you left the oven on (assuming your oven has a camera)
- Finally achieve your dream of becoming ASCII art
- Prove to your coworkers that you can attend video calls from a TTY
- Because we could
Note: Your terminal needs true color support (most modern terminals have this). If you see a sad mosaic of wrong colors, try a different terminal emulator. Also, this won't make you more photogenic - trust us, we tried.
# Run with debug logging
just run
# Run with verbose debug logging
just run-debug
# Format code
just fmt
# Run all checks (format, cargo check, tests)
just check
# Run clippy lints
just clippy
# Run tests only
just testCross-compilation for other architectures uses cross with custom Dockerfiles in docker/.
# Install cross
cargo install cross --git https://github.com/cross-rs/cross
# Debug build
cross build --target aarch64-unknown-linux-gnu
# Release build
cross build --release --target aarch64-unknown-linux-gnu| Target | Dockerfile | Base |
|---|---|---|
aarch64-unknown-linux-gnu |
docker/Dockerfile.aarch64 |
Ubuntu 25.04 |
armv7-unknown-linux-gnueabihf |
docker/Dockerfile.armhf |
Ubuntu 25.04 |
riscv64gc-unknown-linux-gnu |
docker/Dockerfile.riscv64 |
Ubuntu 25.04 |
x86_64-unknown-linux-gnu |
docker/Dockerfile.x86_64 |
Ubuntu 25.04 |
x86_64-unknown-linux-musl |
docker/Dockerfile.x86_64-musl |
Alpine |
aarch64-unknown-linux-musl |
docker/Dockerfile.aarch64-musl |
Alpine + clang |
The configuration is in Cross.toml. Docker or Podman is required.
Podman users: If your system uses btrfs, configure the storage driver:
mkdir -p ~/.config/containers
printf '[storage]\ndriver = "btrfs"\n' > ~/.config/containers/storage.conf
podman system reset --forceIf your kernel lacks the tun module (check with modprobe tun), pass host networking:
CROSS_BUILD_OPTS="--network=host" CROSS_CONTAINER_OPTS="--network=host" cross build --target ...just apk-build [arch] cross-compiles the binary and then packages it as an
.apk in an Alpine container, leaving the result in apk-out/:
just apk-build aarch64On an x86_64 host the packaging half runs in an emulated aarch64 container, and
that needs binfmt_misc registered with the C (credentials) flag. Distros
commonly register qemu-aarch64 with F alone, which makes the kernel ignore
setuid bits on emulated binaries — abuild then fails with:
abuild-apk: setuid(0) failed: Operation not permitted
Check the current flags, and add C if it is missing:
# Check — look for "flags: OCF" rather than "flags: F"
cat /proc/sys/fs/binfmt_misc/qemu-aarch64
# Override the vendor registration with C added (C implies O; keep F)
sed 's/:F$/:OCF/' /usr/lib/binfmt.d/qemu-aarch64-static.conf \
| sudo tee /etc/binfmt.d/qemu-aarch64-static.conf
sudo systemctl restart systemd-binfmtNote that C makes setuid bits effective for all emulated binaries, not just
this build.
For development on atomic/immutable desktops (Fedora Silverblue, Kinoite, Bazzite, etc.):
# Create the development container
distrobox assemble create
# Enter the container
distrobox enter klikka-dev
# Build inside the container
just build-release
# Run the binary on the host (not inside distrobox)
# Camera access via PipeWire requires running on the host
./target/release/klikka
# Remove when no longer needed
distrobox rm klikka-devTo run GUI apps from inside the container, allow local display access on your host:
xhost +si:localuser:$USERAdd this to ~/.distroboxrc to make it permanent.
Note: Camera access requires PipeWire, which doesn't work reliably from inside containers. Build in distrobox, run on host for full functionality.
# Full install (uninstalls old, installs deps if needed, builds and installs)
just flatpak-install
# Run the installed Flatpak
just flatpak-run
# Uninstall all Flatpak components
just flatpak-uninstall
# Individual steps (if needed)
just flatpak-deps # Install Flatpak SDK/runtime
just flatpak-build # Build and install Flatpak
just flatpak-clean # Remove build artifactsThe exposure controls implementation was inspired by cameractrls, a camera controls GUI for Linux.
The night mode photo feature implements a simplified version of the HDR+ algorithm, with implementation guidance from:
-
hdr-plus-swift by Martin Marek (GitHub) - GPL-3.0
- Hierarchical pyramid alignment with L1/L2 hybrid cost functions
- FFT-based frequency domain merging
- Spatial domain merge algorithm
- Noise estimation techniques
-
Google HDR+ Paper - "Burst photography for high dynamic range and low-light imaging on mobile cameras" (Hasinoff et al., SIGGRAPH 2016)
-
Night Sight Paper - "Handheld Mobile Photography in Very Low Light" (Liba et al., SIGGRAPH Asia 2019)
The blur behind the app's overlay chrome reuses shader work from:
- cosmic-comp by System76 (GitHub) - GPL-3.0-only
- Dual-Kawase downsample/upsample blur kernels, transcribed to WGSL
- The
BLUR_PARAMSradius/iteration/offset table - The film-grain hash, which cosmic-comp in turn took from niri
Licensed under the GNU Public License 3.0.
Any contribution intentionally submitted for inclusion in the work by you shall be licensed under the GNU Public License 3.0 (GPL-3.0). Each source file should have a SPDX copyright notice at the top of the file:
// SPDX-License-Identifier: GPL-3.0-only
The easiest way to report a bug is to use the "Report a Bug" button in the app settings. This generates a detailed system report that helps with debugging.
- Open Klikka → Settings → "Report a Bug"
- A bug report file will be saved to
~/Pictures/Camera/ - Your browser will open the bug report form
- Attach the generated report file and describe the issue
You can also report bugs manually if you prefer.
Have an idea for a new feature? Submit a feature request!
