Raphael Publish: a Markdown typesetting engine for WeChat public accounts
Raphael Publish - 公众号排版大师 | 现代 Markdown 排版引擎
At a glance
- What is it?
- Raphael Publish is a browser based Markdown formatting tool aimed at people who publish to WeChat public accounts, where pasted rich text, external images and collapsing tables are the usual problems. It runs entirely in the client on React, TypeScript and Vite, and the repository was last pushed to on 2026-04-05 with no tagged releases.
- Who is it for?
- Raphael Publish fits an author who writes in Markdown and publishes to a WeChat public account, because the two things that break on that platform, third party image hosting and collapsing tables, are exactly what its copy pipeline handles. It is the wrong tool for multi author editing, versioned content or anyone who needs a server side workflow, since the whole application is a client side static build.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Activity is slowing. The repository last received commits 6 months ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Magic paste cleans rich text from Feishu, Notion or Word
The first feature the project leads with is paste handling. Rich text copied from Feishu, Notion, Word or any ordinary web page is sanitised into clean Markdown at the moment it is pasted, so the author never types Markdown syntax by hand. The conversion is done by turndown, with turndown-plugin-gfm in the dependency list, which is the plugin that adds GitHub flavoured Markdown behaviour to turndown output.
Images get their own path. Pasting a screenshot or an image directly with Ctrl or Cmd plus V inserts the Markdown image syntax for you, so a figure pasted out of a chat window lands in the document as an image reference rather than as a stray base64 blob or a broken link.
The trade-off is that the sanitising is lossy in a way the author cannot see. A paste that carries styling, tables with merged cells or embedded widgets will be flattened into whatever turndown can express, and the document looks different from the source once it lands. The engine is tuned for text-first content, which is why the theme system has to supply the visual weight the source document had.
External images are inlined as Base64 before the copy
The reason this project exists at all is a specific platform behaviour. A WeChat public account that references an image hosted elsewhere shows a warning that the image comes from a third party, and the image may fail to display. Raphael Publish solves that at the moment of copying.
When you press the copy to public account button, every external image is converted to Base64 and inlined into the HTML, so the pasted content carries the image data with it and no external request is needed. Background colours, rounded corners and spacing are carried across at the same time, which is the part that decides whether the result looks like the preview or like a plain document.
The cost is size. Base64 inflates the payload, and WeChat articles are not an unlimited transport, so an article with many full width screenshots will produce a very large clipboard payload. The project does not publish a size limit or a compression step, and the same conversion is what makes PDF export possible, so the behaviour is consistent across the two output paths rather than being a special case for the clipboard.
wechatCompat rebuilds lists and tables at the DOM level
The second platform specific problem is layout. HTML lists and tables written for a browser tend to collapse or misalign inside a WeChat article, because the editor sanitises and restructures what it receives. The project handles this with an engine it calls wechatCompat, which reshapes lists and tables in the underlying DOM before the content is copied, so the structure survives the trip into the editor.
The same engine is used for the multi image layout, where several images are placed side by side in a grid, with the stated goal that the grid is not broken apart when the article is rendered on a phone. That is a different problem from the one a CSS media query solves, because the width available inside a WeChat article is not the width of the browser you previewed in.
The practical implication for an author is that the preview is a guide rather than a guarantee, since the real test happens after pasting into the WeChat editor. The wechatCompat engine narrows the gap, but the README does not describe how it detects the target width or what it does with nested tables, so edge cases are worth checking by hand on a first article.
Thirty themes and three preview widths
The theme library holds thirty visual styles, grouped into three collections: classic, trend and additional styles. Among the named ones are a clean white Mac look, an oat colour theme, a WeChat native style, designs modelled on the New York Times, Medium and Stripe, an efficiency blue one, a dark night theme, a retro parchment, a Bloomberg terminal look, Notion, GitHub, Dracula, Nord, Monokai, Solarized, Cyberpunk, Bauhaus and a rainbow candy palette, among others.
Each theme is a separate design rather than a recolouring, and the differences are applied across background colour, fonts, headings, code blocks, quotes and tables, so switching themes changes the character of the document instead of its colour scheme alone. The theme names that are brand and tool names carry a trademark and taste question that the project does not discuss, so a commercial publication should treat those as inspiration rather than as a drop-in identity.
Previewing happens in the browser at three widths: a phone view at 480px, a tablet view at 768px, and a desktop view. The 480px viewport is the one that matters for WeChat, and it is the setting you will want to leave on while writing.
Export to PDF or HTML through html2pdf.js
Beyond copying into the editor, the tool can export the document as a PDF or as an HTML file, which the project positions for archiving, emailing and web publishing. The PDF path goes through html2pdf.js, with type definitions for it in the development dependencies.
Export goes through the same rendering pipeline as the preview, so the PDF is a snapshot of the styled document rather than a plain text dump, which makes it useful as a record of what was published. The HTML export serves the other purpose, giving you a file you can host or hand to someone else.
The difference between the two exports and the clipboard path is worth keeping in mind. The clipboard path is where the WeChat specific work happens, with images inlined and lists and tables restructured. An exported HTML file is a faithful copy of the styled document, and an exported PDF is a fixed layout of it, so neither carries the WeChat compatibility work into the WeChat editor. If your workflow is to publish a file rather than paste into the editor, this project is doing more for you than the name suggests.
Running the app with pnpm, and the scripts that back it
The project is a client side application with no server component, and the local workflow uses pnpm.
pnpm install
pnpm devThe build is a single command, and the production output lands in a dist directory that can be deployed to GitHub Pages or any static hosting service.
pnpm buildpackage.json defines the scripts behind those commands, and the build script is worth reading because it does more than bundle.
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"test": "vitest run",
"test:watch": "vitest",
"test:e2e": "playwright test",
"lint": "eslint .",
"preview": "vite preview"
},Type checking runs before the bundler, so a type error fails the build rather than reaching production. The testing story has two layers: vitest for unit tests and Playwright for end to end tests, with playwright.config.ts at the root and an e2e directory. The styling side uses Tailwind CSS 3 with a tailwind.config.js and a postcss.config.js, and the animation work is done with framer-motion.
A last push on 2026-04-05 with no release tags
The repository has no GitHub releases, and the last push was on 2026-04-05. The current version in package.json is 1.0.0, and the package is marked private, which means the npm registry is not the distribution channel here. The intended delivery is the hosted site at publish.raphael.app or a static build you host yourself.
The licence is MIT, so the code can be reused and modified in commercial work, including for a fork with your own brand and theme set. That matters for a tool in this category, because the usual reason to self host a WeChat formatting tool is to replace the themes and the branding with your own.
The stack is React 18 with TypeScript, Vite 5, Tailwind CSS 3, markdown-it for parsing, highlight.js for code highlighting, turndown for the paste conversion, html2pdf.js for export and framer-motion for animation. TypeScript is pinned at roughly 5.6 and the ESLint setup is the flat config generation with typescript-eslint and the React hooks and refresh plugins. With no tagged releases to diff against, treat the commit history in the repository as the record of what changed.
Editorial conclusion
Raphael Publish fits an author who writes in Markdown and publishes to a WeChat public account, because the two things that break on that platform, third party image hosting and collapsing tables, are exactly what its copy pipeline handles. It is the wrong tool for multi author editing, versioned content or anyone who needs a server side workflow, since the whole application is a client side static build. Before you rely on it, check that the repository state you clone still matches what publish.raphael.app serves, because the last push was on 2026-04-05 and the project publishes no releases to compare against.
Frequently asked questions
How do I run Raphael Publish locally?
The project uses pnpm, so run pnpm install and then pnpm dev to start the Vite development server. A production build is produced by pnpm build and lands in a dist directory for static hosting.
How does Raphael Publish avoid third party image errors on WeChat?
When you use the copy to public account button, every external image is converted to Base64 and inlined into the content, so nothing has to be loaded from another host. Background colours, rounded corners and spacing are carried across at the same time.
How many themes does Raphael Publish include?
Thirty visual themes, grouped into classic, trend and additional styles, with each one designed separately across background, fonts, headings, code blocks, quotes and tables. Preview widths are 480px for phone, 768px for tablet and a desktop view.
What licence is Raphael Publish released under?
The repository is under the MIT licence, and package.json marks the project as private at version 1.0.0 with no published GitHub releases. The last push to the repository was on 2026-04-05.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/liuxiaopai-ai-raphael-publish)Was this useful?