Design system
GitHub

Visual

Striped wordmark

SVG wordmark with horizontal stripes.

npx -y github:anwarlemu/agentcard-brand-cli#release add striped-wordmark
striped-wordmark.preview
Preview

Usage

use-it-for.md

Use across the bottom of SiteFooter on blue. Supports short uppercase words.

never.md
  • More than one per page
  • Long words or sentences
  • On a white ground
  • Set in a font instead of the bars

Example

examples/striped-wordmark.tsx
import { StripedWordmark } from "@/components/visuals/striped-wordmark";
import { Surface } from "@/lib/surface";

export function Site() {
  return (
    <div className="grid gap-6">
      <Surface ground="blue" className="overflow-hidden rounded-panel">
        <StripedWordmark />
      </Surface>
      <Surface ground="blue" className="overflow-hidden rounded-panel">
        <StripedWordmark text="VAULT" />
      </Surface>
    </div>
  );
}

Source

components/visuals/striped-wordmark.tsx
import * as React from "react";

import { cn } from "@/lib/utils";

// The footer's giant word (agentcard.sh, .v7-foot-glyphs): one letter per cell between vertical rules, each letter drawn
// in horizontal bars like type on a tube, the same lines as the logomark's hand. Every glyph is a 16 by 11 grid; a run
// of lit squares in a row becomes one bar, 6 units tall in a 10 unit row, so the stripes show the ground between them.
// The bars are paper and fade a little toward the foot. It is SVG, so it scales with the width it is given (the
// footer's full width) instead of stepping on the type scale. Letters A to Z; anything else is an empty cell.
const GLYPHS: Record<string, string[]> = {
  A: ["....########....", "...##########...", "..####....####..", ".####......####.", ".###........###.", ".###........###.", ".##############.", ".##############.", ".###........###.", ".###........###.", ".###........###."],
  B: [".###########....", ".#############..", ".###.......####.", ".###........###.", ".###.......####.", ".############...", ".#############..", ".###.......####.", ".###........###.", ".#############..", ".###########...."],
  C: ["....#########...", "..#############.", ".####.......###.", ".###............", ".###............", ".###............", ".###............", ".###............", ".####.......###.", "..#############.", "....#########..."],
  D: [".##########.....", ".#############..", ".###......#####.", ".###........###.", ".###........###.", ".###........###.", ".###........###.", ".###........###.", ".###......#####.", ".#############..", ".##########....."],
  E: [".##############.", ".##############.", ".###............", ".###............", ".###............", ".###########....", ".###########....", ".###............", ".###............", ".##############.", ".##############."],
  F: [".##############.", ".##############.", ".###............", ".###............", ".###............", ".###########....", ".###########....", ".###............", ".###............", ".###............", ".###............"],
  G: ["....#########...", "..#############.", ".####.......###.", ".###............", ".###............", ".###....#######.", ".###....#######.", ".###........###.", ".####.......###.", "..#############.", "....#########..."],
  H: [".###........###.", ".###........###.", ".###........###.", ".###........###.", ".###........###.", ".##############.", ".##############.", ".###........###.", ".###........###.", ".###........###.", ".###........###."],
  I: ["....########....", "....########....", "......####......", "......####......", "......####......", "......####......", "......####......", "......####......", "......####......", "....########....", "....########...."],
  J: ["......#########.", "......#########.", "............###.", "............###.", "............###.", "............###.", "............###.", ".###........###.", ".####......####.", "..############..", "....########...."],
  K: [".###.......####.", ".###......####..", ".###.....####...", ".###....####....", ".###...####.....", ".#########......", ".##########.....", ".###....####....", ".###.....####...", ".###......####..", ".###.......####."],
  L: [".###............", ".###............", ".###............", ".###............", ".###............", ".###............", ".###............", ".###............", ".###............", ".##############.", ".##############."],
  M: [".####......####.", ".#####....#####.", ".######..######.", ".###.######.###.", ".###..####..###.", ".###...##...###.", ".###........###.", ".###........###.", ".###........###.", ".###........###.", ".###........###."],
  N: [".###........###.", ".####.......###.", ".#####......###.", ".######.....###.", ".###.###....###.", ".###..###...###.", ".###...###..###.", ".###....###.###.", ".###.....######.", ".###......#####.", ".###.......####."],
  O: ["....########....", "..############..", ".####......####.", ".###........###.", ".###........###.", ".###........###.", ".###........###.", ".###........###.", ".####......####.", "..############..", "....########...."],
  P: [".###########....", ".#############..", ".###.......####.", ".###........###.", ".###.......####.", ".#############..", ".###########....", ".###............", ".###............", ".###............", ".###............"],
  Q: ["....########....", "..############..", ".####......####.", ".###........###.", ".###........###.", ".###........###.", ".###....###.###.", ".###.....######.", ".####.....####..", "..#############.", "....#######.###."],
  R: [".###########....", ".#############..", ".###.......####.", ".###........###.", ".###.......####.", ".#############..", ".###########....", ".###...####.....", ".###....####....", ".###.....####...", ".###......####.."],
  S: ["...###########..", ".##############.", ".####...........", ".###............", ".#####..........", "..###########...", "...###########..", "..........#####.", "............###.", ".##############.", "..###########..."],
  T: [".##############.", ".##############.", "......####......", "......####......", "......####......", "......####......", "......####......", "......####......", "......####......", "......####......", "......####......"],
  U: [".###........###.", ".###........###.", ".###........###.", ".###........###.", ".###........###.", ".###........###.", ".###........###.", ".###........###.", ".####......####.", "..############..", "....########...."],
  V: [".###........###.", ".###........###.", ".###........###.", ".####......####.", "..###......###..", "..####....####..", "...###....###...", "...####..####...", "....###..###....", ".....######.....", "......####......"],
  W: [".###........###.", ".###........###.", ".###........###.", ".###........###.", ".###........###.", ".###...##...###.", ".###..####..###.", ".###.######.###.", ".######..######.", ".#####....#####.", ".####......####."],
  X: [".###........###.", ".####......####.", "..####....####..", "...####..####...", "....########....", ".....######.....", "....########....", "...####..####...", "..####....####..", ".####......####.", ".###........###."],
  Y: [".###........###.", ".####......####.", "..####....####..", "...####..####...", "....########....", ".....######.....", "......####......", "......####......", "......####......", "......####......", "......####......"],
  Z: [".##############.", ".##############.", "..........####..", ".........####...", "........####....", ".......####.....", "......####......", ".....####.......", "....####........", ".##############.", ".##############."],
};

