惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The GitHub Blog
The GitHub Blog
云风的 BLOG
云风的 BLOG
T
Threatpost
WordPress大学
WordPress大学
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
PCI Perspectives
PCI Perspectives
T
The Exploit Database - CXSecurity.com
Y
Y Combinator Blog
雷峰网
雷峰网
爱范儿
爱范儿
The Hacker News
The Hacker News
Last Week in AI
Last Week in AI
Simon Willison's Weblog
Simon Willison's Weblog
T
Tor Project blog
S
Securelist
宝玉的分享
宝玉的分享
L
LangChain Blog
O
OpenAI News
AI
AI
P
Privacy International News Feed
L
LINUX DO - 最新话题
D
DataBreaches.Net
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Attack and Defense Labs
Attack and Defense Labs
罗磊的独立博客
M
MIT News - Artificial intelligence
Security Archives - TechRepublic
Security Archives - TechRepublic
月光博客
月光博客
博客园 - 【当耐特】
T
Tailwind CSS Blog
C
Cybersecurity and Infrastructure Security Agency CISA
H
Help Net Security
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园_首页
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Hacker News - Newest:
Hacker News - Newest: "LLM"
腾讯CDC
Jina AI
Jina AI
The Last Watchdog
The Last Watchdog
K
Kaspersky official blog
Webroot Blog
Webroot Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Blog — PlanetScale
Blog — PlanetScale
MyScale Blog
MyScale Blog
MongoDB | Blog
MongoDB | Blog
P
Proofpoint News Feed
Recorded Future
Recorded Future
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
博客园 - 三生石上(FineUI控件)
The Cloudflare Blog

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
How we generate code screenshots for socials
Accreditly · 2026-06-18 · via DEV Community

We post a lot of code to X and LinkedIn. For a long time we grabbed those screenshots by hand: snippet open in the editor, crop the window, drop the PNG into the post. It worked, but it never stayed consistent. The theme drifted between posts, the widths were all over the place, the output looked soft on retina screens, and roughly once a month someone shipped a screenshot with the file tree still showing.

So we stopped doing it by hand. These days we generate code screenshots two ways, and which one we reach for depends entirely on whether a human or a machine is making the image. For one-offs we use a browser tool, the Code Screenshot Generator, which turns a snippet into a PNG without going anywhere near the codebase. For anything that needs to happen at publish time, or the same way across fifty snippets, we call a code screenshot API instead. This post covers both, and why we settled on the split.

Why screenshotting the editor does not scale

Grabbing the editor window is fine for one image. The trouble starts when you do it repeatedly.

Every screenshot ends up slightly different. One uses your current editor theme, the next uses whatever you switched to last week. The line gutter is in one, absent from another. The padding is whatever the window happened to be. Crop them by hand and the widths never match, so a thread of three snippets reads as three different posts stitched together. And because you are capturing a real screen, the output is tied to your display, which means it looks crisp on your machine and soft on everyone else's phone.

Carbon and Ray.so solve the prettiness problem, and we used them happily for years. They are genuinely good in-browser tools. The catch is that both are in-browser only, with no API. The moment you want a screenshot generated automatically, at publish time or inside a build step, a hand tool is the wrong shape for the job. You cannot put a button-click in a deploy pipeline.

The quick route: a browser tool for one-offs

When it is a single snippet for a tweet or a slide, and you are away from the code anyway, the fastest path is the online code screenshot tool. Paste the snippet, pick the language, and you get a clean image back.

It highlights any language Prism or highlight.js recognises, which is roughly three hundred of them, so JavaScript, Python, Rust, SQL, Elixir and the long tail are all covered. You pick a theme (One Dark, Dracula, GitHub, Night Owl and a handful of others, each matching its VS Code counterpart closely), toggle the macOS-style window chrome on or off, set the padding, and choose a solid colour or a gradient behind the code. Then you download the PNG or copy the hosted URL straight into a post.

That covers the ad-hoc case. The interesting part is what happens when you want the same output without a person in the loop.

The repeatable route: a code screenshot API

When the image needs to be produced by a machine, at publish time, in CI, or off a CMS hook, we use the Code Screenshot API. It is a ready-made template on HTML to Image (html2img.com): you POST the code and a few styling options as JSON, and you get back a hosted PNG URL. It is the same renderer that sits behind the browser tool, so the screenshots match whichever route produced them. There is no headless Chrome for you to install, patch, or babysit.

You need two things to follow along: an account with an API key, and a snippet to render. Here is the smallest call that does something useful, with curl:

