From 1e37d489df91eade8ff91ebd8087a6707197a2cf Mon Sep 17 00:00:00 2001 From: sayed3li97 Date: Mon, 6 Jul 2026 00:40:54 +0400 Subject: [PATCH 1/2] docs: animated architecture diagrams (SVG, brand style) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Five self-contained, dependency-free animated SVG diagrams in the dark / monospace / blue-accent house style, explaining how camera_pro works: - architecture-ffi-flow — a frame's path across the one Dart↔native FFI hop - capability-passport-tier — Supported/NotSupported → Full/Standard/Basic - visual-aids-pipeline — GPU/CPU dispatch → the five overlays - digital-controls — the "no sensor controls → still DSLR" trick - web-puredart-split — the conditional export that keeps dart:ffi off web - Gallery: doc/diagrams/README.md. Hero diagram embedded in the main README ("Architecture at a glance") and ARCHITECTURE.md. - SVGs degrade gracefully: nodes are visible without CSS animation (fill-mode both, no base opacity:0), so renderers that strip animation still show the full diagram. They animate on GitHub. - .pubignore now excludes doc/ entirely (diagrams + screenshots are GitHub-facing; pub.dev resolves README images from the repo). Archive stays ~376 KB. Docs/assets only — no code change. Co-Authored-By: Claude Opus 4.8 --- .pubignore | 2 +- ARCHITECTURE.md | 5 ++ README.md | 13 ++++ doc/diagrams/README.md | 43 ++++++++++++ doc/diagrams/architecture-ffi-flow.svg | 85 +++++++++++++++++++++++ doc/diagrams/capability-passport-tier.svg | 55 +++++++++++++++ doc/diagrams/digital-controls.svg | 59 ++++++++++++++++ doc/diagrams/visual-aids-pipeline.svg | 68 ++++++++++++++++++ doc/diagrams/web-puredart-split.svg | 61 ++++++++++++++++ 9 files changed, 390 insertions(+), 1 deletion(-) create mode 100644 doc/diagrams/README.md create mode 100644 doc/diagrams/architecture-ffi-flow.svg create mode 100644 doc/diagrams/capability-passport-tier.svg create mode 100644 doc/diagrams/digital-controls.svg create mode 100644 doc/diagrams/visual-aids-pipeline.svg create mode 100644 doc/diagrams/web-puredart-split.svg diff --git a/.pubignore b/.pubignore index 97f5406..a2e6bd4 100644 --- a/.pubignore +++ b/.pubignore @@ -1 +1 @@ -doc/web/ +doc/ diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 458a8ad..0ac656a 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -13,6 +13,11 @@ > for the full picture — every ✅ there is verified, and the gaps are listed > honestly. +![camera_pro architecture — a camera frame crossing the one FFI boundary](doc/diagrams/architecture-ffi-flow.svg) + +> More animated diagrams (capability → tier, visual-aids pipeline, digital +> controls, web split) live in [doc/diagrams/](doc/diagrams/). + --- ## Table of Contents diff --git a/README.md b/README.md index 72ebed4..28ed463 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,19 @@ Most Flutter camera packages wrap platform APIs directly and surface raw excepti --- +## Architecture at a glance + +A camera frame's path from the sensor, across the single Dart ↔ native FFI +boundary, up to the live overlay: + +![camera_pro architecture — a camera frame crossing the one FFI boundary](doc/diagrams/architecture-ffi-flow.svg) + +More animated diagrams — **capability passport → tier**, the **visual-aids +pipeline**, the **digital manual-control** trick, and the **web pure-Dart +split** — in **[doc/diagrams/](doc/diagrams/)**. (They animate on GitHub.) + +--- + ## Feature status ### Architecture diff --git a/doc/diagrams/README.md b/doc/diagrams/README.md new file mode 100644 index 0000000..3d05eec --- /dev/null +++ b/doc/diagrams/README.md @@ -0,0 +1,43 @@ +# camera_pro — architecture diagrams + +Animated explanatory diagrams of how `camera_pro` works. They render (and +animate) natively on GitHub. Each is a self-contained, dependency-free SVG. + +> On pub.dev, SVGs may render as a static first frame — view this page on +> GitHub for the animation. + +## Architecture · the one FFI hop + +A camera frame's path from sensor to live overlay, and the single Dart ↔ native +boundary it crosses. + +![Architecture and FFI flow](architecture-ffi-flow.svg) + +## Capability passport → tier + +Every feature is reported as `Supported` or `NotSupported`; `determineTier` +maps the passport to Full / Standard / Basic. + +![Capability passport to tier](capability-passport-tier.svg) + +## Visual-aids pipeline + +One preview frame, dispatched to the Metal GPU when available or the SIMD CPU +core otherwise — both produce byte-identical overlays. + +![Visual-aids pipeline](visual-aids-pipeline.svg) + +## Digital manual-control pipeline + +When a camera exposes no sensor controls (the macOS built-in camera, most +browsers), the six controls are applied digitally per frame — so the device +still reaches `CameraTier.full`. + +![Digital manual-control pipeline](digital-controls.svg) + +## Web pure-Dart split + +A single conditional export keeps `dart:ffi` / `dart:io` off the web build; the +browser gets a pure-Dart `WebCameraBackend` with the C kernels ported to Dart. + +![Web pure-Dart split](web-puredart-split.svg) diff --git a/doc/diagrams/architecture-ffi-flow.svg b/doc/diagrams/architecture-ffi-flow.svg new file mode 100644 index 0000000..93f95a2 --- /dev/null +++ b/doc/diagrams/architecture-ffi-flow.svg @@ -0,0 +1,85 @@ + + + camera_pro architecture: a camera frame crosses one FFI boundary from native to Dart + Bottom lane (native): Camera to HAL backend to C core and Metal. One dashed FFI hop up to the Dart lane: NativeCore, CameraProController, live preview. + + + + + + + + + + + + DART + NATIVE · C / PLATFORM + + + FFI BOUNDARY + + + + + + + + + + + + + + Camera + sensor + + + + HAL backend + AVFoundation · V4L2 · MF · Web + + + + C core + Metal + SIMD kernels · DNG · GPU + + + + + NativeCore · FFI + @Native · isLeaf on O(1) + + + + CameraProController + capabilities · tiers · errors + + + + + + LIVE + + + + + + + + + + dashed: the one FFI hop across the Dart ↔ native boundary · solid: same side + A camera frame: sensor → C / Metal kernel → live overlay. camera_pro + diff --git a/doc/diagrams/capability-passport-tier.svg b/doc/diagrams/capability-passport-tier.svg new file mode 100644 index 0000000..8f2aa23 --- /dev/null +++ b/doc/diagrams/capability-passport-tier.svg @@ -0,0 +1,55 @@ + + + camera_pro capability passport to tier + The backend reports each feature as Supported or NotSupported; determineTier maps the passport to Full, Standard, or Basic. + + + + + + + Backend + device caps + + + + + CAPABILITY PASSPORT + + + ISO + Shutter + White balance + Focus + Zoom + Aperture + + + + + + determineTier() + pure function + + + + + + Full manual (DSLR) + + + Standard + + Basic + + Supported NotSupported (with a reason) + iso + shutter + focus + white balance all supported → Full + diff --git a/doc/diagrams/digital-controls.svg b/doc/diagrams/digital-controls.svg new file mode 100644 index 0000000..faf0340 --- /dev/null +++ b/doc/diagrams/digital-controls.svg @@ -0,0 +1,59 @@ + + + camera_pro digital manual-control pipeline + When the camera exposes no sensor controls, the setters map to digital state applied per frame in the C core, so every control still works and the tier is Full. + + + + + + + + + CONTROLLER SETTERS + + + setIso + setExposure + setWhiteBalance + setFocus + setZoom + + + + + + digital state + gain · bias · temp · blur · zoom + + + + + C core · per frame + adjust · zoom · box blur + + + + + raw + + adjusted + + before + after + + + + + + + No sensor controls on the device? Applied digitally, every frame. + Same six controls, real results → CameraTier.full · macOS + web + diff --git a/doc/diagrams/visual-aids-pipeline.svg b/doc/diagrams/visual-aids-pipeline.svg new file mode 100644 index 0000000..44ef5c5 --- /dev/null +++ b/doc/diagrams/visual-aids-pipeline.svg @@ -0,0 +1,68 @@ + + + camera_pro visual-aids pipeline + A preview frame is dispatched to Metal GPU when available or the SIMD CPU core otherwise; both produce byte-identical overlays composited on the live preview. + + + + + + + + + + Preview frame + RGBA + + + + + + + MetalCompute · GPU + runtime MSL kernels + + + + NativeCore · CPU + NEON / SSSE3 SIMD + + GPU if available, else CPU + byte-identical output + + + + + + overlay kernel + one pass per frame + + + + + histogram + focus peaking + zebra + false color + waveform + + + + + + LIVE + + + + + + + + GPU and CPU paths are cross-checked byte-identical. histogram · peaking · zebra · false color · waveform + diff --git a/doc/diagrams/web-puredart-split.svg b/doc/diagrams/web-puredart-split.svg new file mode 100644 index 0000000..edd3328 --- /dev/null +++ b/doc/diagrams/web-puredart-split.svg @@ -0,0 +1,61 @@ + + + camera_pro web conditional-import split + camera_pro.dart uses a conditional export so the native build gets dart:ffi and the C core, while the web build gets pure Dart with getUserMedia and no dart:ffi or dart:io. + + + + + + + + + + camera_pro.dart + barrel · conditional export + + + + export ... if (dart.library.js_interop) ... + + + + NATIVE BUILD + WEB BUILD + + + + platform_io.dart + dart:ffi · dart:io + + + + + NativeCore (FFI) + C core + AVFoundation · V4L2 · MF + + + + + platform_web.dart + no dart:ffi · no dart:io + + + + + WebCameraBackend · pure Dart + getUserMedia · ported kernels + + + + + + + One import switch, resolved at compile time. + The web build never references dart:ffi / dart:io · same public API on both + From 54d0240276fb00acf65f5ae68ebca4d6ba28349e Mon Sep 17 00:00:00 2001 From: sayed3li97 Date: Mon, 6 Jul 2026 00:51:33 +0400 Subject: [PATCH 2/2] docs: five more animated diagrams (capture, SIMD, burst, CI, buffer pool) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same house style, extending the set to ten: - capture-paths — capturePhoto → PNG / linear-DNG (EXIF) / video - simd-arch — NEON · SSSE3 · scalar, bit-exact (+ the honest bench) - burst-bracket — captureBurst(5) ≈1.2s and −2/0/+2 EV with measured YAVG - ci-matrix — native.yml across macOS / Ubuntu / Windows / web, green - buffer-pool-ring — the lock-free, cache-aligned, GC-free frame ring All self-contained SVG, well-formed (xmllint), graceful-degrading (visible without CSS animation), added to the doc/diagrams gallery. Docs/assets only. Co-Authored-By: Claude Opus 4.8 --- doc/diagrams/README.md | 37 ++++++++++++++++++++++++++ doc/diagrams/buffer-pool-ring.svg | 43 +++++++++++++++++++++++++++++++ doc/diagrams/burst-bracket.svg | 35 +++++++++++++++++++++++++ doc/diagrams/capture-paths.svg | 41 +++++++++++++++++++++++++++++ doc/diagrams/ci-matrix.svg | 42 ++++++++++++++++++++++++++++++ doc/diagrams/simd-arch.svg | 43 +++++++++++++++++++++++++++++++ 6 files changed, 241 insertions(+) create mode 100644 doc/diagrams/buffer-pool-ring.svg create mode 100644 doc/diagrams/burst-bracket.svg create mode 100644 doc/diagrams/capture-paths.svg create mode 100644 doc/diagrams/ci-matrix.svg create mode 100644 doc/diagrams/simd-arch.svg diff --git a/doc/diagrams/README.md b/doc/diagrams/README.md index 3d05eec..fb5fac7 100644 --- a/doc/diagrams/README.md +++ b/doc/diagrams/README.md @@ -41,3 +41,40 @@ A single conditional export keeps `dart:ffi` / `dart:io` off the web build; the browser gets a pure-Dart `WebCameraBackend` with the C kernels ported to Dart. ![Web pure-Dart split](web-puredart-split.svg) + +## Capture paths + +One frame, three encoders: PNG via `dart:ui`, a dependency-free linear-DNG +writer (with EXIF), and video recording — ffprobe / ffmpeg verified. + +![Capture paths](capture-paths.svg) + +## SIMD across architectures + +The histogram kernel has NEON, SSSE3, and scalar paths that produce bit-exact +output (x86 checked under Rosetta 2 + CI). The honest twist: clang's +auto-vectorized scalar edges the hand-written NEON on the M1. + +![SIMD across architectures](simd-arch.svg) + +## Burst + EV bracket + +`captureBurst(5)` fires five frames in about 1.2s; `captureExposureBracket` +takes three at −2 / 0 / +2 EV, with measured mean luminance. + +![Burst and EV bracket](burst-bracket.svg) + +## CI matrix + +`native.yml` runs on every push across macOS, Ubuntu, Windows, and web — every +✅ in the docs is one of these runs. + +![CI matrix](ci-matrix.svg) + +## Lock-free buffer pool + +Frames ride a ring of pre-allocated, cache-aligned buffers; `acquire`/`release` +are O(1) lock-free atomics (and `isLeaf` FFI calls), so nothing per-frame hits +the Dart GC. + +![Lock-free buffer pool](buffer-pool-ring.svg) diff --git a/doc/diagrams/buffer-pool-ring.svg b/doc/diagrams/buffer-pool-ring.svg new file mode 100644 index 0000000..4f5091b --- /dev/null +++ b/doc/diagrams/buffer-pool-ring.svg @@ -0,0 +1,43 @@ + + + camera_pro lock-free buffer pool + Frames cycle through a ring of pre-allocated, cache-aligned buffers; acquire and release are O(1) lock-free atomics, so no per-frame allocation reaches the Dart garbage collector. + + + + + + + + + + + + + + + + RING + 6 × cache-aligned + + + + acquire() + release() + + + Why a ring? + · pre-allocated, cache-aligned (64 B) + · acquire / release: O(1) lock-free atomics + · the FFI calls are isLeaf + · zero per-frame allocation hits the Dart GC + · producer fills · consumer hands to FFI + + + Frames ride the ring, not the heap — no per-frame GC pressure on the hot path. + diff --git a/doc/diagrams/burst-bracket.svg b/doc/diagrams/burst-bracket.svg new file mode 100644 index 0000000..935f3ce --- /dev/null +++ b/doc/diagrams/burst-bracket.svg @@ -0,0 +1,35 @@ + + + camera_pro burst and EV bracket + captureBurst fires five frames in about 1.2 seconds; captureExposureBracket takes three frames at minus two, zero, and plus two EV with measured mean luminance. + + + + + BURST · captureBurst(5) + + + + + + + + + + + 5 shots ≈ 1.2 s + + EV BRACKET · captureExposureBracket([-2, 0, +2]) + + -2YAVG 25.8 + 0YAVG 96.9 + +2YAVG 183.4 + + + Both run through the normal capture path. + measured mean luminance, verified live. + diff --git a/doc/diagrams/capture-paths.svg b/doc/diagrams/capture-paths.svg new file mode 100644 index 0000000..2e4ac16 --- /dev/null +++ b/doc/diagrams/capture-paths.svg @@ -0,0 +1,41 @@ + + + camera_pro capture paths + capturePhoto routes one frame to three encoders: PNG via dart:ui, a linear-DNG writer, and a video recorder. + + + + + + + + + capturePhoto() + png · raw · rawPlusJpeg + + + + + + + + + + + + PNG · dart:uiimage.toByteData + linear-DNG writerC core / pure-Dart + video recorderMediaRecorder / AVFoundation + + .png + .dng+ EXIF + .mov / .webm + + + + One frame, three encoders — PNG · linear-DNG with EXIF · H.264 / webm. verified: ffprobe · ffmpeg + diff --git a/doc/diagrams/ci-matrix.svg b/doc/diagrams/ci-matrix.svg new file mode 100644 index 0000000..2ae9ea6 --- /dev/null +++ b/doc/diagrams/ci-matrix.svg @@ -0,0 +1,42 @@ + + + camera_pro CI matrix + Every push runs native.yml across macos-14, ubuntu, windows, and web runners; all pass. + + + + + + + + + git push + native.yml + + + + + + + + + macos-14C harness · Apple backend · Metal cross-check + ubuntugcc -Werror · -mssse3 · V4L2 lifecycle + windowsMSVC /W4 · Media Foundation lifecycle + webbrowser tests · web-app build + + + + + + + + + + + Every push · four runners · all green. the checks in the docs are these runs + diff --git a/doc/diagrams/simd-arch.svg b/doc/diagrams/simd-arch.svg new file mode 100644 index 0000000..9a4a6fc --- /dev/null +++ b/doc/diagrams/simd-arch.svg @@ -0,0 +1,43 @@ + + + camera_pro SIMD across architectures + The histogram kernel has NEON, SSSE3, and scalar paths that all produce bit-exact output; a bench shows auto-vectorized scalar edging hand-written NEON on M1. + + + + + + + + + histogram kernel + fixed-point luma + + + + + + + + + + NEON · arm64 + SSSE3 · x86 + scalar · fallback + + bit-exactverified on CI + + 1080p histogram · M1 Pro + + scalar2.3 ms + NEON3.1 ms + + + + + Same bits on every arch — x86 checked under Rosetta 2 + CI. honest: auto-vectorized scalar edges hand-NEON here +