CLAUDE.md (3577B)
1 # sframe — CLAUDE.md 2 3 ## Project 4 5 sframe (Simple Frame) is a lightweight command-line tool written in C 6 following the suckless philosophy. It extracts unique frames from video 7 files for research purposes, using perceptual hashing to eliminate 8 duplicates and embedding timestamps in filenames. 9 10 ## Coding Standards — Suckless C Style 11 12 All code in this project MUST follow the suckless.org coding style: 13 14 ### Language 15 - C99 (ISO/IEC 9899:1999), no extensions 16 - POSIX.1-2008 (`_POSIX_C_SOURCE 200809L`) 17 18 ### Indentation & Whitespace 19 - Tabs for indentation (1 tab = 1 level) 20 - Spaces for alignment only, never for indentation 21 - No tabs except at the beginning of a line 22 - Maximum line length: 79 characters 23 24 ### Comments 25 - Use `/* */` only, never `//` 26 - Comment fallthrough cases in switch statements 27 28 ### Variables 29 - All declarations at the top of the block 30 - Pointer `*` adjacent to variable name: `char *p`, not `char* p` 31 - No C99 `bool`; use `int` (0/1) 32 - Global/static variables not used outside TU must be `static` 33 34 ### Functions 35 - Return type on its own line 36 - Function name at column 0 on next line (enables `grep ^funcname`) 37 - Opening `{` on its own line for functions 38 - Functions not used outside their file: `static` 39 40 ```c 41 static void 42 usage(void) 43 { 44 fprintf(stderr, "usage: sframe [-t thresh] [-f fmt] video\n"); 45 exit(1); 46 } 47 ``` 48 49 ### Braces 50 - Opening `{` on same line for control flow (if, for, while, switch) 51 - Closing `}` on its own line unless continuing (else, do-while) 52 - Use braces even for single statements when sibling branches use them 53 54 ### Naming 55 - lowercase_with_underscores for functions and variables 56 - UPPERCASE for macros and constants 57 - CamelCase for typedef'd struct types 58 - No `_t` suffix (reserved by POSIX) 59 - Prefix module functions: `dec_open()`, `diff_hash()`, `util_die()` 60 61 ### Control Flow 62 - Space after `if`, `for`, `while`, `switch` 63 - No space after `(` or before `)` 64 - Use `goto` for cleanup/unwind, not nested ifs 65 - Return/exit early on failure 66 - Test against 0, not -1: `if (func() < 0)` 67 68 ### Error Handling 69 - All allocation checked; goto cleanup on failure 70 - `die()` for fatal errors (prints message, exits) 71 - `warn()` for recoverable errors (prints, continues) 72 73 ### File Organization Order 74 1. License header 75 2. System includes (alphabetical) 76 3. Local includes 77 4. Macros 78 5. Type definitions 79 6. Function declarations 80 7. Global variables 81 8. Function definitions (same order as declarations) 82 83 ### Headers 84 - System headers first, alphabetical 85 - Local headers after blank line 86 - No cyclic dependencies 87 - Include only what is needed 88 89 ## Architecture Rules 90 91 - **No global mutable state.** Pass context structs explicitly. 92 - **No `system()` calls.** Use `fork()/execvp()` or `popen()`. 93 - **No hardcoded paths** except sensible defaults (`~/frames`). 94 - **Separate compilation.** Every .c file compiles independently. 95 96 ## Module Prefixes 97 98 | Module | Prefix | File | 99 |--------|--------|------| 100 | Main/CLI | — | main.c | 101 | Decode | `dec_` | decode.c | 102 | Diff | `diff_` | diff.c | 103 | Utilities | `die()`, `warn()`, `ecalloc()` | util.c | 104 105 ## Build 106 107 ```sh 108 make # build sframe binary 109 make clean # remove build artifacts 110 make install PREFIX=/usr/local # install 111 ``` 112 113 ## Dependencies 114 115 - FFmpeg libraries: libavformat, libavcodec, libavutil, libswscale 116 117 ## Git Conventions 118 119 - No `Co-Authored-By: Claude` lines 120 - Commit messages: imperative, <72 chars, no period 121 - One logical change per commit 122 123 ## CRITICAL: No Building on Moirai 124 125 NEVER run `make`, `sudo make install`, or any build command unless 126 Kris explicitly says "build" in his message.