SQLite schema browser. SDL3 + Dear ImGui + OpenGL 3.3.
main.odin— app entry point, GUI loop, CLI schema dumpschema_load.odin— database-format abstraction:Backend(detect/open/close- neutral row listers), shared
load_schemabuilder, SQLite backend (MSSQL/Postgres backends to come — add entries toBACKENDS)
- neutral row listers), shared
style.odin— theme data +.ssThemeloader, ImGui/ImNodes styling, icon texture loadingblur_windows.odin/blur.odin— Windows glass blur (#+build windows) + no-op shim for other platformsassets/— runtime resources: Roboto font, window-control/file/folder icons,.ssThemethemesvendor/sqlite3/— SQLite amalgamation build, Odin bindingsvendor/imgui/— Dear ImGui + ImNodes via dcimgui C wrapper, Odin bindingsvendor/sdl3_headers/— SDL3 C headers for dcimgui backend compilationvendor/gl/— OpenGL 3.3 core bindings_compile_libs.bat/_compile_libs.sh— build vendor native libs (dcimgui.cpp, sqlite3.c, etc.)build.bat/build.sh/seed.bat/seed.sh/build_icons.bat— build, run, and asset-gen scripts.zed/tasks.json/.zed/debug.json— Zed editor tasks (build/run/debug/release/clean/seed for Windows + Linux) and CodeLLDB launch configs (Windows + Linux)test/— seed tools and SQL schematools/— asset generators (gen_icons.odin)docs/— design docs and style guides (C_STYLE_GUIDE.md,ODIN_STYLE_GUIDE.md)flake.nix/.envrc— Nix dev environment
Linux: enter the Nix dev shell first (nix develop ., or via direnv on cd), then run the scripts below.
nix develop . --command ./build.sh run works for a one-shot build. The devShell provides odin
(git-master, built with LLVM 22), clang, mold, SDL3 and GL at the right versions.
./build.sh [run|release|debug|clean] — same semantics.
build.sh debug run works the same as build.sh run debug.
./seed.sh — builds and runs test/seed.odin to create seed.db.
./seed.sh huge — builds test/huge_seed.odin to create huge.db.
Windows: build.bat [run|release|debug|clean] — compiles vendor libs, then odin build . -vet.
build.bat run builds and launches.
build.bat release adds -o:speed.
build.bat debug adds -o:none -debug.
build.bat clean removes bin/ and build/.
flake.nix— odin built from git-master against LLVM 22 (make release), wrapped withODIN_ROOTset and clang/lld on PATH.devShells.defaultexposes odin + build deps and setsLD_LIBRARY_PATH.nix flake update— bumps odin-src (git-master) and nixpkgs inputs to latest; the devShell picks up new odin..envrc—use flake; direnv auto-loads the devShell oncd.- Sublime build system runs through
nix develop . --command ./build.sh runso C-b works anywhere. - Odin is also installed globally via home-manager (
~/.nix-profile/share), which the Sublime project uses for stdlib file browsing.
- SDL3 for window + input. OpenGL 3.3 core for rendering.
- ImGui binds to SDL3 + OpenGL via dcimgui C wrapper.
- ImNodes for ER diagram node graph (planned).
- SQLite statically linked via amalgamation (
sqlite3.c). - Two foreign lib blocks in imgui.odin:
ImGui_prefix for bare functions,Imfor namespaced (FontAtlas_, TextureData_, etc.). - Adaptive vsync (
SDL_GL_SetSwapInterval(-1)). Poll-based idle loop (no WaitEvent). - Docking via
DockSpaceOverViewport+io.ConfigFlags |= {.DockingEnable}. - No animation in tool mode. GPU idle when no input.
- Prefer clear naming over comments. A well-named type or variable should make
its purpose obvious without a comment. For example,
GlobalColumnIndexis better thanColumnIndex // global index into schema.columns. When a comment is needed, it should explain why, not what or where.
- All application code is Odin. New behavior — layout, rendering,
algorithms, glue — goes in
.odinfiles, never in the vendored C/C++. - Never edit vendored source (
vendor/imgui/*.cpp/*.h— ImGui, ImNodes, the dcimgui/dcimnodes C wrappers —vendor/sqlite3/,vendor/gl/,vendor/sdl3_headers/). If a capability seems to need a vendor change, find (or add) an existing Odin-callable binding instead — ImGui's ownDrawList_*functions (already bound invendor/imgui/imgui.odin) cover most custom-drawing needs without touching C++ at all. Keeping the vendor tree untouched keeps the update path (re-pulling a newer ImGui/ImNodes/ SQLite release) a straight drop-in rather than a rebase of local patches.
- Only give code when I specifically ask for it. Before that: discuss, plan, explain, compare options. I will say "give me the code" or "write it" when ready.
- Critique honestly. Don't soften feedback. Point out dead code, bad naming, architectural issues, stale comments.
- Prefer small, incremental changes. One coherent step per commit.
- No frameworks. No nvrhi, no custom abstractions, no engine. SDL3 + ImGui + SQLite is the stack.
- Explain tradeoffs. If I ask about approach A vs B, give pros/cons and a recommendation, but let me decide.
- Read the full file before editing. Don't assume structure.
- Never guess APIs. Check vendor bindings,
odin doc, or the core library before suggesting function names. Bad guesses waste time.
- Always obey the .ignore file. Even if you know a path, don't read/write to an ignored file.
- Only commit when I ask you to. Do not stage or commit unprompted.
- Exception: if I say "push" without "commit", stage + commit + push as a single step.
- You are responsible for keeping TODO.md up to date.
- Never remove entries. Mark them
[x]when done. - All entries must have:
[S/M/L]size,[P0/P1/P2]priority,[cat]category tag. - When a task is completed, update its status and add the completed date inline if relevant.
- When a new task is discovered mid-session, add it to the appropriate section immediately.
- The "If needed later" section in TODO.md is for optimisations we don't yet know if we need — don't build them until a profile or real-world usage proves they matter.
- CLI path:
print_database_informationdumps schema to stdout viaload_schema(legacy, still works). - GUI: SDL3 + ImGui dockspace, owner-drawn titlebar with window controls and OS glass blur (Windows), menu bar with File > Open and a Theme menu built from a live scan of
assets/themes/*.ssTheme— each file'snametag is the menu label, so a dropped-in theme file extends the menu with no code change. - Theme: Hot Dog Stand (Windows 3.1 meme scheme — gaudy on purpose), Paper & Ink light/dark, OLED Dark, Blueprint, Monokai, Nord — all loaded from
assets/themes/*.ssThemeviaparse_ssTheme/apply_theme. Diagram link colour/thickness are theme-driven too ([diagram_links]section —colour/thicknesskeys,ThemeData.link_color/link_thickness). - File dialog: custom ImGui window with directory navigation, folder/file icons, magic-byte filter (backend-driven via
known_database_format), arena allocator per-frame listing. - Font: Roboto loaded from
assets/Roboto.ttfviaFontAtlas_AddFontFromFileTTF; the bold weight (assets/Roboto-Bold.ttf) pushes the diagram node title text. - Schema data model: typed structs + arena (
Schema,Table,Column,ForeignKey) with FK resolution toGlobalColumnIndex. Loaded through theBackendabstraction inschema_load.odin; SQLite is the only backend so far. - Diagram: ImNodes node editor; One/Two Degree buttons (also shown in the
schema list, acting on the selection) run a BFS over the FK graph from the
seed table and filter visible nodes, Show All restores the full set; pin
ids are
GlobalColumnIndex. Opening a database defaults to One Degree from the first table. A click (release without drag) on a table in the diagram or the schema list retargets the seed (accent-tinted title bar marks it); dragging a node only moves it. Layout: layered (Sugiyama-style), not the original radial rings — tables are ranked by hop distance from the seed (relaxed by FK direction so a same-rank FK never loops sideways), ranks stack left-to-right, ordered within each rank by barycenter + transpose crossing-reduction sweeps, then packed using each table's real ImNodes-rendered size (node_size) so nothing overlaps. Positions are cached and mirrored back from ImNodes each frame (drags persist within a view), and a refresh with an unchanged seed + visible set is skipped, so re-clicking the active table costs nothing. Whenever the view re-lays out, the editor pans so the whole layout sits at the centre of the viewport (EditorContextResetPanning, exported via the dcimnodes wrapper).test/repro_layout.odinis a standalone, no-GUI harness that validates the layout at scale against real.dbfiles (overlap-free, plus crossing/link-node-overlap metrics). Links: drawn ourselves (link_routing.odin), not through ImNodes' ownLink()— that draws a fixed two-point bezier with no obstacle awareness. Every visible table's screen rect and FK pin position is captured fresh each frame straight from what ImNodes just drew (viaDrawList_*and node/pin item rects — no vendor edits, see "Vendoring rules" above), so a routed link tracks a drag or pan for free. Each link samples the plain direct bezier, detours around any other visible table it actually crosses with a couple of waypoints (nudged by a small per-link deterministic stagger so two links detouring around the same obstacle don't land on identical waypoints and overlap through the whole detour), then rebuilds the full path as chained cubic bezier segments — a two-point link keeps ImNodes' own fixed-horizontal-tangent construction (capped atMAX_TANGENT_OFFSETso several links sharing one pin diverge from it sooner instead of bundling into a fake extra crow's foot), while a multi-waypoint link blends each interior waypoint's tangent Catmull-Rom style so a detour reads as one smooth curve rather than a chain of near-straight facets; the two true endpoints always keep the fixed horizontal tangent regardless. A self-referencing FK (e.g.cards.parent_id -> cards.id) skips obstacle routing and always loops from each pin straight down below the node's own bottom edge and back up into the other pin. Cardinality is drawn as crow's-foot notation on the link itself (crow's foot + hollow circle if the referencing column is nullable on the "many" end, a single tick on the "one" end), oriented by the pin's fixed side (always exactly horizontal, never derived from the routed path's local shape — that can flip the glyph to the wrong side when a waypoint bends the curve close to a pin). Hovering a link brightens and thickens it. The per-pin triangle/circle ImNodes shapes are fully transparent (ImNodesCol.Pin/PinHoveredalpha 0), not just shrunk, so they never double up with these glyphs.test/repro_link_routing.odinchecks the routing math standalone.compute_layer_order's rank relaxation explicitly skips self-referencing FKs (from_t == to_t) — without that guard the relaxation condition reads the same map entry on both sides and is trivially true forever, walking the table's own rank up by one every pass with no way to converge until the iteration cap strands it (and everything past it) tens of ranks away from the rest of the layout. - Debugging: Zed debugger (DAP) via
.zed/debug.json— CodeLLDB adapter launches the debug build (the per-OS Debug task runsbuild.bat debug/build.sh debugfirst); press F4 (debugger: start) for the new-process modal.
- File dialog (custom ImGui window with file list)
- Schema data model (typed structs, arena allocator, flat arrays)
- Display schema in ImGui window (tree or list)
- ER diagram with ImNodes
- Schema snapshot format
- AGENTS.md — this file (project context, agent rules)
- TODO.md — task tracking
- ~/.config/opencode/AGENTS.caveman.md — communication mode config