jacquardSnapshot

← snapshot

5154 bytes
import type { SnapshotDto } from "@/lib/types";

const CELL = 6;
const WARP_THREADS = 16;
/** Target column count, so three snapshots and thirty both read as cloth. */
const TARGET_COLS = 132;

const THREAD: Record<string, string> = {
  human: "var(--jac-human)",
  agent: "var(--jac-agent)",
};

/**
 * The cloth this repository has actually woven.
 *
 * Every snapshot is a band of picks — weft thread laid across the warp — and
 * the thread's colour is the provenance hashed into that snapshot's content
 * address. Mixed provenance is not a third colour: the two threads alternate
 * row by row, because mixed *is* both hands. The weave is a 2/2 twill, so the
 * diagonal wales run exactly the way real jacquard cloth does.
 *
 * Nothing here is decoration you could paste into another product: the
 * pattern is a function of this repo's DAG and nothing else.
 */
export function ProvenanceLoom({
  entries,
  height = 96,
  showLegend = true,
}: {
  /** Newest-first, as the log returns them. */
  entries: SnapshotDto[];
  height?: number;
  showLegend?: boolean;
}) {
  // Oldest first: cloth grows away from the beam.
  const picks = [...entries].reverse();
  const n = Math.max(picks.length, 1);
  const picksPer = Math.max(3, Math.ceil(TARGET_COLS / n));
  const cols = n * picksPer;
  const w = cols * CELL;
  const h = WARP_THREADS * CELL;

  const counts = {
    human: entries.filter((e) => e.provenance === "human").length,
    agent: entries.filter((e) => e.provenance === "agent").length,
    mixed: entries.filter((e) => e.provenance === "mixed").length,
  };

  return (
    <div className="jac-loom">
      <div style={{ position: "relative", height }}>
        <svg
          viewBox={`0 0 ${w} ${h}`}
          preserveAspectRatio="none"
          style={{ height, width: "100%" }}
          role="img"
          aria-label={
            entries.length === 0
              ? "An empty warp — no snapshots yet."
              : `Provenance cloth: ${counts.human} human, ${counts.agent} agent, ${counts.mixed} mixed snapshots.`
          }
        >
          {/* the warp: threads under tension, before any weft */}
          <rect width={w} height={h} fill="var(--jac-code-bg)" />
          {Array.from({ length: cols }, (_, i) => (
            <rect
              key={`warp-${String(i)}`}
              x={i * CELL}
              y={0}
              width={CELL - 1.2}
              height={h}
              fill="var(--jac-ink)"
              opacity={0.055}
            />
          ))}

          {picks.map((snapshot, index) => {
            const weft = THREAD[snapshot.provenance];
            return (
              <g
                key={snapshot.id}
                className="jac-pick"
                style={{ animationDelay: `${index * 55}ms` }}
              >
                {Array.from({ length: picksPer }, (_, p) => {
                  const col = index * picksPer + p;
                  return Array.from({ length: WARP_THREADS }, (_, row) => {
                    // 2/2 twill: the weft floats over two warps, under two,
                    // shifted one thread per pick — that shift is the wale.
                    const over = (col + row) % 4 < 2;
                    if (!over) return null;
                    // Mixed alternates thread by thread; it is both hands.
                    const fill =
                      weft ??
                      (row % 2 === 0 ? THREAD.human : THREAD.agent);
                    return (
                      <rect
                        key={`${String(col)}-${String(row)}`}
                        x={col * CELL}
                        y={row * CELL}
                        width={CELL - 0.6}
                        height={CELL - 0.6}
                        rx={1}
                        fill={fill}
                        opacity={0.82}
                      />
                    );
                  });
                })}
              </g>
            );
          })}

          {/* selvage: the finished edge that keeps the cloth from fraying */}
          <rect width={w} height={1.5} fill="var(--jac-ink)" opacity={0.16} />
          <rect y={h - 1.5} width={w} height={1.5} fill="var(--jac-ink)" opacity={0.16} />
        </svg>
        <span className="jac-loom-shuttle" aria-hidden="true" />
      </div>

      {showLegend ? (
        <div className="jac-loom-legend">
          <span className="jac-mono">{entries.length} picks</span>
          <span className="jac-badge jac-badge--human">
            <span className="jac-badge-dot" />
            {counts.human} human
          </span>
          <span className="jac-badge jac-badge--agent">
            <span className="jac-badge-dot" />
            {counts.agent} agent
          </span>
          {counts.mixed > 0 ? (
            <span className="jac-badge jac-badge--mixed">
              <span className="jac-badge-dot" />
              {counts.mixed} mixed
            </span>
          ) : null}
          <span className="jac-spacer" />
          <span>woven from this repo&apos;s provenance — nothing else</span>
        </div>
      ) : null}
    </div>
  );
}