# Quick start

Normalize your first formula, pick a profile, and look at the document tree underneath — in 10 minutes.

https://texform.dev/docs/quick-start

This walks the core TeXForm path in about ten minutes: normalize a formula, choose the profile that controls how aggressive normalization is, and look at the document tree that sits underneath. Every step shows the output and one line on what just happened.

## Install [#install]

Install TeXForm for your language. See [Installation](https://texform.dev/docs/installation) for supported versions and verification.

**Python**

```bash
pip install texform
```

**JavaScript**

```bash
npm install texform
```

**Rust**

```bash
cargo add texform
```

## Normalize your first formula [#normalize-your-first-formula]

Build a `TransformEngine` with the `corpus` profile and normalize a `physics`-package derivative. `physics` is not in the default package set, so the engine gets a knowledge base that names the packages it loads. The convenience macro `\dv{f}{x}` expands into the universal `\frac` form that renders on any plain MathJax or KaTeX deployment.

**Python**

```python
import texform

kb = texform.KnowledgeBase(packages=["base", "ams", "physics"])
engine = texform.TransformEngine(profile="corpus", knowledge_base=kb)
print(engine.normalize(r"\dv{f}{x}"))
```

```text
\frac { \mathrm { d } f } { \mathrm { d } x }
```

**JavaScript**

```js
import { KnowledgeBase, TransformEngine } from 'texform';

const knowledgeBase = new KnowledgeBase({ packages: ['base', 'ams', 'physics'] });
const engine = new TransformEngine({ profile: 'corpus', knowledgeBase });
console.log(engine.normalize('\\dv{f}{x}'));
```

```text
\frac { \mathrm { d } f } { \mathrm { d } x }
```

**Rust**

```rust
use texform::{KnowledgeBase, Profile, TransformEngine};

let kb = KnowledgeBase::builder().packages(&["base", "ams", "physics"]).build()?;
let engine = TransformEngine::builder()
    .knowledge_base(kb)
    .profile(Profile::Corpus)
    .build()?;
let result = engine.normalize(r"\dv{f}{x}")?;
println!("{}", result);
```

```text
\frac { \mathrm { d } f } { \mathrm { d } x }
```

What just happened: the engine parsed `\dv{f}{x}`, recognized it as a `physics` derivative macro, and rewrote it into a form that no longer depends on the `physics` package. The default serialized style is spaced, which is why braces and operators are separated.

## Pick a profile [#pick-a-profile]

The profile is the core decision: it names your downstream use and selects how far normalization goes. Run the same input through the `authoring` profile and compare.

**Python**

```python
import texform

kb = texform.KnowledgeBase(packages=["base", "ams", "physics"])
corpus = texform.TransformEngine(profile="corpus", knowledge_base=kb)
authoring = texform.TransformEngine(profile="authoring", knowledge_base=kb)
print(corpus.normalize(r"\dv{f}{x}"))
print(authoring.normalize(r"\dv{f}{x}"))
```

```text
\frac { \mathrm { d } f } { \mathrm { d } x }
\dv { f } { x }
```

**JavaScript**

```js
import { KnowledgeBase, TransformEngine } from 'texform';

const knowledgeBase = new KnowledgeBase({ packages: ['base', 'ams', 'physics'] });
const corpus = new TransformEngine({ profile: 'corpus', knowledgeBase });
const authoring = new TransformEngine({ profile: 'authoring', knowledgeBase });
console.log(corpus.normalize('\\dv{f}{x}'));
console.log(authoring.normalize('\\dv{f}{x}'));
```

```text
\frac { \mathrm { d } f } { \mathrm { d } x }
\dv { f } { x }
```

**Rust**

```rust
use texform::{KnowledgeBase, Profile, TransformEngine};

let kb = KnowledgeBase::builder().packages(&["base", "ams", "physics"]).build()?;
let corpus = TransformEngine::builder().knowledge_base(kb.clone()).profile(Profile::Corpus).build()?;
let authoring = TransformEngine::builder().knowledge_base(kb).profile(Profile::Authoring).build()?;
println!("{}", corpus.normalize(r"\dv{f}{x}")?);
println!("{}", authoring.normalize(r"\dv{f}{x}")?);
```

```text
\frac { \mathrm { d } f } { \mathrm { d } x }
\dv { f } { x }
```

What just happened: `corpus` expanded the macro because a training corpus should not depend on the `physics` package, while `authoring` kept the author's shorthand. Same input, different target, different output — no profile is "better", only fitter for a downstream use. The four profiles and the rules behind them are covered in [Transforms](https://texform.dev/docs/transforms).

## Look under the hood [#look-under-the-hood]

Beneath `normalize` there is a tree you can use any time. Parse a formula directly, check that the parse is clean, and serialize it back to LaTeX.

**Python**

```python
import texform

result = texform.Parser().parse(r"\frac{x}{y}")
document = result["document"]
print(document.has_errors())
print(document.to_latex())
```

```text
False
\frac { x } { y }
```

**JavaScript**

```js
import { Parser } from 'texform';

const result = new Parser().parse('\\frac{x}{y}');
const document = result.document;
console.log(document.hasErrors());
console.log(document.toLatex());
```

```text
false
\frac { x } { y }
```

**Rust**

```rust
use texform::Parser;

let parser = Parser::builder().build()?;
let parsed = parser.parse(r"\frac{x}{y}");
if let Some(document) = parsed.document() {
    println!("{}", document.has_errors());
    println!("{}", document.to_latex()?);
}
```

```text
false
\frac { x } { y }
```

What just happened: `parse` returned a `Document` — the editable working tree. `has_errors()` confirms the parse is complete (a tree with holes would be read-only and could not be normalized), and `to_latex()` serializes it back. Normalization is this same tree with a rule pipeline applied; you can also walk and edit it directly.

- [Try in Playground](https://play.texform.dev) — Run this flow in the browser, no install needed.

- [Concepts: Transforms](https://texform.dev/docs/transforms) — The four profiles and the multi-phase pipeline behind normalization.

- [Guide: Normalize a corpus](https://texform.dev/docs/normalize-a-corpus) — Run one reused engine over a whole dataset.

