PageSourceSearch

https://cristiangabriel.dev/pixel-art.js?v=ab25daa2

js cristiangabriel.dev collected 2026-10-02 01:52:17 UTC 7,406 bytes, 175 lines download raw bytes

1(function () {
2  /* global React */
3  // ─────────────────────────────────────────────────────────────
4  // Pixel art primitives.
5  // Each icon is an 8x8 or 10x10 grid encoded as strings.
6  // Legend: ' ' = empty, '#' = forest, '.' = moss, 'o' = soft moss
7  // Renders as crisp <svg><rect/></svg>.
8  // ─────────────────────────────────────────────────────────────
9
10  const PIX_COLORS = {
11    "#": "var(--forest)",
12    ".": "var(--moss)",
13    o: "var(--moss-soft)",
14    d: "var(--forest-deep)",
15    l: "#A0C97A",
16    p: "#C7A878",
17    r: "#cf6a5b",
18    b: "#3a3a3a",
19    s: "#DFEFD2",
20    // ── Idle-garden plant palette (fixed hues so the plants read the same in
21    //    light + dark themes; only used by the procedural plants below). ──
22    k: "#3B5E22",
23    // stem / dark leaf
24    m: "#4E7A30",
25    // mid green
26    g: "#6FA84A",
27    // leaf green
28    y: "#F2D45C",
29    // flower centre / dandelion
30    f: "#E59ABF",
31    // petal (pink)
32    v: "#C9A3E0",
33    // petal (lilac)
34    w: "#F7EFE0",
35    // petal (cream) / seed puff
36    t: "#6B5436",
37    // soil
38    u: "#8A6A42" // soil highlight
39  };
40  function PixelGrid({
41    rows,
42    scale = 3,
43    color,
44    style = {},
45    className = ""
46  }) {
47    const h = rows.length;
48    const w = Math.max(...rows.map(r => r.length));
49    const rects = [];
50    for (let y = 0; y < h; y++) {
51      for (let x = 0; x < rows[y].length; x++) {
52        const ch = rows[y][x];
53        if (ch === " " || !ch) continue;
54        const fill = color || PIX_COLORS[ch] || "var(--forest)";
55        rects.push(/*#__PURE__*/React.createElement("rect", {
56          key: `${x},${y}`,
57          x: x * scale,
58          y: y * scale,
59          width: scale,
60          height: scale,
61          fill: fill
62        }));
63      }
64    }
65    return /*#__PURE__*/React.createElement("svg", {
66      width: w * scale,
67      height: h * scale,
68      viewBox: `0 0 ${w * scale} ${h * scale}`,
69      style: {
70        display: "block",
71        shapeRendering: "crispEdges",
72        ...style
73      },
74      className: className
75    }, rects);
76  }
77
78  // Tiny icons (8x8) for the tech stack
79  const TECH_ICONS = {
80    Java: ["   ##   ", "  #..#  ", "  #..#  ", "   ##   ", " ###### ", "##    ##", " ###### ", "   ##   "],
81    "Spring Boot": ["  ....  ", " .#..#. ", ".#....#.", ".#....#.", ".#....#.", ".#....#.", " .#..#. ", "  ....  "],
82    JPA: [" .####. ", "#.oooo.#", "#.####.#", "#.oooo.#", "#.####.#", "#.oooo.#", "#......#", " .####. "],
83    Python: [" .####  ", ".#....# ", ".#.##.# ", " .####  ", "  ####. ", " #....#.", " #.##.#.", "  ####. "],
84    Flask: ["   ##   ", "   ##   ", "  ####  ", "  #..#  ", " ##..## ", "##....##", "##....##", " ###### "],
85    Docker: ["        ", "  ####  ", " ##..## ", "########", "        ", "########", " ##..## ", "  ####  "],
86    Postman: ["        ", "########", "#.#..#.#", "#..##..#", "#.####.#", "#......#", "########", "        "],
87    "REST APIs": ["  ##  ##", " #.    .", " #.    .", "##      ", "##      ", " #.    .", " #.    .", "  ##  ##"],
88    "Alpine.js": ["        ", "   ##   ", "  #..#  ", " #....# ", " #.##.# ", "##....##", "########", "        "],
89    "DaVinci Resolve": ["########", "#.####.#", "########", "#.####.#", "#.####.#", "########", "#.####.#", "########"],
90    PostgreSQL: ["  ####  ", " #....# ", "#.oooo.#", "#.o##o.#", "#.oooo.#", "#......#", " ##..## ", "   ##   "],
91    MySQL: [" .#..#. ", ".#.##.#.", "#.####.#", "#.####.#", "#.####.#", "#.####.#", ".#.##.#.", " .#..#. "],
92    Git: ["   ##   ", "  ####  ", " ###### ", "##.##.##", "##.##.##", " ###### ", "  ####  ", "   ##   "],
93    GitHub: [" ###### ", "########", "#.####.#", "#.####.#", "########", "########", " ## ##  ", " #   #  "],
94    Linux: ["   ##   ", "  #bb#  ", "  #ss#  ", "  ####  ", " ###### ", "########", "##    ##", "##    ##"],
95    Thymeleaf: ["       #", "      #.", "     #..", " #  #...", "##.##...", " #..#...", "  #..#  ", "   ##   "],
96    HTML: ["########", "#......#", "#.####.#", "#......#", "#.####.#", "#......#", "#......#", "########"],
97    CSS: ["########", "#......#", "#.####.#", "#......#", "#.####.#", "#......#", "#.####.#", "########"],
98    JavaScript: ["########", "##....##", "##.##.##", "##.##.##", "##.##.##", "##....##", "##.####.", "########"],
99    Bootstrap: ["########", "##....##", "##.##.##", "##.#..##", "##.##.##", "##.#..##", "##....##", "########"],
100    SQL: [" ###### ", "#.oooo.#", "#......#", "#.oooo.#", "#......#", "#.oooo.#", "#......#", " ###### "],
101    Prompting: [" ###### ", "##.##.##", "#......#", "#.####.#", "#......#", "#......#", " ###### ", "   ##   "]
102  };
103  function PixelIcon({
104    name,
105    scale = 3
106  }) {
107    const rows = TECH_ICONS[name];
108    if (!rows) return null;
109    return /*#__PURE__*/React.createElement(PixelGrid, {
110      rows: rows,
111      scale: scale
112    });
113  }
114
115  // Pixel sprouts & leaves used for corner decorations and dividers
116  const SPRITES = {
117    sprout: ["   ..   ", "  .oo.  ", "   ..   ", "   ##   ", "..####..", " .####. ", "   ##   ", "   ##   "],
118    leafLeft: ["   ..   ", "  ....  ", " .#..#. ", ".#....#.", " .#..#. ", "  ....  ", "   #    ", "   #    "],
119    tinyLeaf: [" ..  ", "....", " .. "],
120    mushroom: [" .... ", ".rrrr.", "rrssrr", "rrssrr", ".pppp.", " .pp. "]
121  };
122
123  // Pixel divider — leaves + sprouts marching along a baseline
124  function PixelDivider({
125    width = 520
126  }) {
127    const segments = [];
128    const itemPx = 28;
129    const count = Math.floor(width / itemPx);
130    for (let i = 0; i < count; i++) {
131      const variant = i % 5;
132      let rows;
133      if (variant === 0) rows = SPRITES.tinyLeaf;else if (variant === 1) rows = ["  ##  ", "  ##  "];else if (variant === 2) rows = SPRITES.tinyLeaf;else if (variant === 3) rows = ["  ##  ", "  ##  "];else rows = SPRITES.sprout;
134      segments.push(/*#__PURE__*/React.createElement("div", {
135        key: i,
136        style: {
137          display: "flex",
138          alignItems: "flex-end"
139        }
140      }, /*#__PURE__*/React.createElement(PixelGrid, {
141        rows: rows,
142        scale: 2
143      })));
144    }
145    return /*#__PURE__*/React.createElement("div", {
146      className: "pixel-divider"
147    }, /*#__PURE__*/React.createElement("span", {
148      className: "line"
149    }), /*#__PURE__*/React.createElement("div", {
150      style: {
151        display: "flex",
152        gap: 6,
153        alignItems: "flex-end"
154      }
155    }, segments), /*#__PURE__*/React.createElement("span", {
156      className: "line"
157    }));
158  }
159
160  // Walking pixel character — a tiny 10x14 traveler with 2 frames
161  // frame A and frame B (legs swap)
162  const CHARACTER_FRAMES = [[
163  // frame A
164  "   ####   ", "  #ssss#  ", "  #s##s#  ", "  #ssss#  ", "   ####   ", "  ######  ", " #..##..# ", " #..##..# ", " #..##..# ", "  ######  ", "   ####   ", "   #  #   ", "   #  #   ", "  ##  ##  "], [
165  // frame B (legs forward/back)
166  "   ####   ", "  #ssss#  ", "  #s##s#  ", "  #ssss#  ", "   ####   ", "  ######  ", " #..##..# ", " #..##..# ", " #..##..# ", "  ######  ", "   ####   ", "  ##  ##  ", "  #    #  ", " ##    ## "]];
167  Object.assign(window, {
168    PixelGrid,
169    PixelIcon,
170    PixelDivider,
171    TECH_ICONS,
172    SPRITES,
173    CHARACTER_FRAMES
174  });
175})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.