Text to Elegant Image
- Version: 1.2.1
- License: MIT
- Author: Evan Song · github.com/Songhonglei
- Repository: https://github.com/Songhonglei/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:
| # | File | Style | Visual Keywords | Best For |
|---|---|---|---|---|
| 1 | 01_cyberpunk.md | Cyberpunk (Default) | Dark/Neon/SVG Hex Grid | AI analysis, tech reports, cool posters |
| 2 | 02_minimal.md | Minimal & Elegant | White background/Serif/Whitespace/Noise rice paper | Literary essays, diaries, humanities |
| 3 | 03_apple.md | Apple-Inspired | Light gray/Frosted glass cards/Colorful windows | Productivity tools, retrospectives, methodologies |
| 4 | 04_cowork.md | Cowork Light Tech | Apple gray-white/Tech blue/Frosted glass Hero | Internal sharing, AI tool intros, product manuals |
| 5 | 05_newspaper.md | Newspaper/Magazine | Ivory/Lead type grain/Black & white print | Historical events, timelines, in-depth narratives |
| 6 | 06_bloomberg.md | Bloomberg Terminal | Pure black CRT texture/Orange glowing text | Data reports, metric comparisons, fintech |
| 7 | 07_ink.md | Chinese Ink Scroll | Rice paper ink wash/Cinnabar red/Brushstroke line | Chinese history, culture & art, Eastern aesthetics |
| 8 | 08_steampunk.md | Steampunk | Dark brown/Copper gears/Rivets/Pressure gauges | Industrial history, technological leaps, mechanical aesthetics |
| 9 | 09_xhs.md | Xiaohongshu Style | White background/Official Red/Rounded cards | Knowledge notes, lifestyle guides,干货 (value) sharing |
| 10 | 10_morandi.md | Morandi (Muted Tones) | Warm gray & cream base/Dusty green/Swatch cards/Restrained whitespace | Brand methodologies, retrospectives, humanities essays |
| 11 | 11_glass.md | Glassmorphism | Colorful gradient background/Light orbs/Frosted cards | SaaS websites, event pages, feature showcases |
| 12 | 12_palace.md | Imperial Palace (Forbidden City) | Dark brown wood base/Cinnabar red/Gold characters/Meander seal | Chinese history, traditional festivals, museum exhibitions |
| 13 | 13_fresh.md | Fresh Natural Green | Light mint background/Forest green/Leaf elements | Health & wellness, lifestyle, science & guide articles |
| 14 | 14_earthy.md | Earthy & Natural | Linen weave/Terracotta orange/Hand-stitched card effect | Handcraft coffee, lifestyle aesthetics, brand stories |
| 15 | 15_dreamy.md | Elegant Purple Dreamy | Lavender base/Purple gradient/Starry accents | Beauty & fashion, emotions, event posters |
| 16 | 16_macaron.md | Macaron Pastel | Cream pink base/Polka dots/Candy-colored numbers | Desserts & maternity, lifestyle sharing, holiday greetings |
| 17 | 17_carbon.md | Dark Minimal | Charcoal dark base/Teal green/Terminal line numbers | Technical docs, developer content, data reports |
| 18 | 18_vivid.md | Vivid Gradient | Purple-pink-orange gradient/Fluid color blocks/Gradient outlined cards | Event 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:
| Mode | Trigger Words | Vibe |
|---|---|---|
| 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":
| Layout | Trigger Words | Specs | Layout Notes |
|---|---|---|---|
| Long Image (Default) | "Long image"/"Big image"/unspecified | Width 560px, height auto | Title 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.containerheight 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 0to 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.containerin 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;--flatwould eliminate its core visual—not recommended. Cover cards: Consider adding a soft glow decorative orb (top-right or bottom-right, usingradial-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
- After determining the style, read
resources/styles/<NN_key>.md(containing style CSS, HTML structure examples, component variable mapping, font injection, signature decorative elements) andresources/styles/_BASE.md(common skeleton + layout conventions) - If Step 1 revealed visualization opportunities, read
resources/components.css, copy the required component CSS segments into<style>, and also copy the:rootblock of the 'component variable mapping' from the style file (components use--t2e-*variables for color matching) - If the style file contains a "Font Injection" section, add the font
<link>into<head> - If the style file contains a "Signature Decorative Elements" section, prioritize using these elements to enhance identity
- Inject the content into the skeleton, generate the complete HTML, and save it to
/tmp/elegant_image_<timestamp>.htmlusing thewritetool (the tool name iswrite, notwrite_to_file)
Footer Handling Rules (Important):
- User has not specified author info: Write the default value into the
.footerelement in the HTML:<skill name> @ <current model name>- Example:
text-to-elegant-image @ claude-4.6-sonnet
- Example:
- User has specified author info (e.g., "Author: John Doe"): Write the user-specified text.
- User explicitly says no footer: Do not generate the
.footerelement in the HTML; append--no-footerto 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 usage | Alternative |
|---|---|
| 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 symbols | Delete, or use style-specific signature decorative elements (leaves/stars/seals, etc.) |
| Progress/arrows | Use 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):
- The output path explicitly passed in the command
- The environment variable
T2EI_OUTPUT_DIR - Default value:
./output(theoutput/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"' >> ~/.bashrcDo not ask again afterward.
Footer Parameter Explanation:
| Parameter | Effect |
|---|---|
| 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-footer | Completely 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.jscan 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 theT2EI_OUTPUT_DIRenvironment variable, see Step 5).
Script List
| Script | Purpose |
|---|---|
scripts/setup.sh | Dependency check (Node/Chrome/puppeteer-core); prompts and installs if puppeteer-core is missing (output visible) |
scripts/check_emoji.py | Emoji check before screenshot; outputs character and line number on FAIL |
scripts/export_image.js | Puppeteer screenshot export: font waiting + precise height cropping + uniform frame margin + card background toggle (--flat) + footer injection/removal |