Look, Everything Is…Code
Code is my default medium, not just for programs. It makes visual production cheaper, repeatable, and easier to change, but taste remains human.That cover is a hand-written HTML file, screenshotted by a browser with no window on it.The method: 24 files in, five images outMy last article went out…
Code is my default medium, not just for programs. It makes visual production cheaper, repeatable, and easier to change, but taste remains human.That cover is a hand-written HTML file, screenshotted by a browser with no window on it.The method: 24 files in, five images outMy last article went out with five images. I wrote 24 HTML files, rendered them through headless Chrome, and kept five. The cover alone took nine variants before one survived.Twenty-four files for five survivors is the method, not the embarrassment. Nothing here was one-shot by a model and shipped: nineteen of those renders I rejected by hand, one at a time. Each render is a single command, so all twenty-four still fit into one afternoon. The expensive part was judgment, not rendering.Then code got cheap. That part is well-documented; work that used to justify a contractor now takes an afternoon. Here is the part I claim as mine: when code gets cheap enough, it stops staying inside software. It invades things that were never code. What I generate now instead of drawing:the logo and the favicon setarticle covers and diagramssocial cards for 20,000+ pagesmy LinkedIn bannerscreenshots for docsThe logo is a Python functionMost people assume a company logo comes from a designer’s file. Mine comes from a function that returns SVG: an image described in markup, not pixels. One flag picks the square avatar or the badge variant. A sibling script builds the favicon set from the same constant: the mark in black on a gold tile.There is exactly one hand-picked color in the whole icon. Every other shade is derived from it by a mixing function; the blueprint grid lines are brand gold sunk 74 percent into the dark background, computed, never eyedropped.GOLD = "#f3a52b" # oklch(0.78 0.155 72), the brand primaryCANVAS = 512 # SVG coordinate space; raster size is independentCORNER = 104 # rounded-square radius, matches the faviconCELL = 36 # blueprint grid celldef _mix(a: str, b: str, t: float) -> str: ra, ga, ba = _hex(a) rb, gb, bb = _hex(b) return "#%02x%02x%02x" % tuple(round(x + (y - x) * t) for x, y in ((ra, rb), (ga, gb), (ba, bb)))line = _mix(GOLD, BG_BOT, 0.74) # grid line = gold sunk into the dark basegrid = f''' '''The background is not a picture. It is a pattern: one L-shaped path, tiled every 36 units, in a color computed from the brand primary. Three named constants at the top of the file are the entire “design system” of the icon; change CELL and the whole grid re-flows.That is the shipped org avatar, not an illustration of one. The mark is GOLD; every faint grid line behind it is _mix(GOLD, BG_BOT, 0.74).What it replaced: a Figma file only I could open, and an export step I always forgot.A constant you can change beats a shape you have to redraw.Covers and diagrams are HTML plus a headless browserI used to draw diagrams in Python with matplotlib. Even then the practice was the same: every arrowhead in my first article’s figures came out of one helper, eight lines of vector math instead of a stencil.def _classic_head_polygon(p_to, direction, head_length, head_width, notch_ratio): u = direction / np.linalg.norm(direction) perp = np.array([-u[1], u[0]]) back_center = p_to - u * head_length notch = back_center + u * (head_length * notch_ratio) upper_back = back_center + perp * (head_width / 2) lower_back = back_center - perp * (head_width / 2) return Polygon([p_to, lower_back, notch, upper_back], closed=True)Straight, curved, and arc arrows all reuse that one polygon. Now I author the picture as a web page instead, and let a browser take the photograph. .token{position:absolute;width:26px;height:26px;border-radius:50%; background:radial-gradient(circle at 38% 35%,#ffd98a,var(--amber) 62%,#c97e12); box-shadow:0 0 34px 10px rgba(245,166,35,.6);}No canvas, no image library: the glow is a box shadow, the token is a div. The photograph is one command.google-chrome --headless=new --disable-gpu --hide-scrollbars \ --force-device-scale-factor=2 --window-size="${W},${H}" \ --screenshot="$tmp" "file://$html"convert "$tmp" -resize "${W}x${H}" -strip -quality 95 "$out"What it replaced: Canva, and the habit of re-drawing a diagram from scratch every time one number changed.238 lines of HTML and CSS make the cover above and the one-source figure further down. Both come out of the same 569-byte shell script I shipped my last article with, byte-identical down to the hash.CSS is the layout engine. The browser is only the camera.Social cards are rendered at request timeThe image people see when my site is shared on LinkedIn is not a file in the repo. It is a component, rendered to a PNG when the crawler asks for it. The source is public: opengraph-image.tsx.export const size = { width: 1200, height: 630 };export default function OpenGraphImage() { return new ImageResponse( Owned by you. , { ...size } );}What it replaced: a folder of stale share images, each one a screenshot of a headline I had already rewritten.My MCP catalog serves 20,000+ server pages, and every one of them gets its own social card with a colored letter tile. Nobody assigned those colors. Five lines of hashing did:const TILE_COLORS = ['#f3a52b', '#3b82f6', '#8b5cf6', '#10b981', '#ef4444', '#ec4899'];function tileColor(seed: string): string { let hash = 0; for (let i = 0; i < seed.length; i += 1) hash = (hash * 31 + seed.charCodeAt(i)) | 0; return TILE_COLORS[Math.abs(hash) % TILE_COLORS.length];}The same name always lands on the same color, with zero design decisions stored anywhere. You cannot do that twenty thousand times in a design tool.A stale image is a file. A fresh one is a function.Screenshots are a loopProduct screenshots for docs used to mean pressing a key, cropping, and repeating in dark mode. Now Playwright does the whole set at a fixed size and double resolution (screenshot-blog.mjs, public).const browser = await chromium.launch();for (const { url, file, theme } of shots) { const ctx = await browser.newContext({ viewport: { width: 1280, height: 900 }, deviceScaleFactor: 2 }); await ctx.addInitScript((t) => localStorage.setItem('theme', t), theme); const page = await ctx.newPage(); await page.goto(`${BASE}${url}`, { waitUntil: 'networkidle' }); await page.screenshot({ path: `${OUT}/${file}`, fullPage: true });}Anything I redo in dark mode is a loop I have not written yet.The LinkedIn banner is a random seedMy LinkedIn background looks hand-crafted: amber nodes dense on the left, fading right, thin lines between neighbors. The part that reads as designed is one small function. Brightness falls off with distance from the left edge, and a line inherits the brightness of its midpoint, dimmed by its length:def brightness(x): # 1.0 at left edge -> ~0.12 at right edge (matches fade) t = max(0.0, min(1.0, x / W)) return 0.12 + (1.0 - t) ** 1.6 * 0.9for i in range(N): for j in range(i + 1, N): x1, y1, _ = nodes[i] x2, y2, _ = nodes[j] d = math.hypot(x1 - x2, y1 - y2) if d < LINK_DIST: b = brightness((x1 + x2) / 2) * (1 - d / LINK_DIST) op = round(b * 0.55, 3) if op < 0.015: continue svg.append(f'')That is the real banner, not a mockup of one. Every line in it has the opacity that brightness() returned for its midpoint.The taste is three numbers: the 0.55 damp, the 1.6 falloff, and the 0.015 floor that drops the faintest lines instead of drawing mud on the right. Two commands make the PNG:python3 plexus.py > plexus.svgrsvg-convert -w 3548 -h 888 plexus.svg | convert - -resize 1774x444 plexus-bg.pngWhat it replaced: nothing. I would never have commissioned a banner. The whole script is public: plexus.py, 72 lines. Run it, and you get my banner.This asset exists only because generating it cost less than deciding whether I needed it.Slides are the same shape, and the piece I moved last: markdown in, deck out, through Marp or Slidev.Even the charts are circles doing mathThe composition donut in my design system is not a chart library (donut-card.tsx, public). It is one SVG circle wearing its stroke as data. The circumference is the whole; each segment gets a stroke-dasharray of "this much on, the rest off," and the offsets stack.const sum = total ?? (segments.reduce((s, x) => s + x.value, 0) || 1);const r = 18;const c = 2 * Math.PI * r;let offset = 0;segments.map((s) => { const length = (s.value / sum) * c; const dash = `${length} ${c - length}`; const dashOffset = -offset; offset += length; return ;});No arc paths, no trigonometry, no dependency. A pie chart is a circle that knows arithmetic.The furthest I have pushed this is a full 3D scene: my Obsidian plugin renders your notes as a rotating galaxy, live in the Obsidian community store. Every tag becomes a glowing diamond inside a wireframe cage (tag-hub-mesh.ts, public). Two unit geometries do it: a solid octahedron and the wireframe of a subdivided one, each built once and reused by every node.const CORE_GEOMETRY = new OctahedronGeometry(1, 0);const CAGE_GEOMETRY = new WireframeGeometry(new OctahedronGeometry(1, 1));const core = new Mesh(CORE_GEOMETRY, coreMat);core.scale.setScalar(opts.radius * CORE_SCALE);const cage = new LineSegments(CAGE_GEOMETRY, cageMat);cage.scale.setScalar(opts.radius * CAGE_SCALE);group.add(core, cage);That is the plugin rendering a real vault, not a concept shot. Every position is force-layout output: my notes made their own galaxy, yours would make a different one.What these replaced: a charting library I never had to add and, honestly, a graphic I could never have drawn at all.One committed value, several translations. That figure came out of the same script as the cover.The reason it holds togetherAssets written as code can be aligned with each other, because they can share a value instead of resembling one.One line in my design system’s tokens.css sets the brand primary for the dark theme all my sites default to:--color-primary: oklch(0.78 0.155 72);The dashboard imports it. That value converts to exactly #f3a52b, the GOLD constant at the top of the logo script. The diagrams, the covers, the social cards, and the logo all read the same number.One source, several tool-native translations. A design file cannot import anything.An agent can fix a text fileWhen a render fails, the failure arrives as text: a font the headless browser does not have, or an SVG path that will not parse. My agent reads the error, edits the source line, and re-renders. That loop closes because the asset is text.A binary design file cannot hand an agent a parser error, and an agent cannot open it to make the fix.A logo in SVG is code, not an image, and that is the whole difference.What this does not doIt does not produce high-craft brand work. Spatial judgment is where generated vector art still falls down, and no amount of iteration turns a script into an art director. If you need a wordmark that will outlive the company, hire a human.The usual objection — that code is cheap, but software is expensive to maintain — does not bite here for one reason: these assets are disposable by design. I do not maintain a cover. When the article changes, I delete the PNG and run the script. Nine variants for one cover is not sloppiness. It is the cost structure.Iteration is the only thing that got cheap. Taste is still applied by hand, one rejection at a time.Try the pattern in one command. Write any HTML file, call itcover.html, then:google-chrome --headless=new --window-size=1200,630 --force-device-scale-factor=2 \ --screenshot=out.png "file://$PWD/cover.html"That is a design tool. It was already installed.Everything in this article is live, not staged:agentage.io — the logo, favicons, and request-time social cardsAgentage Galaxy in the Obsidian store — the 3D vault graphvreshch.com/blog — covers and screenshots from the Playwright pipelinemedium.com/@vreshch — the previous articles whose figures came out of render.shAbout the authorVolodymyr Vreshch builds agentage Memory, a shared memory layer for AI agents, and catalog.agentage.io, an MCP directory indexing 20,000+ servers. He writes about agents, MCP, and developer tooling at vreshch.com. Senior Software Engineer at Microsoft. On GitHub: @vreshch.This story is published on Generative AI. Connect with us on LinkedIn and follow Zeniteq to stay in the loop with the latest AI stories.Subscribe to our newsletter and YouTube channel to stay updated with the latest news and updates on generative AI. Let’s shape the future of AI together!Look, Everything Is…Code was originally published in Generative AI on Medium, where people are continuing the conversation by highlighting and responding to this story.Source: Generative AI Pub — Published — Category: Image AI