const COLS = 16;
const ROWS = 11;

function BarGlyph({ rows }: { rows?: string[] }) {
  const bars: { x: number; y: number; w: number }[] = [];
  rows?.forEach((row, y) => {
    for (const run of row.matchAll(/#+/g)) bars.push({ x: run.index ?? 0, y, w: run[0].length });
  });
  return (
    <svg
      viewBox={`0 0 ${COLS * 10} ${ROWS * 10}`}
      aria-hidden
      className="-mb-0.5 block h-auto w-full fill-paper [mask-image:linear-gradient(var(--ds-color-black)_45%,color-mix(in_srgb,var(--ds-color-black)_55%,transparent))]"
    >
      {bars.map((b) => (
        <rect key={`${b.x}-${b.y}`} x={b.x * 10} y={b.y * 10 + 2} width={b.w * 10} height={6} />
      ))}
    </svg>
  );
}

function StripedWordmark({ text = "AGENTCARD", label, className, style, ...props }: Omit<React.ComponentProps<"div">, "children"> & { text?: string; label?: string }) {
  const letters = [...text.toUpperCase()];
  return (
    <div
      role="img"
      aria-label={label ?? text}
      data-slot="striped-wordmark"
      className={cn("grid w-full", className)}
      style={{ gridTemplateColumns: `repeat(${letters.length}, minmax(0, 1fr))`, ...style }}
      {...props}
    >
      {letters.map((letter, i) => (
        <div
          key={i}
          className="grid items-end border-l border-line-on-brand-strong px-[clamp(--spacing(0.75),0.8vw,--spacing(3.5))] pt-[clamp(--spacing(5),3vw,--spacing(12))] pb-[clamp(0rem,calc((87.5rem-100vw)*0.145),--spacing(19))] first:border-l-0"
        >
          <BarGlyph rows={GLYPHS[letter]} />
        </div>
      ))}
    </div>
  );
}

export { StripedWordmark };

Reference: agentcard-website src/components/v7/site-footer.tsx (BarGlyph, .v7-foot-glyphs); src/app/globals.css:5085; agentcard.sh / (computed).