Bit Archaeology

Bit-level visualisation for the moment a single integer turns out to secretly carry multiple sub-fields. Pass the packed integer as value and a flat array of segments — each { label, offset, width } — and the component renders one bit box per bit (MSB on the left, LSB on the right), then paints a coloured overlay per segment, labelled with the field name and its decoded decimal value.

Generic over the underlying protocol — works equally well for an 8-bit network header, a packed RGBA pixel, a bit-set instruction encoding, a packed FEN board square, or any "this integer secretly carries N sub-fields" demonstration.

Packed integer 172, binary 10101100. Segments: FLAGS: 2, OP: 5, PAYLOAD: 4.
Customize
Value
172
Display

Installation

npx shadcn@latest add https://craftbits.dev/r/bit-archaeology.json

Usage

import { BitArchaeology } from "@craft-bits/core";
 
<BitArchaeology
  value={0b10_101_100}
  segments={[
    { label: "FLAGS", offset: 6, width: 2 },
    { label: "OP", offset: 3, width: 3 },
    { label: "PAYLOAD", offset: 0, width: 3 },
  ]}
/>

Show the decimal weight of each bit under the bit row — useful when teaching bit significance:

<BitArchaeology value={172} segments={segments} showWeights />

Override per-segment tones rather than letting the palette rotate:

<BitArchaeology
  value={172}
  segments={[
    { label: "FLAGS", offset: 6, width: 2, tone: "warning" },
    { label: "OP", offset: 3, width: 3, tone: "accent" },
    { label: "PAYLOAD", offset: 0, width: 3, tone: "success" },
  ]}
/>

Understanding the component

  1. MSB on the left. Bit rows render in human-readable order — bit bitCount - 1 on the far left, bit 0 on the far right. The component reads value as an unsigned integer; negative inputs are interpreted via JavaScript's unsigned-right-shift semantics.
  2. Segments are LSB-anchored. offset is the LSB position of the field (offset: 0 is the rightmost bit), and width is how many consecutive bits the field owns. Overlapping segments are allowed; the last entry in the array wins for a given bit.
  3. Decoded values. Each segment extracts its decimal value and renders it inside the segment pill. Pass showSegmentValues={false} to hide the decoded numbers and label the fields only.
  4. Tones rotate by default. Adjacent segments receive different tones from a five-colour rotation (accent, success, warning, error, default) so neighbouring fields read as visually distinct without any work from the caller. Pass a tone per segment to override.
  5. Bits without a segment. Any bit that no segment claims renders as a neutral chip — useful for "reserved" / "padding" bits in a real protocol header.
  6. Bit weights. showWeights prints the bit's decimal weight (128, 64, 32, ...) under each bit box. Off by default so the bit row stays compact.
  7. Reduced motion. The staggered bit enter animation collapses to instant under prefers-reduced-motion: reduce.

Props

PropTypeDefaultDescription
valuenumberrequiredThe packed integer to dissect. Read as an unsigned bitCount-bit value.
segmentsBitArchaeologySegment[]requiredBit ranges to decode and label.
bitCountnumber8Total number of bits to render. Clamped to 1..31.
showWeightsbooleanfalseShow the decimal weight of each bit under the bit row.
showSegmentValuesbooleantrueShow the decoded decimal value inside each segment overlay.
transitionTransitionSPRINGS.smoothOverride the enter transition. Reduced-motion users snap regardless.
classNamestringMerged onto the root via cn().

Accessibility

  • The component root carries role="group" and an aria-labelledby pointing at an off-screen <span> that summarises the packed integer, its binary form, and the decoded value of every segment.
  • Every bit and segment overlay exposes data-position, data-bit, data-owned, and data-tone attributes so consumer apps can hook custom styles or assistive tooling without re-reading the DOM.
  • Tone is never the only signal — segment values are printed numerically inside the overlay, so colourblind users see the magnitude even when the highlight colour is hard to discriminate.
  • Motion respects prefers-reduced-motion: reduce — the staggered bit enter animation collapses to instant.

Credits

  • Extracted from: algoflashcards (src/lessons/primitives/construction/BitArchaeology.tsx). The source was a multi-phase "reverse the crime" puzzle (evidence gathering → operator deduction → mask construction → verification). The library extract keeps only the underlying visualisation primitive — a packed integer rendered as a bit row with labelled segment overlays — and lets the caller compose any puzzle or reducer-driven scoring on top.