CommunityImagegithub.com

Songhonglei/text-to-elegant-image

Intelligently analyzes Markdown/plain text content, formats it, and exports it as a high-resolution elegant long image or shareable poster (with 18 built-in visual styles). Triggered by intents like

What is text-to-elegant-image?

This skill converts Markdown or plain text into beautifully formatted, high-resolution long images (vertical layout) or shareable posters. It works by generating an HTML file with rich CSS styling and then capturing a screenshot using a headless Puppeteer browser, producing a 2x deviceScaleFactor PNG. The skill includes 18 distinct visual styles (e.g., Cyberpunk, Minimal, Apple, Newspaper, Chinese Ink, etc.), each with its own CSS, typography, and decorative elements. It intelligently scans the content for structured elements (headings, key quotes, comparisons, timelines, KPIs) and can convert them into visual components like KPI cards, progress bars, donut charts, and timeline steps using a built-in component library. Users can specify a style or let the system recommend one based on content type, choose between long image and poster (3:4) layouts, and customize the output width, frame margin, card background, and footer. The skill performs dependency checks (Node.js, Chrome, puppeteer-core) before each use and validates that no emoji are present in the generated HTML to avoid rendering issues in headless environments. It supports changing styles without regenerating the entire HTML, and provides a fallback mechanism if screenshot capture fails.

Works with✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Songhonglei/text-to-elegant-image/tree/HEAD

Installed? Explore more Image skills: steipete/songsee, affaan-m/frontend-design, mattpocock/improve-codebase-architecture · View all 6 →

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

Text to Elegant Image

Converts Markdown or plain text into beautifully formatted high-definition long images. Works by generating an HTML file and capturing a screenshot with a headless Puppeteer browser.

Resource File Structure

resources/
├── styles/               # 18 styles, one file per style (CSS + HTML example + component variable mapping + decorative elements)
│   ├── 01_cyberpunk.md … 18_vivid.md
│   └── _BASE.md          # Common HTML skeleton + layout conventions + open-source CSS tool library reference
└── components.css        # General visual component library (KPI cards/progress bars/comparison bars/donut/flows/timelines, etc.)

Reading Discipline: Read only the files you need. Once the style is determined, read only the corresponding styles/NN_key.md + styles/_BASE.md files; do not read other style files. Read components.css only when the content includes data/flows/comparisons.

Style Selection

There are 18 styles available:

#FileStyleVisual KeywordsBest For
101_cyberpunk.mdCyberpunk (Default)Dark/Neon/SVG Hex GridAI analysis, tech reports, cool posters
202_minimal.mdMinimal & ElegantWhite background/Serif/Whitespace/Noise rice paperLiterary essays, diaries, humanities
303_apple.mdApple-InspiredLight gray/Frosted glass cards/Colorful windowsProductivity tools, retrospectives, methodologies
404_cowork.mdCowork Light TechApple gray-white/Tech blue/Frosted glass HeroInternal sharing, AI tool intros, product manuals
505_newspaper.mdNewspaper/MagazineIvory/Lead type grain/Black & white printHistorical events, timelines, in-depth narratives
606_bloomberg.mdBloomberg TerminalPure black CRT texture/Orange glowing textData reports, metric comparisons, fintech
707_ink.mdChinese Ink ScrollRice paper ink wash/Cinnabar red/Brushstroke lineChinese history, culture & art, Eastern aesthetics
808_steampunk.mdSteampunkDark brown/Copper gears/Rivets/Pressure gaugesIndustrial history, technological leaps, mechanical aesthetics
909_xhs.mdXiaohongshu StyleWhite background/Official Red/Rounded cardsKnowledge notes, lifestyle guides,干货 (value) sharing
1010_morandi.mdMorandi (Muted Tones)Warm gray & cream base/Dusty green/Swatch cards/Restrained whitespaceBrand methodologies, retrospectives, humanities essays
1111_glass.mdGlassmorphismColorful gradient background/Light orbs/Frosted cardsSaaS websites, event pages, feature showcases
1212_palace.mdImperial Palace (Forbidden City)Dark brown wood base/Cinnabar red/Gold characters/Meander sealChinese history, traditional festivals, museum exhibitions
1313_fresh.mdFresh Natural GreenLight mint background/Forest green/Leaf elementsHealth & wellness, lifestyle, science & guide articles
1414_earthy.mdEarthy & NaturalLinen weave/Terracotta orange/Hand-stitched card effectHandcraft coffee, lifestyle aesthetics, brand stories
1515_dreamy.mdElegant Purple DreamyLavender base/Purple gradient/Starry accentsBeauty & fashion, emotions, event posters
1616_macaron.mdMacaron PastelCream pink base/Polka dots/Candy-colored numbersDesserts & maternity, lifestyle sharing, holiday greetings
1717_carbon.mdDark MinimalCharcoal dark base/Teal green/Terminal line numbersTechnical docs, developer content, data reports
1818_vivid.mdVivid GradientPurple-pink-orange gradient/Fluid color blocks/Gradient outlined cardsEvent promotions, youth brands, music & entertainment

