# harshit-dhanwalkar/asciicam architecture

> Architecture diagram of the GitHub repository harshit-dhanwalkar/asciicam, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-07-31). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/harshit-dhanwalkar/asciicam
- Repository: https://github.com/harshit-dhanwalkar/asciicam

## Overview

#### Purpose and Entry Point
AsciiCam is a C99 terminal webcam viewer that captures live video, transforms frames into grayscale or RGB-derived terminal cells, and renders ASCII/Unicode/ANSI truecolor output in real time. The executable entry point and main control loop are in `C/src/main.c`; build orchestration is `C/Makefile`.

#### Capture Abstraction and Platform Boundary
Camera acquisition is selected at compile time behind a common capture interface. Linux uses V4L2, macOS uses AVFoundation, and Windows uses Media Foundation. Platform conditionals and shared declarations belong at the boundary rather than in rendering code.
- `C/include/capture.h`
- `C/src/capture_linux.c`
- `C/src/capture_macos.c`
- `C/src/capture_windows.c`

Linux additionally exposes live hardware exposure, contrast, and white-balance controls through V4L2 ioctls; the non-Linux backends retain capture but stub those controls.

#### Frame Processing and Terminal Rendering
The rendering subsystem converts camera-format frames (YUYV) to grayscale or RGB, applies selected visual processing, maps brightness to a character ramp, and writes terminal escape sequences/cells. It owns render modes including ASCII, braille, blocks, half-blocks, and dots, plus ANSI truecolor and dithering behavior.
- `C/src/ascii.c`
- `C/include/ascii.h`
- `C/charsets/ascii.txt`

Character ramps are external text assets, enabling runtime charset selection and reload. Built-in selectable ramps reside under `C/charsets/`, including line, dot, and shade-oriented mappings.

#### Filter and Plugin Pipeline
Filters are dynamically loaded shared objects and form a frame-processing pipeline before final rendering. The repository supplies invert, threshold, and edge-detection plugins; edge detection supports Sobel variants and Laplacian behavior. Plugin loading, invocation, change detection, unload/reload, and runtime parameter selection are centralized separately from individual filter implementations.
- `C/src/plugins.c`
- `C/include/plugins.h`
- `C/filters/edge_detect.c`

On Linux, live plugin and charset reload relies on `inotify` plus `dlopen`; plugins are compiled as `.so` files. This is a key runtime extension boundary: plugin code operates through the interface declared by `plugins.h`, while the host owns loading and lifecycle.

#### Main Loop, Input, and Timing
`main.c` coordinates command-line options, camera setup, terminal interaction, plugin/charset state, frame acquisition, processing, and shutdown. Runtime key commands change render mode, edge mode, charset, depth effect, plugin selection/parameters, and camera controls. Frame cadence is capped using monotonic-clock timing and sleep-based pacing.
- `C/src/main.c`
- `C/src/timing.c`
- `C/include/timing.h`

#### Concurrent Frame Exchange
A producer/consumer design provides double-buffered capture-to-render exchange. This isolates camera acquisition from terminal rendering and avoids handing partially written frames to the renderer. The README notes the active sharing implementation exists independently while integration in the primary loop is partial/stubbed.
- `C/src/thread_sharing.c`
- `C/include/thread_sharing.h`
- `C/src/main.c`

#### Runtime/Foundation Layer
Linux targets a bundled `nolibc`-style support layer for allocation, I/O, startup, syscall wrappers, signals, formatting, and option parsing; it reduces dependence on normal libc APIs. The build still materially depends on platform camera APIs and, on Linux, `libdl` and `pthread`.
- `C/lib/nolibc.h`
- `C/lib/nl_alloc.c`
- `C/lib/nl_start.c`

The operational flow is: startup/options → platform capture initialization → persistent frame/output buffer setup → capture and optional threaded handoff → plugin/filter processing → charset/render-mode mapping and terminal output → timing/input/reload polling → cleanup.

