跪拜 Guibai
← Back to the summary

Motie Turns Markdown Into WeChat-Ready HTML With Inline Styles, Not Preview Polish

Moving Markdown Documents to WeChat Official Accounts with TRAE

Competition track: Full-chain development in practice

Topic direction: Improving real work scenarios — development and iteration of a Markdown WeChat Official Account typesetting tool

Technical articles flow nicely in Markdown, but moving them to WeChat Official Account often means formatting them again: heading levels need adjusting, code needs highlighting, local images may not carry over, and long tables on mobile can break out of the body.

I wanted to turn this repetitive task into a small tool: paste Markdown, check the preview, click copy, then paste into the WeChat Official Account body editor. It’s called Motie (墨贴), and it’s currently a pure static web page.

This is an actual iteration round on an existing project. I used the new version of TRAE to adjust styles and modify features, continuing to improve the tool around problems encountered in real articles. Below, I expand on requirements, key decisions, bug fixes, and delivery results.

image.png

First, narrow the goal down to one article that works

The initial description was “convert Markdown into a format WeChat Official Accounts recognizes.” Once broken down, what needed to be delivered was a formatted HTML rich text.

I scoped it to one workflow: input an existing technical article, handle headings, code, images, lists, and tables, check mobile width, then copy to WeChat. Account login, asset upload, and auto-publishing are done on the platform; the web page itself can be tried as soon as it opens.

The interface also converged around this goal: the editor and preview areas take up the main space, copy is at the top, and typesetting options are in the sidebar. The default primary color is now #1c8feb; captions, outline, and paragraph spacing were all added around long-article editing.

While requirements were being repeatedly adjusted, I found that “make it a bit nicer” is hard to accept. Replacing it with “the preview shows no scrollbar but the full text is still readable” and “images paste at the cursor” makes the result clear to check. When using AI to modify a project, write constraints concretely; only then do you know where to verify later.

image.png

image.png

Preview and copy use the same content

Typesetting tools tend to spend effort on preview styling, but what readers ultimately use is the content pasted into WeChat.

If code colors come only from the page’s own CSS, or headings depend on a class, the copy may fail once it leaves this page. Therefore, Motie organizes the conversion result into inline styles, and the same HTML is used for preview, rich-text copy, and standalone file export.

The processing flow is:

Markdown
  → Marked parsing
  → DOMPurify sanitizes untrusted HTML
  → handle code, images, lists, and reference links
  → write inline styles
  → preview / copy / export

Marked, DOMPurify, highlight.js, and Lucide are all bundled with the project, so opening the page doesn’t require temporary CDN requests. Styles for headings, blockquotes, tables, and code markers are written onto the elements, and the copied body is not locked to a certain pixel width.

This reduces the output’s dependence on the original page environment, but the target editor may still adjust styles, so later you need to check the tool output and the WeChat paste result separately.

One paste is what really exposes problems

In actual trial use, several problems appeared that affect usage more than color scheme: parameters in code were split across lines, indentation was messed up, task-list checkbox markers and text were split into two paragraphs, and some reference URLs were duplicated and concatenated.

These reports happened after pasting into WeChat; the tool preview itself might not reproduce them. So fixes had to look at the output structure.

Code can’t rely on white-space alone

Setting only white-space: pre-wrap may not make the target editor preserve the same effect when processing HTML. Currently, code blocks use explicit <br> to preserve source line breaks, non-breaking spaces to preserve spaces, and tabs display as two columns; highlighted parameter fragments remain inline.

For example, in the original code below, parameters, indentation, and blank lines all need to be preserved:

async function fetchUsers(page, { active = true, pageSize = 20 } = {}) {
  const params = { page, active, pageSize };

  return request('/api/users', { params });
}

When mobile width is insufficient, long code wrapping naturally is allowed; splitting parameters into new body paragraphs is an error to avoid. The plain-text clipboard separately preserves the original code, including tabs from the source file.

Checkbox markers and item text must be in the same paragraph

Task lists also got structural adjustments: ☑ / ☐ are placed directly into the paragraph where the item text is. When encountering old content already split into “one paragraph for the symbol, one for the text,” only the symbol and the first sentence are merged; subsequent explanatory paragraphs remain.