Xiaohongshu Style (Style 9) – Two Modes

Style 9 has two built-in sub-modes, specified by the user; if unspecified, Mode A is the default:

ModeTrigger WordsVibe
A — Clean & Formal"Simple"/"Formal"/"Clean"/"Knowledge"Thin borders, small border-radius, underlined numbers, high breathing space
B — Rich & Lively"Lively"/"Rich"/"Cute"/"Life"/"Fun"Light pink, large border-radius, solid circle numbers, wavy decorative line, Footer with CTA text

After generation, inform the user of the current mode and suggest switching:

"Generated in clean mode. If you'd like a lively version, say 'make a lively one'."

Style Selection Guide

When the user doesn't specify a style, automatically recommend based on content type and inform the user of available options:

Content leans toward → Recommended Style
──────────────────────────────────────
Tech/AI/Data Analysis        → Cyberpunk or Bloomberg Terminal
History/Timeline/Narrative   → Newspaper/Magazine or Chinese Ink Scroll (Chinese history)
Industry/Machinery/Tech Leap → Steampunk
Efficiency/Methodology/Summary → Apple-Inspired or Cowork Light Tech
Literature/Diary/Humanities  → Minimal & Elegant or Chinese Ink Scroll
Corporate Internal Sharing   → Cowork Light Tech
Knowledge Notes/Lifestyle Guides/Value Sharing → Xiaohongshu Style
Brand Methodologies/Retrospectives/High-End → Morandi (Muted Tones)
SaaS/Product Website/Event Pages → Glassmorphism or Vivid Gradient
Chinese History/National Style/Museums → Imperial Palace or Chinese Ink Scroll
Health/Eco/Lifestyle → Fresh Natural Green
Handcraft/Coffee/Life Aesthetics → Earthy & Natural
Beauty/Fashion/Emotions/Romance → Elegant Purple Dreamy
Desserts/Mom & Baby/Cute/种草 (Grow grass / recommendation) → Macaron Pastel
Tech Docs/Developers/Eye Comfort → Dark Minimal
Events/Promos/Trendy/Youth → Vivid Gradient

Example recommendation script:

"Based on the content, I recommend 'Xiaohongshu Style' (strong note-taking feel, good for sharing) or 'Apple-Inspired' (more tool-like). There are 18 styles in total; you can also tell me which one you'd like (e.g., 'Imperial Palace', 'Morandi', 'Glassmorphism')."