Main entry points: [`C/src/main.c`](https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/src/main.c) (Main loop), [`C/include/capture.h`](https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/include/capture.h) (Capture interface), [`C/src/plugins.c`](https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/src/plugins.c) (Plugin host), [`C/Makefile`](https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/Makefile) (C build)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_app["Application"]
  node_main["Main loop<br/>C99 executable<br/>[main.c]"]
  node_timing["Frame timing<br/>timing module<br/>[timing.c]"]
  node_timing_api["Timing API<br/>header<br/>[timing.h]"]
  node_frame_exchange["Double-buffer exchange<br/>producer-consumer<br/>[thread_sharing.c]"]
end

subgraph group_capture["Capture Boundary"]
  node_capture_api{{"Capture interface<br/>platform abstraction<br/>[capture.h]"}}
  node_linux_capture["V4L2 capture<br/>Linux backend<br/>[capture_linux.c]"]
  node_macos_capture["AVFoundation capture<br/>macOS backend<br/>[capture_macos.c]"]
  node_windows_capture["Media Foundation capture<br/>Windows backend<br/>[capture_windows.c]"]
end

subgraph group_processing["Processing &amp; Extensions"]
  node_plugins["Plugin host<br/>dynamic filter pipeline<br/>[plugins.c]"]
  node_plugin_api{{"Plugin interface<br/>header<br/>[plugins.h]"}}
  node_edge_filter["Edge-detection filter<br/>filter plugin<br/>[edge_detect.c]"]
  node_renderer["Terminal renderer<br/>frame conversion and output<br/>[ascii.c]"]
  node_renderer_api["Renderer API<br/>header<br/>[ascii.h]"]
  node_charsets["Character ramps<br/>runtime text assets<br/>[ascii.txt]"]
end

subgraph group_foundation["Runtime Foundation"]
  node_build["C build<br/>Makefile"]
  node_nolibc["nolibc support<br/>Linux support layer<br/>[nolibc.h]"]
  node_nl_alloc["Low-level allocation<br/>runtime implementation<br/>[nl_alloc.c]"]
  node_nl_start["Low-level startup<br/>runtime implementation<br/>[nl_start.c]"]
end

node_terminal(("Terminal output"))

node_build -->|"builds"| node_main
node_build -.->|"Linux target"| node_linux_capture
node_build -.->|"macOS target"| node_macos_capture
node_build -.->|"Windows target"| node_windows_capture
node_main -->|"initializes"| node_capture_api
node_capture_api -.->|"compile-time backend"| node_linux_capture
node_capture_api -.->|"compile-time backend"| node_macos_capture
node_capture_api -.->|"compile-time backend"| node_windows_capture
node_linux_capture -->|"captured frames"| node_frame_exchange
node_frame_exchange -->|"frame handoff"| node_plugins
node_capture_api -.->|"frames when handoff inactive"| node_plugins
node_main -->|"configures pipeline"| node_plugins
node_plugins -->|"hosts contract"| node_plugin_api
node_edge_filter -->|"implements"| node_plugin_api
node_plugins -->|"processed frame"| node_renderer
node_charsets -->|"brightness ramp / reload"| node_renderer
node_renderer -->|"ANSI cells"| node_terminal
node_main -->|"paces loop"| node_timing
node_timing -->|"implements"| node_timing_api
node_main -.->|"Linux foundation"| node_nolibc
node_nl_alloc -->|"implements"| node_nolibc
node_nl_start -->|"implements"| node_nolibc
node_renderer_api -->|"declares"| node_renderer