curl -X POST https://app.html2img.com/api/v1/templates/code-screenshot \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "export async function fetchUser(id: string) {\n  const res = await fetch(`/api/users/${id}`);\n\n  if (!res.ok) {\n    throw new Error(`Failed to load user ${id}`);\n  }\n\n  return res.json() as Promise<User>;\n}",
    "language": "typescript",
    "title": "src/lib/users.ts",
    "theme": "atom-one-dark",
    "background": "linear-gradient(135deg, #6366F1 0%, #8B5CF6 50%, #EC4899 100%)",
    "padding": 72,
    "show_window_chrome": "true",
    "show_line_numbers": "false"
  }'

The fields map onto what you would set in the browser tool. code is the snippet, with newlines escaped in the JSON string. language drives the highlighting. title is the filename shown in the window bar. theme, background, and padding are the styling, and the two show_ flags toggle the window chrome and line numbers. Only code is required; leave the rest off and the template falls back to sensible defaults. The full input list, with example values and validation rules, is in the Code Screenshot template reference.

By default the template renders a 1600 by 1000 PNG, which you can override with width and height. A successful call returns JSON:

{
  "success": true,
  "id": "abc123",
  "url": "https://i.html2img.com/abc123.png",
  "credits_remaining": 1234,
  "template": "code-screenshot"
}

The url is a CDN link to the rendered image. That URL is the whole point: you store it, embed it, or attach it to a post.

Wiring it into the publishing flow

In practice you do not run curl, you call this from the code that publishes the post. Here is the Node version wrapped in a small helper that hands back the image URL:

async function codeScreenshot(code, language, title) {
  const res = await fetch('https://app.html2img.com/api/v1/templates/code-screenshot', {
    method: 'POST',
    headers: {
      'X-API-Key': process.env.HTML2IMG_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      code,
      language,
      title,
      theme: 'atom-one-dark',
      background: 'linear-gradient(135deg, #6366F1 0%, #8B5CF6 50%, #EC4899 100%)',
      padding: 72,
      show_window_chrome: 'true',
      show_line_numbers: 'false',
    }),
  });

  if (!res.ok) {
    throw new Error(`code-screenshot render failed: ${res.status}`);
  }

  const { url } = await res.json();
  return url;
}

Call it once per snippet when a post is published, save the returned URL alongside the post, and attach that image to the tweet or LinkedIn share. The code is rendered once and served from the CDN forever after, so there is no per-view cost.

We mostly publish from Laravel, and the shape is identical there. The HTTP client does the work:

use Illuminate\Support\Facades\Http;

$url = Http::withHeaders(['X-API-Key' => config('services.html2img.key')])
    ->post('https://app.html2img.com/api/v1/templates/code-screenshot', [
        'code' => $snippet,
        'language' => 'php',
        'title' => 'app/Actions/RenderSnippet.php',
        'theme' => 'atom-one-dark',
        'show_window_chrome' => 'true',
    ])
    ->throw()
    ->json('url');

The other languages follow the same pattern, and the reference has worked examples for Python, Ruby, React and Vue if you want a closer fit to your stack.

Getting the screenshots to actually read on social

A clean render is only half the job. Social feeds re-compress your image and shrink it, so a few habits make the difference between a screenshot people can read and one they scroll past.

Trim the snippet first. Anything past roughly twenty lines shrinks below a readable point size once the renderer scales it to fit, so cut to the part that matters and split a longer example into a sequence of smaller images rather than one tall one nobody can read.

Pick a theme that survives compression. Low-contrast themes like Solarized Light lose detail when X or LinkedIn re-encode the image for the feed. Higher-contrast themes (One Dark, Dracula, GitHub) hold up far better through that round trip, so favour them for anything social.

Keep it sharp. The browser tool has a 2x DPI toggle for retina output. Through the API the default 1600 by 1000 render is already large enough to stay crisp after a feed re-compresses it, and you can push the dimensions higher if you need more headroom.

Cache the URL hard. A rendered snippet's CDN URL does not change unless the code changes, so set long cache headers and only re-render when the snippet itself moves. Re-rendering an unchanged screenshot on every publish is wasted work.

Which one we reach for

The split is simple. One-offs, and anything where you are already away from the editor, go through the code screenshot generator in the browser. Anything repeatable, or that has to happen at publish time, goes through the code screenshot template and its API. Because both run the same renderer, the two never drift apart, which was the original problem we set out to fix.

If you want to go deeper, the Code Screenshot API reference lists every input, including line numbers, diff highlighting by setting the language to diff, and custom themes via a Prism variables block.

How do you handle code screenshots for your posts at the moment, still grabbing them by hand, or have you wired it into publishing? Let me know in the comments.