Keyword matching when users describe style preferences:

  • "Techy"/"Cool"/"Dark"/"Neon" → Cyberpunk
  • "Simple"/"White"/"Clean"/"Artistic" → Minimal & Elegant
  • "Apple-like"/"Modern"/"Product feel" → Apple-Inspired
  • "Light tech"/"Internal"/"Blue"/"Apple blue"/"Tech blue" → Cowork Light Tech
  • "Newspaper"/"Magazine"/"History"/"Retro print" → Newspaper/Magazine
  • "Data"/"Finance"/"Terminal"/"Bloomberg" → Bloomberg Terminal
  • "Ink wash"/"Chinese"/"Oriental"/"Scroll"/"Ancient" → Chinese Ink Scroll
  • "Steam"/"Punk"/"Mechanical"/"Copper"/"Gears"/"Retro industrial" → Steampunk
  • "Xiaohongshu"/"Notes"/"种草"/"Guides"/"Sharing"/"Red" → Xiaohongshu Style (Official Red #FF2442)
  • "Morandi"/"Muted tones"/"Low saturation"/"Quiet"/"High-end" → Morandi (Muted Tones)
  • "Glass"/"Frosted glass"/"Matte"/"Transparent"/"Lucid"/"SaaS" → Glassmorphism
  • "Imperial Palace"/"Palace"/"Red Wall"/"Gold gilding"/"Cinnabar"/"National style" → Imperial Palace
  • "Fresh"/"Green"/"Natural"/"Mint"/"Eco"/"Forest" → Fresh Natural Green
  • "Earthy tones"/"Natural wood"/"Terracotta"/"Linen"/"Handcrafted"/"Warm & down-to-earth" → Earthy & Natural
  • "Purple"/"Dreamy"/"Lavender"/"Romantic"/"Elegant purple" → Elegant Purple Dreamy
  • "Macaron"/"Pink"/"Pastel"/"Sweet"/"Cute"/"Girly" → Macaron Pastel
  • "Dark mode"/"Dark"/"Black minimal"/"Eye comfort"/"Techy"/"Developer" → Dark Minimal
  • "Gradient"/"Vibrant"/"Trendy"/"Youthful"/"Colorful"/"Dynamic" → Vivid Gradient

Layout Modes (Long Image / Poster)

Default output is a long image (560px wide, vertical multi-section). Switch layout when the user says "poster"/"quote poster"/"cover"/"header image":

LayoutTrigger WordsSpecsLayout Notes
Long Image (Default)"Long image"/"Big image"/unspecifiedWidth 560px, height autoTitle area + multiple content sections, full content load
Quote Poster"Poster"/"Quote"/"Share image"Width 600px, height 800px fixed (3:4)One core quote enlarged and centered + large whitespace + small source text, content limited to 30 characters
Cover Card"Cover"/"Header image"Width 600px, height 800px fixed (3:4)Large title + subtitle + 2-3 short bullet points, Xiaohongshu cover rhythm

Poster/Cover mode: Choose any of the 18 styles for its color palette and aesthetic. Change .container to width: 600px; height: 800px; display: flex; flex-direction: column; justify-content: center; for fixed height centered layout; the screenshot command MUST pass --fixed-height 800 to bypass height auto-detection, and pass width as 600, like:

node scripts/export_image.js <html> <output.png> 600 --fixed-height 800

Long image mode (default): Do not pass --fixed-height; the script automatically measures the actual .container height and crops excess bottom margin. Frame Margin: Long image mode defaults to adding a 32px uniform frame around the canvas (left/right by widening the canvas + margin:auto, top/bottom by overriding body padding), equal margins on all sides, no content touching the edges—no manual parameter needed. To customize, use --frame <px> (e.g., --frame 48), or --frame 0 to disable the frame and let content touch the edges. Fixed layouts (--fixed-height) already have the container filling the canvas with internal padding and will automatically ignore --frame. Card Background: The .container in all 18 styles defaults to a card visual (background color + border + border-radius/shadow, each style using its own color scheme and aesthetic, e.g., cyberpunk neon border, ink wash paper-style border, Morandi solid color block). This pairs with the frame margin to create a "card floating on canvas" matted effect—no manual parameter needed; it's on by default. To revert to the old flat full-width style (content blending directly into the background, no card border), pass --flat: node scripts/export_image.js <html> <output.png> 560 --flat. ⚠️ For Glassmorphism (11_glass), the card background is the frosted glass effect itself; --flat would eliminate its core visual—not recommended. Cover cards: Consider adding a soft glow decorative orb (top-right or bottom-right, using radial-gradient + absolute positioning) to balance the whitespace from left-aligned content and avoid a large empty right side.

Execution Flow

Step 1: Parse Content Structure

Read the user's content and extract:

  • Main title, subtitle
  • Core quote (to be displayed prominently)
  • Structured sections (comparisons, lists, timelines, etc.)

Visualization Opportunity Scan (Important): Scan the content for key numbers, percentages, rankings, trends, processes, comparisons, and timelines—these should be converted into visual components (KPI cards, progress bars, comparison bars, donuts, process steps, timelines, see comments in resources/components.css) rather than being presented as plain text. 2-3 key numbers warrant a KPI card; rankings/comparisons warrant comparison bars. Rich visuals are key to a quality long image.

Step 2: Read Style Resources and Generate HTML

  1. After determining the style, read resources/styles/<NN_key>.md (containing style CSS, HTML structure examples, component variable mapping, font injection, signature decorative elements) and resources/styles/_BASE.md (common skeleton + layout conventions)
  2. If Step 1 revealed visualization opportunities, read resources/components.css, copy the required component CSS segments into <style>, and also copy the :root block of the 'component variable mapping' from the style file (components use --t2e-* variables for color matching)
  3. If the style file contains a "Font Injection" section, add the font <link> into <head>
  4. If the style file contains a "Signature Decorative Elements" section, prioritize using these elements to enhance identity
  5. Inject the content into the skeleton, generate the complete HTML, and save it to /tmp/elegant_image_<timestamp>.html using the write tool (the tool name is write, not write_to_file)

Footer Handling Rules (Important):

  • User has not specified author info: Write the default value into the .footer element in the HTML: <skill name> @ <current model name>
    • Example: text-to-elegant-image @ claude-4.6-sonnet
  • User has specified author info (e.g., "Author: John Doe"): Write the user-specified text.
  • User explicitly says no footer: Do not generate the .footer element in the HTML; append --no-footer to the screenshot command.

Do not write "Generated by " or any AI identity identifier in the footer.

Step 3: Dependency Check & Initialization (Before Each Use)

Run the setup script to check the environment:

bash <skill directory>/scripts/setup.sh
  • Checks Node.js (>= v18), Chrome/Chromium, puppeteer-core - three dependencies.
  • If all are ready, it passes directly and prints ✔ All dependencies ready.
  • If Node.js / Chrome is missing: The script prints an error and exits (exit 1), prompting to install the missing dependency (Node.js >= v18 / Chrome or Chromium).
  • If puppeteer-core is missing: The script prompts "Installing..." and runs npm install (the installation output is visible; it only installs the puppeteer-core rendering dependency).

The script returns very quickly when dependencies are ready, with no performance overhead. It is recommended to run it before each use.

Step 4: Emoji Check (Mandatory Before Screenshot)

Absolutely prohibit the use of emoji when generating HTML—the headless environment lacks color emoji fonts, which will render as black square garbled characters. Alternative solutions:

Original emoji usageAlternative
Section icons (chart/crystal ball/map, etc.)Plain text title, differentiated by border-left color bar
Status markers (checkmark/cross/warning)Use colored badge: <span class="badge-green">Fully Automatic</span>
Decorative symbolsDelete, or use style-specific signature decorative elements (leaves/stars/seals, etc.)
Progress/arrowsUse CSS ::before pseudo-elements or plain text ->, ·

After generation, you MUST run a check:

python3 <skill directory>/scripts/check_emoji.py <HTML file path>

If it FAILs (exit 1) → replace according to the output line numbers → re-run until PASS before proceeding to Screenshot.

Step 5: Execute Screenshot Export

node <skill directory>/scripts/export_image.js \
  <absolute HTML file path> \
  <output directory>/<filename>.png \
  [width] [--author "Author Info" | --no-footer]

Output Directory Configuration (Guide the user on first use):

The output directory is resolved with the following priority (high to low):

  1. The output path explicitly passed in the command
  2. The environment variable T2EI_OUTPUT_DIR
  3. Default value: ./output (the output/ directory under the current working directory)

💡 First-Time User Guide: The first time you generate a long image for a user, ask once: "Which directory would you like to save the images to?"

  • User doesn't specify → Use the default ./output.
  • User specifies a fixed directory → Suggest persisting it via an environment variable:
    echo 'export T2EI_OUTPUT_DIR="$HOME/my-images"' >> ~/.bashrc
    

Do not ask again afterward.

Footer Parameter Explanation:

ParameterEffect
Not passed (default)Uses the footer already written in the HTML (see Step 2)
--author "Custom text"Replaces the footer with the specified text
--no-footerCompletely removes the footer

The script automatically detects the Chrome/Chromium path (Linux/macOS/WSL), automatically waits for webfonts to load (up to 8s; non-blocking if CDN is unreachable), automatically measures content height for precise cropping, and automatically creates the output directory if it does not exist. Width defaults to 600px, with 2x deviceScaleFactor for high-definition output.

Step 6: Return Results and Deliver Image

After a successful screenshot, simply return the local PNG path to the user:

Image generated 🎉
Local path: <output directory>/<filename>.png

The user can view this PNG directly in the file system / editor or distribute it themselves.

📌 Regarding Auto-Distribution (Reserved, Not Built-in) This open-source version only handles the "text → elegant long image" generation; it does not include any automatic image posting capability to IM channels. To automatically push the generated image to channels like WeChat / Telegram / Slack, you can integrate the respective platform's Bot / API after this step (future versions may provide optional adapters). Currently, please let the user manually retrieve the local PNG for distribution.

Style Change (Low-Cost Path)

When a user says "Change to [another] style" for an already generated long image: Do not rewrite the entire HTML. Read the new style file, only replace the <style> segment for the style CSS and the component variable mapping (--t2e-* :root block), and batch-replace the old style's prefix class in the HTML (e.g., mo-*) with the new style's prefix (e.g., fr-*)—the skeleton components for each style are isomorphic (header/title/subtitle/section-title/card/item/num/quote/tag/divider/footer), so they map one-to-one. Then re-run Steps 4-6.

Fallback Mechanism

If the screenshot fails (e.g., browser not installed), the script will output the HTML file path and guide the user to open it in a browser and manually print/save as PDF/image.

Key Notes

  • The third argument of export_image.js can specify the width (default 600px), with 2x deviceScaleFactor ensuring high-definition output.
  • Do not reference external images; use pure CSS shapes or inline SVG data URIs for icons to avoid network loading failures. The only allowed external resource is the font CDN (fonts.googleapis.com, a public service; falls back to system fonts, non-blocking).
  • Output path: <output directory>/<filename>.png (default output directory is ./output, configurable with the T2EI_OUTPUT_DIR environment variable, see Step 5).

Script List

ScriptPurpose
scripts/setup.shDependency check (Node/Chrome/puppeteer-core); prompts and installs if puppeteer-core is missing (output visible)
scripts/check_emoji.pyEmoji check before screenshot; outputs character and line number on FAIL
scripts/export_image.jsPuppeteer screenshot export: font waiting + precise height cropping + uniform frame margin + card background toggle (--flat) + footer injection/removal

Related Skills