"라이트룸과 비슷한데 무료고, 가볍고, 코드를 통째로 들여다볼 수 있다"가 핵심 가치다. 실제로 사용자가 슬라이더를 움직일 때마다 원본 픽셀은 절대 손대지 않고 .rrdata라는 사이드카 파일에 "이 슬라이더를 +30 했다"는 기록만 남긴다. 화면에 보이는 결과물은 매 프레임 GPU에서 새로 합성된 미리보기다.
일반 사진 앱이 "도자기에 그림을 그리는 것"이라면, RapidRAW(또는 라이트룸 같은 비파괴 편집기)는 "도자기 위에 투명 셀로판지를 여러 장 겹치는 것"이다. 도자기(원본 RAW)는 평생 그대로다. 셀로판지에 적힌 메모(.rrdata 사이드카)만 바꿔서 결과를 무한히 되돌릴 수 있다.
그리고 셀로판지를 통과한 빛(최종 픽셀)을 계산하는 일을 CPU가 아니라 수천 개 코어가 동시에 같은 식을 푸는 GPU에 떠넘긴 것이 RapidRAW의 "Rapid"다.
사진 RAW 편집 시장은 사실상 Adobe Lightroom Classic이 표준이고, 무료 대안은 darktable(C 코드, 강력하지만 UX가 어려움)과 RawTherapee(같은 계열)뿐이었다. 두 제품 모두 강력하지만 "디자인이 90년대 같다"는 평가가 일관됐다. RapidRAW는 현대적인 UI + 빠른 GPU 응답성 + 비파괴 편집이라는 라이트룸의 핵심을 그대로 가져오면서, 코드는 누구나 들여다볼 수 있게 만들었다.
저자(Timon Käch)는 README에 직접 적어놨다 — "18살이고 도제 교육을 받으며 짬내서 만들었다." 2025년 6월 13일 Day 1부터 6월 27일까지 14일 동안 매일 진척 로그를 공개했다. Day 1에 Tauri 셋업과 brightness/contrast 셰이더, Day 8에 RAW 파일 지원, Day 13에 비트맵 기반 마스크 시스템 재작성까지의 속도가 트위터/Hacker News에서 화제가 됐다.
저자는 라이선스 선택 이유를 명시했다: "RapidRAW와 그 파생물이 영원히 오픈소스로 남게 하기 위해 AGPL을 골랐다." 즉 코드를 가져다 SaaS로 만들거나 클로즈드 데스크탑 제품에 끼워 팔 수 없다. 카피레프트가 가장 강한 라이선스 중 하나라서, "내가 만든 개선이 다시 본가에 환원될 거라는 확신"이 컨트리뷰터 유입에 유리하게 작동했다.
경쟁 무료 제품(darktable)에는 AI 자동 마스킹이 없다. RapidRAW는 로컬 CLIP 모델로 자동 태깅, ONNX Runtime으로 피사체·하늘·전경 자동 분리 마스크, 그리고 ComfyUI 서버 연동을 통한 생성형 채우기(Generative Replace)까지 한 앱에 넣었다. "라이트룸 대안"을 넘어 "라이트룸 + Photoshop의 생성형 채우기" 영역까지 한 번에 노린다.
| 항목 | RapidRAW | Adobe Lightroom | darktable |
|---|---|---|---|
| 가격 | 완전 무료 | 월 ~$10 구독 | 완전 무료 |
| 라이선스 | AGPL-3.0 | 독점 | GPLv3 |
| GPU 가속 | WGPU+WGSL (Vulkan/DX12/Metal/OpenGL) | OpenCL/Metal | OpenCL (선택적) |
| UI 모던함 | React 19 + Tauri | 네이티브, 표준 | GTK, 옛 느낌 |
| AI 자동 마스킹 | O (로컬 ONNX) | O (클라우드) | X |
| 생성형 채우기 | O (ComfyUI 연동) | O (Firefly 클라우드) | X |
| RAW 파일 지원 | rawler (dnglab 기반) | 광범위, 최고 수준 | 광범위 |
| 설치 크기 | 수십 MB (Tauri) | 2GB+ | ~200MB |
RapidRAW의 무거운 작업(파일 IO, RAW 디코딩, GPU 호출, AI 추론)은 전부 Rust에서 돌아간다. 핵심 의존성을 카테고리별로 정리한다:
| 카테고리 | 크레이트 | 역할 |
|---|---|---|
| 데스크탑 셸 | tauri 2.11 | 웹뷰 + Rust 백엔드 묶음. macos-private-api + rustls-tls 기능 활성 |
tauri-plugin-* | dialog · fs · shell · process · os · single-instance 6종 플러그인 | |
| GPU 처리 | wgpu 29 | WebGPU 표준 추상화 — Vulkan/DX12/Metal/OpenGL 백엔드 자동 선택 |
bytemuck 1.25 | Rust 구조체 ↔ GPU 버퍼 바이트 변환 (derive 매크로로 zero-copy) | |
| RAW · 이미지 | rawler | RAW 디코딩 (dnglab 프로젝트의 핵심, Canon CR3/Sony ARW/Nikon NEF 등) |
image 0.25 · imageproc · image-hdr | 일반 이미지 처리, HDR 합성 | |
mozjpeg-rs · webp · jxl-oxide · jxl-encoder | JPEG (mozjpeg 최적화) · WebP · JPEG XL 인코더/디코더 | |
| AI 추론 | ort 2.0.0-rc.10 | ONNX Runtime의 Rust 바인딩 — CLIP, 마스킹 모델 추론 |
tokenizers 0.23 · ndarray 0.16 | Hugging Face 토크나이저 + N차원 배열 (CLIP 텍스트 입력용) | |
| 동시성 | rayon 1.12 | "data-parallel for 루프" — CPU 코어 전부에 자동 분산 |
tokio 1 | async 런타임 (full features) — 파일 IO, 네트워크 | |
| 메모리 | mimalloc 0.1 | Microsoft의 빠른 할당자, 기본 시스템 malloc 대체 |
memmap2 0.9 | 대용량 RAW 파일을 디스크에서 메모리에 직접 매핑 (복사 0회) | |
| 수학 | nalgebra 0.34 | 일반 선형대수 — 변환 행렬, 색 공간 변환 |
glam 0.32 | 게임/그래픽용 SIMD 가속 벡터·행렬 (셰이더 입력 준비용) | |
| 메타데이터 | kamadak-exif 0.6 · little_exif 0.6 | EXIF 읽기/쓰기 — 카메라 모델, 셔터/조리개 등 |
quick-xml 0.40 | XMP 메타데이터 (Adobe 표준 사이드카 포맷) 처리 | |
| 해시·식별 | blake3 · sha2 · image_hasher | 썸네일 캐시 키, 이미지 지문 (perceptual hash) |
| 유틸 | trash 5 · walkdir · tempfile · chrono | OS 휴지통, 폴더 재귀, 임시 파일, 시간 |
Cargo.toml에 적힌 의존성 한 줄이 곧 크레이트 하나다.UI는 일반 웹 앱과 거의 똑같다. Tauri가 운영체제의 웹뷰(macOS=WebKit, Windows=WebView2, Linux=WebKitGTK)에 React 앱을 실어주고, JS에서 호출한 명령은 IPC로 Rust 함수에 도달한다.
| 카테고리 | 패키지 | 역할 |
|---|---|---|
| 코어 | react 19.2 + react-dom 19.2 | 최신 React (Compiler, Actions 시대) |
typescript 6 | TS 6 — 신형 컴파일러 | |
| 빌드 | vite 8 + @vitejs/plugin-react 6 + esbuild 0.28 | 초고속 dev 서버 + 프로덕션 번들 |
| 스타일링 | tailwindcss 4.3 + @tailwindcss/vite | Tailwind 4 (Lightning CSS 엔진) |
| 상태관리 | zustand 5 | Redux 대안, 훨씬 가벼움 — 사진 편집 슬라이더 값들이 다 여기에 |
@dnd-kit/core 6.3 | 패널 드래그앤드롭 (라이트룸식 분할 화면) | |
| 캔버스·이미지 | konva 10 + react-konva 19 | HTML5 Canvas 위 마스킹 브러시·기울기 그리기 |
react-image-crop 11 | 크롭 박스 UI | |
react-window 2 | 썸네일 그리드 가상화 (1만 장 폴더도 60fps) | |
| 애니메이션 | framer-motion 12.38 | 패널 슬라이드, 페이드 전환 |
| 색 픽커 | @uiw/color-convert · @uiw/react-color-wheel | 색 변환 + 컬러 휠 (색조정용) |
| 유틸 | lodash.debounce · lodash.throttle · uuid · clsx | 슬라이더 throttling, 사이드카 UUID |
| 인증 | @clerk/react 6.6 | "옵셔널 클라우드 구독" 로그인 — 본체 기능과 분리 |
| 알림 · 아이콘 | react-toastify 11 · lucide-react 1.14 · simple-icons | 토스트 + 아이콘셋 |
웹 개발자가 데스크탑 사진 편집기를 만들 수 있는 시대가 됐다는 뜻이다. 같은 React 컴포넌트가 웹 브라우저(개발 모드 npm run dev) → 그리고 데스크탑 OS 네이티브 윈도우(npm start = tauri dev) 양쪽에서 똑같이 동작한다. 핫 리로드도 그대로 살아있다.
"32-bit GPU 파이프라인"이라는 README의 표현이 핵심이다. 일반 사진 앱은 8비트(0~255) 정수로 픽셀을 들고 다닌다. RapidRAW는 RAW 디코딩 직후부터 모든 픽셀을 RGBA 각 32비트 부동소수점으로 들고 있다. 그리고 모든 연산(노출, 톤, 색조정, 마스크 합성)을 WGSL 셰이더로 작성해 GPU의 수천 코어가 동시에 픽셀에 적용한다.
.msi / .dmg 파일로 배포. Tauri가 코드사이닝, 노터라이즈, 자동 업데이터까지 묶어줌.io.github.CyberTimon.RapidRAW), Debian 계열은 .deb, Arch 계열은 AUR의 rapidraw-bin. 사실상 모든 주요 배포판 커버.target_os = "android" 분기가 있다. NDK, JNI 의존성이 있고, 인앱에 include_dir로 에셋을 굽는다. 실험적이지만 모바일까지 노린다는 의지가 보임.profile.release에서 codegen-units = 1(전체 한 번에 컴파일, 최적화 극대화) + lto = true(링크 타임 최적화) + strip = true(디버그 심볼 제거). 그리고 profile.dev는 자기 코드만 opt-level=2, 의존성은 opt-level=3으로 — 디버그 빌드도 의존성은 release처럼 최적화돼서 dev 사이클이 빠르다.모든 편집 결과는 원본 파일에 절대 쓰지 않는다. 대신 같은 폴더에 IMG_001.CR3가 있으면 IMG_001.rrdata라는 작은 사이드카 파일을 만들어 "노출 +0.3, 섀도우 +25, 마스크 1번에 색온도 +10..." 같은 편집 명령 목록만 적는다. 화면에 보이는 결과물은 매번 GPU에서 새로 합성된 프리뷰다.
실수로 너무 강하게 보정해도 원본은 그대로다. 1년 뒤에 봐도 똑같은 .rrdata 파일을 적용하면 같은 결과가 나온다. 그리고 .rrdata 파일을 친구에게 보내면 친구는 자기 RAW에 그 "레시피"를 적용할 수 있다 — 이것이 Lightroom의 프리셋 시장이 생긴 원리다.
Tauri는 Electron과 달리 Node.js를 번들하지 않는다. 대신 운영체제가 이미 갖고 있는 WebView(시스템 브라우저 엔진)를 빌려 쓰고, 백엔드는 컴파일된 Rust 바이너리 한 개로 끝낸다. 결과: 설치 크기 수십 MB(Electron 앱은 100MB+), 메모리 사용량 절반.
// 프런트(JS) → 백엔드(Rust) 호출 예
// React 컴포넌트 안에서
import { invoke } from '@tauri-apps/api/core';
const preview = await invoke('apply_exposure', {
imageId: 'uuid-xxx',
exposure: 0.3
});
// Rust 측 (src-tauri/src/commands.rs 안에 이런 식)
#[tauri::command]
async fn apply_exposure(image_id: String, exposure: f32)
-> Result<String, String> {
// WGPU에 셰이더 uniform 업데이트
// 결과를 base64 PNG로 반환
}
한 장의 사진을 보정하는 흐름:
"피사체만 자동 선택"을 클릭하면 화면이 멈추면 안 된다. RapidRAW는 ONNX Runtime(ort 크레이트)을 통해 로컬에 미리 받아둔 세그멘테이션 모델을 별도 Tokio 태스크에서 돌린다. 결과 마스크는 다시 비트맵으로 변환되어 GPU 셰이더의 입력 텍스처가 된다.
ONNX는 "다른 프레임워크(PyTorch, TensorFlow)에서 학습한 모델을 한 가지 표준으로 저장하는 포맷"이다. 저자는 모델을 직접 학습한 게 아니라 이미 공개된 무료 세그멘테이션 모델을 ONNX로 변환해 사용한다. Rust 앱이 PyTorch 런타임을 통째로 들고 다닐 필요 없이 ONNX Runtime 하나면 추론을 돌릴 수 있다는 점이 매력.
"생성형 채우기" 같은 무거운 작업은 RapidRAW 본체가 직접 안 한다. 대신 RapidRAW-AI-Connector라는 별도 미들웨어가 로컬 ComfyUI 서버에 붙어서 처리한다. 똑똑한 점은 원본 이미지는 한 번만 업로드해서 캐싱하고, 이후 편집할 때마다 마스크 + 텍스트 프롬프트만 보낸다는 것. 4K 사진을 매번 다시 전송하지 않아 응답성이 살아남는다.
rawler(RAW 디코더) 크레이트의 fork 버전(CyberTimon/RapidRAW-DngLab)을 서브모듈로 연결한다. git clone --recurse-submodules를 깜빡하면 빌드가 깨지는 흔한 함정.package.json → "start": "tauri dev" — 개발 모드 진입점. Vite 핫 리로드 + Rust 자동 재빌드.src-tauri/Cargo.toml — Rust 의존성 단일 진실. 모든 GPU/AI/RAW 처리 능력의 출처.src-tauri/src/main.rs — Tauri 앱 시작 스텁 (fn main() { rapidraw_lib::run(); } 4줄). 실제 명령 등록·앱 빌더·상태 초기화는 lib.rs에 있다 (Tauri 2 표준 패턴).이 레포의 가장 큰 학습 가치다. Tauri는 "Electron의 더 가벼운 후속작" 포지션인데, 막상 처음 만들려고 하면 JS↔Rust IPC, 명령 시그니처, 권한 설정, 번들링·코드사이닝까지 학습 비용이 꽤 있다. RapidRAW는 src-tauri/src/commands/ 폴더를 보면 명령을 어떻게 모듈로 쪼개는지, tauri.conf.json에서 윈도우/권한/번들을 어떻게 설정하는지 실전 예시가 모두 있다.
"파일 카운터" Tauri 앱을 만들어보자 — 폴더를 드래그하면 안의 파일 수를 세서 보여주는 미니 앱. JS에서 invoke('count_files', { path })를 호출하고 Rust에서 walkdir로 카운트하면 끝. Tauri의 IPC, 파일 시스템 권한, 번들링까지 한 번에 경험한다.
GPU 프로그래밍은 "어렵다"는 평판이 있지만, WebGPU 표준은 OpenGL/Vulkan보다 진입 장벽이 훨씬 낮다. RapidRAW의 src-tauri/src/shaders/*.wgsl은 실전 셰이더 모음이다 — 노출, 톤 매핑, 색 휠, 마스크 합성 같은 익숙한 사진 보정 효과가 GPU 코드로 어떻게 표현되는지 직접 비교할 수 있다.
WGPU의 공식 튜토리얼 "Learn WGPU"를 따라가며 첫 셰이더(브라이트니스만 조절)를 작성해보자. 그리고 RapidRAW의 brightness.wgsl이 어떻게 다른지 비교. RapidRAW는 8비트 입력을 받지 않고 32비트 float 입력을 받기 때문에 클리핑(잘림)이 없다 — 그 차이를 직접 느껴보면 32비트 파이프라인의 가치가 보인다.
편집기 UI는 슬라이더 수십 개가 동시에 움직인다. Redux로 짜면 보일러플레이트 폭증이라 Zustand 같은 가벼운 라이브러리가 사실상 표준이 되어가는 중. RapidRAW의 src/stores/를 읽으면 "여러 슬라이더 값을 어떻게 한 store에 모으고, undo/redo를 어떻게 구현하는지" 실전 답을 얻는다.
이 패턴은 사진/영상 편집기뿐 아니라 코드 에디터, IDE, 노트 앱에도 응용된다. Git의 stash, VSCode의 .vscode 폴더, Lightroom의 .xmp 파일, RapidRAW의 .rrdata가 다 같은 원리다. "원본은 절대 안 건드리고, 변경 의도만 별도 파일에 저장한다"는 발상.
RapidRAW는 PyTorch 한 줄도 의존하지 않으면서 AI 마스킹을 수행한다. ort 크레이트가 ONNX Runtime의 Rust 바인딩이고, tokenizers로 Hugging Face 토크나이저를 들어와 CLIP 입력을 만든다. "PyTorch 학습 → ONNX export → 어디서나 추론"이라는 산업 표준 흐름을 데스크탑 앱 안에서 어떻게 적용하는지 살아있는 사례다.
vite.config.js의 clearScreen: false, strictPort: true, HMR 포트 설정 같은 Tauri 특유의 깨알 옵션들이 들어있다. "데스크탑 앱에서 핫 리로드가 작동한다"는 건 마법이 아니라 이런 설정의 누적이다.
.github/workflows/의 워크플로를 보면 Windows .msi, macOS .dmg(notarization 포함), Linux .deb + Flatpak + AppImage까지 한 푸시로 다 빌드되는 매트릭스가 있다. 1인 개발자가 4개 OS에 동시 배포할 수 있는 비결.
| 항목 | 최소 | 권장 | 설명 |
|---|---|---|---|
| OS — Windows | Windows 10 | Windows 11 | DirectX 12 또는 Vulkan 백엔드 |
| OS — macOS | macOS 13 Ventura | 최신 | Metal 백엔드 (Apple Silicon에서 가장 좋음) |
| OS — Linux | Ubuntu 22.04+ | 최신 | Vulkan 또는 OpenGL, WebKitGTK 필요 |
| RAM | 8 GB | 16 GB 이상 | RAW 파일 1장 = 보통 25~60 MB, undo 히스토리·마스크 누적되면 메모리 빠르게 먹음 |
| GPU | 2015년 이후 통합 그래픽 | 전용 GPU (NVIDIA/AMD/Apple Silicon) | Pascal 이전(GTX 9xx 이하) NVIDIA는 README에 "improving speed 우선과제"로 표시됨 |
| 저장공간 | 500 MB | SSD 권장 | 본체는 가볍지만 사이드카 + 캐시 + 썸네일이 누적 |
RapidRAW는 GPU 백엔드를 자동 선택하는데, 종종 시스템과 안 맞는 백엔드가 선택돼서 첫 이미지 진입 시 충돌한다. Settings → Processing → Processing Backend를 Auto에서 Vulkan / DirectX12 / OpenGL / Metal 중 OS에 맞는 걸로 수동 지정해야 한다. README의 "Common Problems" 섹션에 명시된 1순위 트러블슈팅.
GNOME + NVIDIA + Wayland 조합에서 WebKit이 충돌한다(저자 잘못이 아니라 WebKit/NVIDIA 드라이버 문제). 우회법:
WEBKIT_DISABLE_DMABUF_RENDERER=1 RapidRAW 또는 WEBKIT_DISABLE_COMPOSITING_MODE=1 RapidRAW로 실행. 또는 X11로 전환하거나 AMD/Intel GPU 사용.
"Build from Source"를 따라 실제로 컴파일해보자. git clone --recurse-submodules, npm install, npm start 세 줄이지만 Rust 처음 설치하는 사람이면 30분~1시간 걸린다. 컴파일 동안 Rust 컴파일러가 의존성 200개를 빌드하는 것을 구경하는 경험 자체가 학습이다.
"Sepia(세피아 톤)" 슬라이더를 만들어보자. (1) src-tauri/src/shaders/에 새 WGSL 파일 1개 추가 (2) commands/에 새 명령 1개 등록 (3) React 컴포넌트에서 슬라이더 1개 추가, invoke로 호출. 끝나면 Tauri 앱이 어떻게 layer되는지 한 사이클 완전히 이해하게 된다.
본인 카메라 RAW가 지원 안 되면 rawler 레포(dnglab의 일부)에 카메라 프로파일 PR을 보낸 다음, 그 변경을 RapidRAW의 fork에 동기화해서 직접 빌드한다. README의 "Image format issues" 섹션이 정확히 이 워크플로를 가이드한다. 오픈소스에 첫 기여를 해보는 좋은 핑계.
3D LUT(예: .cube 파일)는 영화/사진 색보정의 표준 포맷이다. Davinci Resolve나 Photoshop에서 마음에 드는 룩을 만들어 .cube로 export → RapidRAW의 LUT 폴더에 넣고 적용. 그리고 WGSL 셰이더에서 LUT 텍스처가 어떻게 샘플링되는지(data/ 또는 shaders/ 살펴봄) 직접 읽어보면 색보정의 본질이 보인다.
로컬에 ComfyUI 설치 → RapidRAW-AI-Connector 미들웨어 실행 → RapidRAW의 Settings에서 연결. 그리고 ComfyUI에서 "흐림 효과 + Lora 적용 + 디퓨전 인페인팅" 같은 커스텀 워크플로를 .json으로 export해 RapidRAW에 import. RAW 사진 한 장에 디퓨전 모델 마법이 붙는 워크플로를 직접 손에 쥐게 된다.
| 주차 | 주제 | 목표 산출물 |
|---|---|---|
| 1주 | Rust 입문 (The Book 1~6장) | "hello world", 변수, 소유권 개념 이해 |
| 2주 | Rust 트레이트 · 에러 처리 · async | tokio로 비동기 파일 카운터 CLI 작성 |
| 3주 | Tauri 입문 (Quick Start) | "폴더 드래그 → 파일 수 표시" 데스크탑 앱 |
| 4주 | Tauri 명령 · 권한 · 번들링 | 위 앱을 .msi / .dmg / .deb로 빌드 |
| 5주 | React 19 + Zustand 복습 | 슬라이더 상태를 Zustand로 관리하는 미니 앱 |
| 6주 | WebGPU 입문 (Learn WGPU 1~5장) | WGSL로 첫 셰이더 — 화면을 빨강으로 칠하기 |
| 7주 | WGSL 셰이더로 이미지 처리 | JPEG 한 장에 brightness/contrast 적용 |
| 8주 | RapidRAW 클론 + 빌드 | 로컬에서 RapidRAW 빌드 성공, 직접 사진 한 장 편집 |
| 9주 | RapidRAW 셰이더 코드 읽기 | shaders/*.wgsl 5개 골라 노트 정리 |
| 10주 | RAW 파이프라인 깊이 (rawler, demosaicing) | "베이어 패턴 → RGB" 변환의 원리 한 페이지 정리 |
| 11주 | ONNX Runtime + 작은 모델 직접 추론 | MobileNet ONNX를 ort로 Rust에서 추론하는 미니 앱 |
| 12주 | 본인 사진 편집 워크플로를 RapidRAW로 완전 이관 | Lightroom 없이 한 달 살기 가능 여부 평가 |
@vertex, @fragment, @compute 함수를 정의하면 GPU가 실행.