id: BB-RESEARCH-4JDRXJS3 type: research title: Luigit change-shape glyph feasibility and prior art
Luigit change-shape glyph feasibility and prior art
Question
Can a compact change-shape glyph improve history scanning enough to justify its computation, rendering, and visual complexity?
Scope
This research evaluates a commit-row visualization of per-file additions and deletions. It covers visual precedent, perceptual limits, bounded rendering, binary and oversized files, accessibility, and implementation validation. It records the accepted design and the evidence supporting its adoption.
Sources and evidence
Git and forge precedent
- Git diffstat already pairs per-file names with compact change bars and exact aggregate counts.
- Git numstat emits decimal additions and deletions for text files, but emits
-for both counts on binary files. - Git diffstat represents a differing binary file with its new byte size in the added field and old byte size in the deleted field.
- Git
--dirstat=linesdivides binary byte damage into 64-byte units because binary files have no natural line unit. Git's source calls this normalization cheap and heuristic, not a measurement of changed bytes. - GitHub commit lists expose aggregate additions, deletions, and changed-file counts, while richer per-file shape usually appears only after navigation.
- GitLab, Gerrit, cgit, Gitiles, and Review Board use bounded diffstat-like bars, exact counts, omission states, or file summaries rather than an unbounded commit-row plot.
- Fossil's timeline uses compact activity rails, but those encode chronology rather than additions and deletions.
Sources: Git diff options, Git v2.53.0 binary diffstat accounting, Git v2.53.0 binary dirstat normalization, GitHub commit history, GitLab changes, Gerrit review UI, Gitiles, cgit, Review Board diffs, Fossil timeline.
General visualization precedent
- Diverging bars make positive and negative quantities separable around a common baseline.
- Small multiples support rapid comparison when every row uses the same orientation and bounded dimensions.
- Width, height, position, intensity, and texture are finite visual channels. A bounded raster cannot losslessly display arbitrarily many independent file values.
- Color intensity is weaker than position or length for quantitative judgments. It is suitable as a redundant overflow cue, not the sole carrier of an exact value.
- Texture can distinguish estimated or non-text values when color is unavailable.
- Exact textual totals remain necessary because a tiny glyph cannot communicate exact aggregate or per-file values reliably.
Sources: Cleveland and McGill, graphical perception, WCAG use of color, WCAG non-text contrast.
Repository palette
modules/klops/stagit/nugu.css provides automatic light and dark Nugu tokens.
The accepted mockups use Nugu info colors for additions and Nugu error colors for deletions.
A stronger magnitude variant is not currently a named Nugu token.
Production intensity variants must be generated through the Nugu asset pipeline rather than hand-authored in this repository.
Mockup evidence
Seven visual iterations tested aggregate bars, mirrored Unicode blocks, CSS bars, Nugu colors, bounded width, grouping, binary texture, oversized-file treatment, and equal column widths.
The accepted form has:
- one horizontal baseline;
- additions above and deletions below;
- paired per-file columns;
- Nugu-derived directional colors;
- exact textual file and line totals;
- a fixed chart height and bounded width;
- inverse column-width scaling between a minimum and maximum;
- explicit grouping when file count exceeds display capacity;
- stronger color plus a cap mark for exact values beyond the height range;
- distinct patterns for binary and computation-oversized size estimates;
- inset pattern strokes so patterned and solid columns keep identical width.
A Firefox 155.0.1 headless screenshot at 720 by 900 pixels verified that CSS bars meet one exact baseline. The earlier font-block rendering crossed the baseline because glyph metrics and transforms did not align reliably.
The accepted mockup manifest is:
/home/me/.cache/pi/mockups/01a068f7-0269-7d2f-bd56-224796300968/0213b369-e467-4940-86bb-4950c7d0b078/007-call_NfpuWYITm7dTc1fpRgN69oa9_fc_0f591dd6b70142d8016a9f067940c887d2b28b7d738d3dd66f/manifest.json
Findings
The useful question is per-file concentration
Aggregate files, +lines, and -lines already answer overall size and direction exactly.
The glyph earns its place only if it answers a different question:
Is this change concentrated in a few files or spread across many, and where do additions or deletions dominate?
One paired column per file exposes that shape directly. A single aggregate rectangle, pie, donut, or sparkline does not.
The glyph is contextual evidence beside a commit, not a repository dashboard and not a replacement for diffstat or the changed-files view.
Horizontal encoding
For file counts within capacity, every file receives one equal-width column. Available width is divided by file count, then clamped between a measured minimum and maximum. Gaps shrink before columns do. The chart remains centered when only a few files changed.
The accepted prototype uses:
- maximum chart width of 192 CSS pixels;
- maximum chart height of 52 CSS pixels, split evenly around a two-pixel baseline;
- column widths between two and twelve CSS pixels;
- up to 32 displayed columns in a commit row.
These are experiment values, not production constants. Responsive measurements, device-pixel ratios, IBM Plex rendering, and the history-row information budget must determine final values.
Too many files require explicit aggregation
No minimum-width bounded chart can preserve one visible column per file without limit. Luigit must therefore make the loss bounded, deterministic, and visible.
For more files than the display capacity:
- Partition files by representation class: exact text, estimated oversized text, binary, and non-line metadata.
- Rank files within each class by descending represented magnitude, using path as the stable tie-breaker.
- Assign the available columns proportionally among non-empty classes.
- Partition each ranked class into contiguous groups whose file counts differ by at most one.
- Sum the represented positive and negative quantities within each group.
- Render one column per group with the class's solid or patterned treatment.
- Show text such as
500 files · all files grouped into 32 bars.
Every file contributes to a displayed group, so aggregate represented quantities remain complete. Individual per-file shape is necessarily coarsened. The changed-files view remains the lossless destination.
Grouping must not combine exact line counts and byte-derived estimates into one visually homogeneous column.
Vertical encoding
Additions rise from the baseline and deletions descend from it. Both directions use the same scale within one glyph. Files are ranked by their combined represented magnitude, while their positive and negative heights remain independently visible.
A linear within-change scale best preserves concentration. The largest directional value reaches the normal height limit; smaller values use proportional heights. A nonzero value receives a minimum visible mark when its proportional result would disappear. That minimum is a visibility accommodation, not an exact magnitude.
Very large exact line counts may exceed the chosen height range. They remain capped in height and receive both:
- a more intense Nugu-derived directional color;
- a double cap mark at the outer edge.
Intensity communicates an overflow tier, not an exact count. The cap preserves the distinction without color. Exact aggregate line totals remain visible as text, and exact per-file totals remain available in the changed-files view. Magnitude tiers and thresholds require corpus calibration before implementation.
Binary-file heuristic
Binary files have no natural additions and deletions in lines. Luigit should follow Git's existing cheap display convention rather than invent an unexplained unit:
- new binary size contributes above the baseline;
- old binary size contributes below the baseline;
- each 64 bytes contributes one display unit, rounded up;
- a directional stripe pattern marks both bars as binary size, not changed lines.
For a binary addition, only the new-size bar exists. For a deletion, only the old-size bar exists. For a modification, both full old and full new sizes appear. A same-size one-byte modification therefore still renders two full-size patterned bars. This is intentional: the bars show preimage and postimage footprint, not measured changed bytes.
Visible text must say binary old/new sizes use 64-byte units or an equivalently clear phrase.
The detailed file row must show exact byte sizes.
The glyph must never add these units to textual +lines and -lines labels.
Git's 64-byte normalization is credible prior art, but Git itself describes it as a cheap heuristic. Luigit should preserve that caveat in help text.
Computation-oversized text
A text file may exceed the budget for computing exact line changes while its old and new blob sizes remain cheaply available. Suppressing it loses useful shape, but rendering byte sizes as exact line churn is false.
Luigit may render the same 64-byte old/new size units with a diagonal estimate pattern distinct from the binary pattern. The summary must state that the line diff was skipped and old/new byte estimates are shown. Estimated oversized values may use the stronger magnitude color, but pattern and text remain the authoritative distinction.
This treatment applies only when both object identity and blob sizes are known safely. If object size, object type, visibility, or comparison basis is unresolved, the glyph must expose an unavailable or partial state instead of guessing.
Non-line changes
Pure renames, mode changes, symlink transitions, and gitlink updates can change a commit without textual line churn. They need exact textual counts or status markers next to the glyph. They must not receive invented line heights.
Submodule gitlinks have fixed-size object identifiers rather than meaningful blob-size changes. A small patterned baseline marker may represent their presence, but it must remain distinct from binary and oversized-size bars.
Rename detection affects whether a change appears as an edit or delete-plus-add. The glyph must use the same declared rename policy and comparison basis as its linked diff.
Merge and root commits
A merge commit has no single intrinsic diff. The glyph must state and use one comparison basis:
- first parent for the default first-parent history;
- selected parent when the user changes parent context;
- empty tree for a root commit.
Combined merge shape belongs in a dedicated comparison, not an unlabeled commit-row glyph.
Derived-state and runtime cost
Per-file line counts can require reading blobs, classifying content, rename analysis, and textual diff. Computing them synchronously for every visible history row risks violating Luigit's warm-page target.
The glyph data is derived state and must have independent limits for:
- commits considered per page;
- files considered per commit;
- bytes read and diffed;
- CPU time;
- memory;
- concurrent computations;
- cached records and disk usage;
- rendered columns and HTML bytes.
Binary object sizes are cheap only after safe object lookup. Oversized byte estimates avoid full line-diff work but still consume object and metadata budgets.
History rendering should consume a versioned cached summary when available. A cache miss may show exact aggregate facts already available within budget, a pending enhancement, or an explicit partial state. It must not turn an ordinary history request into unbounded whole-repository diff computation.
The summary cache key must include repository identity, commit and parent object IDs, hash algorithm, diff algorithm, rename policy, binary classification policy, line-count limits, grouping version, and glyph-scale version. Ref movement does not change immutable summaries, but visibility must be rechecked before output. Garbage collection may reclaim only this derived state.
Rendering implementation
CSS bars are the current candidate because they align independently of font glyph metrics and require no JavaScript, canvas, SVG, or runtime helper executable. Each displayed column should use one element with pseudo-elements or equivalent bounded markup for the two directions. Pattern borders must be inset so every treatment preserves the same external column width.
At the prototype limit, one 50-row history page can add up to 1,600 displayed columns. That DOM cost is not automatically acceptable. Implementation must benchmark node count, HTML bytes, style cost, paint cost, and mobile layout. A lower capacity or more compact server-rendered representation may be required.
Accessibility
The glyph is supplementary and should be hidden from the accessibility tree because visible adjacent text carries the exact summary. The linked changed-files view supplies exact per-file details.
Meaning is redundant:
- vertical direction separates additions from deletions;
- Nugu color reinforces direction;
- cap shape marks overflow;
- texture marks binary and estimated values;
- visible words state exact totals, grouping, and estimation.
Keyboard operation does not depend on the glyph. If the glyph links to changed files, the surrounding descriptive link is the target rather than individual bars. Forced-colors and monochrome screenshots must preserve baseline, caps, and patterns.
Adoption decision
Seven interactive mockup iterations compared aggregate summaries, mirrored block glyphs, aligned CSS bars, bounded layouts, grouping, and edge-case encodings. Oliver judged the mirrored per-file skyline immediately useful for scanning change concentration and direction, then accepted its final visual form. That evaluation supplies the human judgment required by the spec's experimentation condition.
The skyline is adopted for Luigit. No synthetic percentage threshold or additional user study gates the feature.
Implementation validation
Performance and correctness remain ordinary implementation requirements rather than evidence of visual value.
Build deterministic fixtures containing:
- one-file and many-file changes;
- concentrated and evenly distributed changes;
- addition-heavy, deletion-heavy, and balanced changes;
- mixed exact text, binary, and oversized text;
- pure renames, mode changes, gitlinks, root commits, and merges;
- more files than the display capacity;
- extreme line and byte magnitudes;
- light, dark, narrow, and wide layouts.
Record object IDs, parent basis, rename policy, exact counts, estimates, grouping, and the expected glyph model. Verify that every file contributes exactly once, grouped totals remain complete, patterns preserve column width, and partial or unavailable facts remain explicit.
Benchmark:
- cached and uncached summary computation;
- bytes read and diffed;
- CPU, memory, concurrency, and derived-disk use;
- history-page generation against Luigit's existing warm-page target;
- HTML bytes and DOM nodes at the maximum page size;
- browser style, layout, paint, and mobile behavior;
- cache reclamation and failed cache-fill behavior.
If the initial representation is too expensive, reduce displayed capacity, compact the markup, fill caches out of band, or render an explicit pending or partial state. Performance tuning may change implementation details but must preserve the accepted skyline semantics.
Conclusions
- The adopted design is a mirrored per-file skyline, not a single aggregate glyph.
- Its primary value is concentration and directional distribution across files.
- Exact textual totals remain mandatory and authoritative.
- Width is bounded through inverse scaling, then explicit deterministic grouping.
- Height is bounded through proportional scaling, with redundant cap and intensity cues for overflow.
- Binary files use patterned old/new sizes normalized to 64-byte display units, following Git's documented heuristic.
- Computation-oversized text may use a distinct patterned old/new byte estimate, never an unlabeled pseudo-line count.
- Pattern treatments must preserve the exact width of solid bars.
- CSS bars are more reliable than transformed Unicode block glyphs for baseline alignment.
- The reviewed mockup experiment demonstrated the required human benefit, and the skyline is adopted. Rendering cost remains an implementation concern governed by Luigit's ordinary resource and performance requirements.
Open questions
- What column capacity, width clamp, and chart height survive realistic mobile and desktop history rows?
- Which exact line thresholds define the stronger magnitude tiers?
- Which Nugu-generated tokens provide stronger addition and deletion variants with sufficient contrast?
- Should grouped columns use equal file-count bins or a corpus-calibrated density rule?
- How should representation-class column capacity be allocated when one commit mixes many text, binary, and oversized files?
- What cache-fill policy preserves warm history latency without hiding useful shape indefinitely?
- Can a lower-node server-rendered encoding retain the accepted baseline and pattern behavior?
Provenance
Research completed 2026-09-07 from official Git documentation, Git v2.53.0 diff.c, surveyed Git web interfaces, visualization and accessibility guidance, repository Nugu assets, and seven reviewed mockup iterations.
The 64-byte binary rule is prior art from Git; extending the unit to computation-oversized text is a Luigit proposal and must remain labeled as an estimate.