Reference links got a focused fix for the duplication: bare URLs no longer display as “URL:URL”; already-written [1], [2] sources keep their original numbering. Long addresses can wrap naturally with the body, but the numbering and link are not artificially split into multiple paragraphs.

The project organized these inputs into a WeChat paste regression sample. Future modifications can reuse the same article repeatedly to compare original, preview, and WeChat results. Currently the related structural tests pass; the actual WeChat effect after fixes still needs retesting.

image.png

image.png

Double scrollbars: a very visible interaction problem

The preview area also had two vertical scrollbars, inner and outer. The scroll wheel sometimes scrolled inside the article and sometimes outside, which is awkward when reading long articles.

When fixing it, I first dealt with the scroll container: the article was changed to display directly in the outer preview canvas, the nested iframe viewport was removed, the body expands naturally, and the outer layer uniformly handles vertical scrolling.

After that, another layer of visual adjustment was made: the preview doesn’t show scrollbars, but wheel, touch, and keyboard can still read. Long code with auto-wrap off can still be viewed horizontally, and the sidebar outline and top back button provide positioning entry points.

The mobile and desktop preview width caps are 375px and 680px respectively, shrinking automatically when the panel isn’t wide enough. This simulates the body reading width; in the end, you still have to look at WeChat’s own mobile preview.

This adjustment reminded me that the description of a UI problem and the implementation layer need to match. For double scrollbars, first check the layout and scroll container; after determining the scroll area, then handle whether the scrollbar is visible.

After pasting an image, things aren’t over

Writing technical articles often requires adding a screenshot, so now you can paste an image directly at the cursor in the editor, or choose a file or drag in PNG, JPG, WebP, GIF. After insertion, a Markdown image reference is generated, and the preview uses the current page’s resource mapping.

In the original draft, ./images/a.png is only a path; the web page won’t automatically read a computer file based on this text. Image management provides one-by-one replacement: choose a local original image, or fill in a complete HTTP / HTTPS address.

There are two limitations you should know in advance.

First, local images are currently kept only in the current page’s memory. Saving a draft or downloading Markdown won’t package the images; when you need a backup with images before refreshing, you should export HTML or save the originals separately.

Second, an image displaying successfully in the tool doesn’t mean WeChat has received it. External links may have anti-leeching, and embedded data: images may also be rejected. After pasting, you still need to check each one; if images are missing, upload the originals in WeChat.

Therefore, this tool’s one-click copy solves the preparation of typeset content; whether images are accepted depends on the actual WeChat result.

How to verify the delivered result

The current version is 1.1.0. The source has been pushed to GitHub, and the GitHub Pages address is accessible. When verified on October 22, 2026, the online entry point and core scripts/styles all returned HTTP 200 and matched the local delivery files.

The local test record is 44 passing: 26 conversion tests and 18 UI logic tests. These include code line breaks and indentation, task lists, reference links, image insertion, dangerous content sanitization, paragraph spacing, caption toggles, and outline positioning.

Tests also check a timing that is easy to miss: the editor has 200ms debounce. If a user copies immediately after typing, the button should refresh the conversion result first, then read the current body.

These verifications have boundaries. UI tests use jsdom, and the clipboard uses an interface stand-in; online resources being accessible doesn’t mean real browser layout and the WeChat editor have been accepted. For now, you should still check the paste effect in a real account draft, then send a WeChat mobile preview.

To run it yourself, open the project’s index.html directly; with a Node.js environment, run this in the project directory:

npm start

When you need to modify code and reproduce tests, run:

npm ci
npm run check
npm test

The development workflow left by this iteration

Compared to writing a certain amount of code at once, I prefer to keep this workflow: take a real article to propose requirements, continue modifying with concrete anomalies, preserve problem inputs, use the same result for preview, copy, and export, and finally check on the target platform.

TRAE participated in style adjustments and feature modifications in this practice. For me, the part worth continuing to use is turning a “looks about right” requirement step by step into changes that can be rechecked: what was wrong, what changed, and what input to check again. Specific conversations and code diffs should be viewed together with real operation screens.

There are already many mature Markdown typesetting tools. Motie’s value lies in repeatedly dealing with those small, specific annoyances around one’s own articles, and leaving a result that can be opened, used, and further modified.