typed-smiles renders SMILES strings as clean 2D molecular diagrams in Typst.
It uses a small Rust/WASM plugin for parsing and layout, then draws the result
with CeTZ.
The package is meant for chemistry notes, reaction schemes, reports, and teaching material where you want molecules to live directly in your Typst source instead of copying diagrams from a separate editor.
Basic molecule drawing
Start by importing smiles. Pass a SMILES string and the package will draw the
skeletal structure.
#import "@preview/typed-smiles:0.1.0": smiles
#grid(
columns: (1fr, 1fr, 1fr, 1fr),
gutter: 1.2em,
align: center,
[*Ethanol* \ #text(size: 8pt, `CCO`) \ #smiles("CCO")],
[*Alanine* \ #text(size: 8pt, `CC(N)C(=O)O`) \ #smiles("CC(N)C(=O)O")],
[*Chlorobenzene* \ #text(size: 8pt, `ClC1=CC=CC=C1`) \ #smiles("ClC1=CC=CC=C1")],
[*Furan* \ #text(size: 8pt, `C1=CC=CO1`) \ #smiles("C1=CC=CO1")],
)

Scaling
Use bond-length to scale diagrams. The scale is uniform, so the molecule keeps
its aspect ratio. Here is the same molecule drawn at three sizes:
#grid(
columns: (1fr, 1fr, 1fr),
gutter: 1.2em,
align: center,
[*Small* \ #text(size: 8pt, `bond-length: 0.8`) \
#smiles("C1=CC=CC=C1", bond-length: 0.8)],
[*Default* \ #text(size: 8pt, `bond-length: 1.0`) \
#smiles("C1=CC=CC=C1")],
[*Large* \ #text(size: 8pt, `bond-length: 1.4`) \
#smiles("C1=CC=CC=C1", bond-length: 1.4)],
)

Chemical formulas and equations
typed-smiles re-exports ce from chemformula, so the same import can handle
ordinary formulas and text-based chemical equations. This is useful for salts,
small inorganic species, conditions, and equations where a full molecular
diagram would be unnecessary.
#import "@preview/typed-smiles:0.1.0": ce
#grid(
columns: (1fr, 1fr),
gutter: 1.2em,
row-gutter: 1em,
align: center,
[*Formula* \ #text(size: 8pt, `H2SO4`) \ #ce("H2SO4")],
[*Ions* \ #text(size: 8pt, `(NH4)2SO4`) \ #ce("(NH4)2SO4")],
[*Combustion* \ #text(size: 8pt, `CH4 + 2O2 -> CO2 + 2H2O`) \
#ce("CH4 + 2O2 -> CO2 + 2H2O")],
[*Equilibrium* \ #text(size: 8pt, `N2 + 3H2 <=> 2NH3`) \
#ce("N2 + 3H2 <=> 2NH3")],
)

Reaction schemes
For structural reaction schemes, use reaction, rxn-arrow, and mol. These
helpers let you combine SMILES-based molecule diagrams with ce() formulas,
plus signs, labels, and arrow conditions in one layout.
#import "@preview/typed-smiles:0.1.0": smiles, ce, rxn-arrow, mol, reaction
#reaction(
mol(smiles("CC(=O)O"), label: text(size: 8pt)[acetic acid]),
[+],
mol(smiles("CCO"), label: text(size: 8pt)[ethanol]),
rxn-arrow(above: ce("H+"), below: [heat]),
mol(smiles("CCOC(=O)C"), label: text(size: 8pt)[ethyl acetate]),
[+],
ce("H2O"),
)
#reaction(
mol(smiles("C1=CC=CC=C1"), label: text(size: 8pt)[benzene]),
rxn-arrow(above: ce("Br2"), below: ce("FeBr3")),
mol(smiles("BrC1=CC=CC=C1"), label: text(size: 8pt)[bromobenzene]),
)

Multi-step mechanisms
Reaction arrows can point right, left, up, or down. This lets you write compact wrap-around schemes without manually placing every molecule.
#reaction(
mol(smiles("C1=CC=CC=C1"), label: text(size: 8pt)[1]),
rxn-arrow(above: ce("Br2"), below: ce("FeBr3")),
mol(smiles("BrC1=CC=CC=C1"), label: text(size: 8pt)[A]),
rxn-arrow(dir: "down", above: ce("HNO3"), below: ce("H2SO4")),
mol(smiles("BrC1=CC(=CC=C1)[N+](=O)[O-]"), label: text(size: 8pt)[B]),
rxn-arrow(dir: "left", above: ce("Fe"), below: ce("HCl")),
mol(smiles("BrC1=CC(=CC=C1)N"), label: text(size: 8pt)[C]),
)

Wedges, dashed bonds, and hydrogens
Use / for a solid wedge and \ for a hashed wedge. By default, carbon
hydrogens stay implicit, but show-h: true displays computed implicit
hydrogens. Explicit bracket hydrogens, such as [NH4+], are always shown.
#grid(
columns: (1fr, 1fr, 1fr, 1fr),
gutter: 1.2em,
align: center,
[*Solid wedge* \ #text(size: 8pt, `C/N`) \ #smiles("C/N")],
[*Hashed wedge* \ #text(size: 8pt, `C\N`) \ #smiles("C\\N")],
[*Implicit H* \ #text(size: 8pt, `CCO`) \ #smiles("CCO", show-h: true)],
[*Explicit H* \ #text(size: 8pt, `[NH4+]`) \ #smiles("[NH4+]")],
)

API
#smiles(smiles-str, bond-length, atom-font-size, color, rotation, show-h)
Renders a SMILES string as a 2D skeletal molecular diagram.
| Parameter | Type | Default | Description |
|---|---|---|---|
smiles-str |
str |
required | OpenSMILES string |
bond-length |
float |
1.0 |
Uniform bond length scale factor; 1.0 equals 30pt per bond |
atom-font-size |
length |
11pt |
Atom label font size |
color |
bool |
true |
Apply Jmol CPK atom colors |
rotation |
angle |
0deg |
Rotate the molecule while keeping atom labels upright |
show-h |
bool |
false |
Show computed implicit hydrogens |
#display-smiles is an alias for #smiles.
#rxn-arrow(above, below, dir)
Creates an arrow for #reaction.
| Parameter | Type | Default | Description |
|---|---|---|---|
above |
content |
none |
Label above a horizontal arrow, or right of a vertical arrow |
below |
content |
none |
Label below a horizontal arrow, or left of a vertical arrow |
dir |
str |
"right" |
One of "right", "left", "down", or "up" |
#mol(content, label: none)
Wraps a molecule or formula with an optional centered label below it.
#reaction(gap-h, gap-v, ..items)
Lays out molecules, formulas, plus signs, and rxn-arrow values in a reaction
scheme. Directional arrows move the placement cursor, so multi-line schemes can
be written as a single sequence.
SMILES support
The package uses the smiles-parser
crate for parsing.
Current limitations:
- Aromatic lowercase atoms are not parsed by
smiles-parser0.4. Use Kekule forms such asC1=CC=CC=C1instead ofc1ccccc1. - Directional
/and\bonds are rendered as wedge/hash bonds, but the package does not yet perform full stereochemical interpretation. - Bridged bicyclics may have atom overlap; template matching is not implemented.
- Implicit hydrogen counts use a simple standard-valence model.
Architecture
SMILES string -> Rust WASM plugin -> JSON layout -> CeTZ drawing in Typst
The published package bundles the compiled WebAssembly plugin, so documents can
use typed-smiles directly through Typst’s package import. The plugin handles
SMILES parsing and 2D coordinates; the Typst layer is a thin renderer plus
reaction-scheme helpers.
License
MIT