|
| 1 | +# gitdiff3d |
| 2 | + |
| 3 | +A git diff is a pile of text. Somebody typed that text, one key at a time, in |
| 4 | +some order that made sense to them. `gitdiff3d` plays it back: your diff becomes |
| 5 | +a 3d scene where every changed line is a plate floating in space, and a caret |
| 6 | +walks through them typing the additions in and erasing the deletions. |
| 7 | + |
| 8 | + |
| 9 | + |
| 10 | +## Install |
| 11 | + |
| 12 | +``` |
| 13 | +git clone https://github.com/vdayanand/gitdiff3d |
| 14 | +cd gitdiff3d |
| 15 | +make install # symlinks bin/gitdiff3d.js into ~/bin |
| 16 | +``` |
| 17 | + |
| 18 | +Or run it straight out of the checkout with `node bin/gitdiff3d.js`. |
| 19 | + |
| 20 | +Node 18 or newer. No dependencies: three.js is vendored, everything else is the |
| 21 | +standard library and the `git` already on your path. |
| 22 | + |
| 23 | +## Use |
| 24 | + |
| 25 | +``` |
| 26 | +gitdiff3d working tree vs HEAD |
| 27 | +gitdiff3d --staged the index |
| 28 | +gitdiff3d HEAD~3..HEAD a commit range |
| 29 | +gitdiff3d main HEAD two revisions |
| 30 | +gitdiff3d -- src/ limit to a path |
| 31 | +``` |
| 32 | + |
| 33 | +It builds the scene, serves it on a random local port, and opens your browser. |
| 34 | + |
| 35 | +``` |
| 36 | +--port <n> listen on port n (default: random) |
| 37 | +--max-hunks <n> keep only the first n hunks (default: all) |
| 38 | +--order <how> story or git (default: story) |
| 39 | +--context <n> lines of unchanged code around each hunk (default: 8) |
| 40 | +--json print the scene model, do not serve |
| 41 | +--no-open serve without opening a browser |
| 42 | +``` |
| 43 | + |
| 44 | +## Story order |
| 45 | + |
| 46 | +Git prints hunks in path order, which is alphabetical, which is nobody's |
| 47 | +thinking. The default `--order story` reorders them the way the change was |
| 48 | +probably made: a hunk that introduces a name comes before the hunks that call |
| 49 | +that name, and failing that, schema before models before logic before callers |
| 50 | +before tests before prose. It is a topological sort over "who defines what", |
| 51 | +with the file's role as the tie breaker. `--order git` turns it off. |
| 52 | + |
| 53 | +## Overlay |
| 54 | + |
| 55 | +Press `l` and the old version of the hunk sits behind the new one, both in |
| 56 | +frame, separated in depth rather than side by side. This is the one thing a flat |
| 57 | +diff cannot do. |
| 58 | + |
| 59 | + |
| 60 | + |
| 61 | +## Keys |
| 62 | + |
| 63 | +``` |
| 64 | +space pause , . a keystroke back or forward |
| 65 | +< > a whole line b r rewind this hunk |
| 66 | +arrows previous or next hunk a autoplay through everything |
| 67 | +j / k scroll wheel, ctrl-wheel zoom, shift-wheel sideways |
| 68 | +drag orbit 0 refit the camera and follow the caret |
| 69 | +c more or less context (refetched from git) |
| 70 | +l overlay g / G fade the front or back plane |
| 71 | +t / T next or previous theme f fullscreen |
| 72 | +x / X faster or slower m keystroke sound v speak the file and symbol |
| 73 | +? show or hide the shortcuts |
| 74 | +``` |
| 75 | + |
| 76 | +Twelve editor themes, dark and light: tokyo night, dracula, one dark, nord, |
| 77 | +gruvbox, solarized, github light, one light, gruvbox light, everforest light, |
| 78 | +mint. A theme names only the colours an editor names; the papers, rims and |
| 79 | +chrome are mixed from those, so nothing needs a table of shades. |
| 80 | + |
| 81 | +## How it works |
| 82 | + |
| 83 | +``` |
| 84 | +git diff -U8 -> parse-diff -> structure -> layout -> order -> viewer |
| 85 | + hunks and which symbol scene story three.js, |
| 86 | + lines each hunk is model sort one plate |
| 87 | + inside per line |
| 88 | +``` |
| 89 | + |
| 90 | +The server holds the scene model and re-runs the diff only when you ask for a |
| 91 | +different context width. Everything the browser needs is one JSON document plus |
| 92 | +one HTML file, so the viewer is dumb on purpose: it draws what it is given. |
| 93 | + |
| 94 | +Source structure is understood by regex, not by a real parser. It knows c-like |
| 95 | +languages (js, ts, go, rust, java, kotlin, swift, c#, c, c++, php, scala, dart), |
| 96 | +python, julia and ruby well enough to name the function a hunk lands in and to |
| 97 | +tell a comment-only change from a real one. Other languages still render, they |
| 98 | +just get no symbol names and no story order. |
| 99 | + |
| 100 | +Binary files are skipped. Very long lines are clipped to 200 characters. |
| 101 | + |
| 102 | +## Licence |
| 103 | + |
| 104 | +MIT, see [LICENSE](LICENSE). Bundles [three.js](https://threejs.org) r128, |
| 105 | +also MIT. |
0 commit comments