click node_build "https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/Makefile"
click node_main "https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/src/main.c"
click node_timing "https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/src/timing.c"
click node_timing_api "https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/include/timing.h"
click node_frame_exchange "https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/src/thread_sharing.c"
click node_capture_api "https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/include/capture.h"
click node_linux_capture "https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/src/capture_linux.c"
click node_macos_capture "https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/src/capture_macos.c"
click node_windows_capture "https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/src/capture_windows.c"
click node_plugins "https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/src/plugins.c"
click node_plugin_api "https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/include/plugins.h"
click node_edge_filter "https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/filters/edge_detect.c"
click node_renderer "https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/src/ascii.c"
click node_renderer_api "https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/include/ascii.h"
click node_charsets "https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/charsets/ascii.txt"
click node_nolibc "https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/lib/nolibc.h"
click node_nl_alloc "https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/lib/nl_alloc.c"
click node_nl_start "https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/lib/nl_start.c"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_main,node_timing,node_timing_api,node_frame_exchange toneBlue
class node_capture_api,node_linux_capture,node_macos_capture,node_windows_capture toneAmber
class node_plugins,node_plugin_api,node_edge_filter,node_renderer,node_renderer_api,node_charsets toneMint
class node_build,node_nolibc,node_nl_alloc,node_nl_start toneRose
class node_terminal toneNeutral
```

## Components

### Application

- [Main loop](https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/src/main.c): C99 executable · Coordinates startup, capture, processing, input, pacing, and cleanup. · `C/src/main.c`
- [Frame timing](https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/src/timing.c): timing module · Caps frame cadence with monotonic time and sleep. · `C/src/timing.c`
- [Timing API](https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/include/timing.h): header · `C/include/timing.h`
- [Double-buffer exchange](https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/src/thread_sharing.c): producer-consumer · Separates capture writes from renderer reads; primary-loop integration is partial. · `C/src/thread_sharing.c`

### Capture Boundary

- [Capture interface](https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/include/capture.h): platform abstraction · Common camera acquisition and control declarations. · `C/include/capture.h`
- [V4L2 capture](https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/src/capture_linux.c): Linux backend · Captures frames and exposes live camera controls through ioctls. · `C/src/capture_linux.c`
- [AVFoundation capture](https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/src/capture_macos.c): macOS backend · Camera backend with stubbed hardware controls. · `C/src/capture_macos.c`
- [Media Foundation capture](https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/src/capture_windows.c): Windows backend · Camera backend with stubbed hardware controls. · `C/src/capture_windows.c`

### Processing & Extensions

- [Plugin host](https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/src/plugins.c): dynamic filter pipeline · Loads, invokes, watches, reloads, and configures filters. · `C/src/plugins.c`
- [Plugin interface](https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/include/plugins.h): header · Extension contract implemented by filter shared objects. · `C/include/plugins.h`
- [Edge-detection filter](https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/filters/edge_detect.c): filter plugin · Supports Sobel variants and Laplacian behavior. · `C/filters/edge_detect.c`
- [Terminal renderer](https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/src/ascii.c): frame conversion and output · Converts YUYV, applies visual modes, maps cells, and emits ANSI output. · `C/src/ascii.c`
- [Renderer API](https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/include/ascii.h): header · `C/include/ascii.h`
- [Character ramps](https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/charsets/ascii.txt): runtime text assets · Selectable and reloadable brightness mappings. · `C/charsets/ascii.txt`

### Runtime Foundation

- [C build](https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/Makefile): Makefile · Builds executable and platform-specific components. · `C/Makefile`
- [nolibc support](https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/lib/nolibc.h): Linux support layer · Provides low-level allocation, I/O, syscalls, startup, and parsing. · `C/lib/nolibc.h`
- [Low-level allocation](https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/lib/nl_alloc.c): runtime implementation · `C/lib/nl_alloc.c`
- [Low-level startup](https://github.com/harshit-dhanwalkar/asciicam/blob/main/C/lib/nl_start.c): runtime implementation · `C/lib/nl_start.c`

### Other components

- **Terminal output**: terminal · ASCII, Unicode, and ANSI truecolor display.

## Connections

- C build → Main loop: builds
- C build → V4L2 capture: Linux target
- C build → AVFoundation capture: macOS target
- C build → Media Foundation capture: Windows target
- Main loop → Capture interface: initializes
- Capture interface → V4L2 capture: compile-time backend
- Capture interface → AVFoundation capture: compile-time backend
- Capture interface → Media Foundation capture: compile-time backend
- V4L2 capture → Double-buffer exchange: captured frames
- Double-buffer exchange → Plugin host: frame handoff
- Capture interface → Plugin host: frames when handoff inactive
- Main loop → Plugin host: configures pipeline
- Plugin host → Plugin interface: hosts contract
- Edge-detection filter → Plugin interface: implements
- Plugin host → Terminal renderer: processed frame
- Character ramps → Terminal renderer: brightness ramp / reload
- Terminal renderer → Terminal output: ANSI cells
- Main loop → Frame timing: paces loop
- Frame timing → Timing API: implements
- Main loop → nolibc support: Linux foundation
- Low-level allocation → nolibc support: implements
- Low-level startup → nolibc support: implements
- Renderer API → Terminal renderer: declares
