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

推荐订阅源

WordPress大学
WordPress大学
A
About on SuperTechFans
量子位
B
Blog RSS Feed
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园_首页
MongoDB | Blog
MongoDB | Blog
小众软件
小众软件
Blog — PlanetScale
Blog — PlanetScale
Microsoft Azure Blog
Microsoft Azure Blog
V
V2EX
Google DeepMind News
Google DeepMind News
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
H
Hackread – Cybersecurity News, Data Breaches, AI and More
G
Google Developers Blog
U
Unit 42
D
DataBreaches.Net
博客园 - Franky
D
Docker
宝玉的分享
宝玉的分享
Y
Y Combinator Blog
月光博客
月光博客
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Hugging Face - Blog
Hugging Face - 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
I forked MathLive to make basic chemistry formulas less a...
Kyle · 2026-05-22 · via DEV Community

I recently published a small MathLive fork:

GitHub:

https://github.com/LatoAndroid/mathlive-chemistry

npm:

https://www.npmjs.com/package/mathlive-chemistry

It is not the official MathLive package. It is a focused fork of arnog/mathlive that adds a bit of chemistry support:

  1. better editing behavior for common \ce{...} formulas;
  2. a small \chemfig{...} subset for simple organic structures.

Most of the coding for this fork was done with AI coding assistance. Not in the "one prompt and ship it" way. I set the scope, read the existing code, pushed back on bad changes, checked the rendering details, and used AI mostly as the implementation/debugging partner. That worked well for this kind of fork because the important part was not inventing a new architecture, but keeping the changes small and compatible.

The goal is not to build a professional chemistry editor. It is more boring than that: make common chemistry notation behave reasonably inside a MathLive-based formula editor.

Why I forked it

MathLive already does the hard parts of math editing well: rendering, selection, serialization, keyboard input, virtual keyboard support, and so on.

Chemistry is the rough edge.

Upstream MathLive already supports part of mhchem:

\ce{2H2 + O2 -> 2H2O}
\ce{CaCO3 ->[heat] CaO + CO2 ^}
\ce{SO4^2- + Ba^2+ -> BaSO4 v}

Enter fullscreen mode Exit fullscreen mode

But \ce{...} is mostly display-oriented. Internally it is represented by ChemAtom. The rough flow is:

\ce{...}
  -> read the argument as a balanced string
  -> parse it with the mhchem parser
  -> texify it into normal TeX
  -> parseLatex(tex)
  -> render through MathLive

Enter fullscreen mode Exit fullscreen mode

That is a good design for display. It preserves the original \ce{...} source and avoids guessing too much.

The problem is editing. In some cases the formula still behaves too much like one captured object instead of something that can participate naturally in MathLive editing.

What I changed for ChemAtom

I did not make every \ce editable. That would be unsafe. mhchem accepts a lot of syntax, and it can contain embedded TeX. If the fork tries to normalize all of that, it will eventually damage somebody's input.

So the editable path is intentionally narrow:

  • only \ce, not \pu;
  • skip empty or very long arguments;
  • skip arguments containing \, $, or &;
  • inspect the mhchem parser output and allow only known simple output types.

The check is roughly:

function isEditableChemFormula(command, arg, parsed) {
  if (command !== '\\ce') return false;
  if (!arg || arg.length > 512) return false;
  if (/[\\$&]/.test(arg)) return false;
  return isEditableChemOutput(parsed);
}

Enter fullscreen mode Exit fullscreen mode

For the editable subset, captureSelection is disabled so the generated MathLive body can be selected and edited recursively.

Serialization is the other important part. The atom does not just keep returning the original string. It serializes the current body, runs a small normalization step, then wraps it back into:

\ce{...}

Enter fullscreen mode Exit fullscreen mode

For example, a test changes the internal body from:

\ce{2H2 + O2 -> 2H2O}

Enter fullscreen mode Exit fullscreen mode

to something like:

3\mathrm{H}_{2}+\mathrm{O}_{2}\longrightarrow2\mathrm{H}_{2}\mathrm{O}

Enter fullscreen mode Exit fullscreen mode

and gets this back:

\ce{3H2+O2 -> 2H2O}

Enter fullscreen mode Exit fullscreen mode

It is not trying to preserve every space. It is trying to preserve a valid editable chemistry formula.

The chemfig part

MathLive does not support \chemfig upstream. A command like this is unknown:

\chemfig{*6(-=-=-=)}

Enter fullscreen mode Exit fullscreen mode

Full chemfig support would be a much bigger project. I only needed a few common structures:

\chemfig{CH_3-CH_2-OH}
\chemfig{CH_2=CH_2}
\chemfig{HC#CH}
\chemfig{CH_3-C(=O)-OH}
\chemfig{*6(-=-=-=)}
\chemfig{*6(-=-(-CH_3)-=-)}
\chemfig{*6(-=-(-NO_2)-=-)}
\chemfig{*6(-=-(-COOH)-=-)}

Enter fullscreen mode Exit fullscreen mode

So this fork uses a small parser instead of a full chemfig implementation:

  • parseLinear() for simple chains and single/double/triple bonds;
  • parseRing() for a six-membered ring with simple substituents.

The result is rendered as SVG and then wrapped in a MathLive Box:

\chemfig{...}
  -> parseChemfig()
  -> ChemfigStructure
  -> SVG
  -> Box(width / height / depth)
  -> inline MathLive rendering

Enter fullscreen mode Exit fullscreen mode

This is not the most elegant thing in the world, but it keeps the change local. I did not want to rework MathLive's layout model just for a small chemistry subset.

Right now \chemfig{...} is still an object-level atom for editing. It renders, selects, deletes, and serializes. It is not a visual structure editor.

Install

npm install mathlive-chemistry

Enter fullscreen mode Exit fullscreen mode

Usage stays close to MathLive:

import 'mathlive-chemistry';

Enter fullscreen mode Exit fullscreen mode

or:

import { MathfieldElement } from 'mathlive-chemistry';

Enter fullscreen mode Exit fullscreen mode

What this is not

This fork is not:

  • official MathLive;
  • a full mhchem implementation;
  • a full chemfig implementation;
  • a professional chemistry drawing tool.

It does not handle advanced stereochemistry, wedge/dashed bonds, mechanism arrows, electron pushing, or complex research-grade structures.

Complex \ce{...} and \pu{...} still stay conservative and behave as whole objects. That is intentional.

Relationship to MathLive

Original project:

https://github.com/arnog/mathlive

This fork:

https://github.com/LatoAndroid/mathlive-chemistry

The original project is by Arno Gourdol and MathLive contributors, under the MIT license. This fork keeps the same license.

There is still plenty to polish, especially around spacing, baselines, and the exact chemfig subset. Those tiny layout details are annoying: a one-pixel difference can look fine in isolation and wrong inside a formula.

If you are using MathLive and have real chemistry examples that fail, feel free to open an issue:

https://github.com/LatoAndroid/mathlive-chemistry/issues