ODEROM

Oriented Differential Exterior calculus for Relativity, Operators and Manifolds
In the browser · a short guide
Rafael Camargo Rodrigues de Lima
UDESC — Universidade do Estado de Santa Catarina
rafael.lima@udesc.br
oderom.pages.dev · nothing to install · 20 August 2026

Contents

  1. What this is, and what you do not need
  2. One minute: your first curvature
  3. The notebook
  4. Choosing your language
  5. Starting from the gallery
  6. Writing your own metric
  7. What you can ask for
  8. Getting results out
  9. The other half: abstract indices
  10. Saving and reopening
  11. When a calculation takes too long
  12. What is different from the desktop version
  13. Going further

1. What this is, and what you do not need

oderom.pages.dev computes curvature. Give it a manifold, a coordinate chart and a metric, and it returns Christoffel symbols, the Riemann and Ricci tensors, and invariant scalars — in closed form, as algebra, with no numerical approximation anywhere.

You need a browser. That is the whole list. No download, no installer, no account, no administrator rights, no Python, no LaTeX installation. It works the same in a university lab, on a borrowed laptop, and on a machine where you are not allowed to install anything.

The computation runs on your machine. The engine is compiled to WebAssembly and executes inside your own browser tab. Nothing you type is sent to a server; there is no account, no upload, and nothing to leak. The consequence is that speed depends on your machine, and that closing the tab loses whatever you have not saved.

2. One minute: your first curvature

Open the page. It arrives with an example already loaded — the Reissner–Nordström metric, a charged black hole — in four blocks, none of them executed:

manifold M dim 4
bundle TM on M dim 4

chart schw on M coords (t, r, theta, phi)

metric g on schw bundle TM {
  [t,t] = -(1 - 2*M/r + Q^2/r^2),
  [r,r] = 1/(1 - 2*M/r + Q^2/r^2),
  [theta,theta] = r^2,
  [phi,phi] = r^2 * sin(theta)^2
}

kretschmann

Click in the first block and press Shift+Enter four times, once per block. The last one prints the Kretschmann scalar:

(-96*M*Q^2*r + 48*M^2*r^2 + 56*Q^4)/r^8

On screen it arrives typeset as a real fraction with real exponents; the line above is the same result written out flat.

That is the closed form from the textbook, computed from the metric you can see on screen. Set Q = 0 in the metric, run again, and it collapses to 48M²/r⁶ — Schwarzschild.

3. The notebook

The page is a stack of blocks. You edit a block and run it; the result appears underneath, typeset.

KeyWhat it does
Shift+EnterRun this block, move to the next one (creating one if this was the last).
Ctrl+EnterRun this block and stay in it. This is the one for iterating.
Alt+EnterRun this block and insert a new one right below.

The number in brackets on the left is the execution counter. [ ] means never run; [3] means this was the third block you ran. It follows the order you ran things in, not the order they sit on the page.

Nothing recomputes by itself. Opening a file runs nothing. Editing runs nothing. Clicking runs nothing. Only the three keys above run a block, and only the block you pressed them in. If a result is on screen, you asked for it.

When you edit a block that has already run, it turns stale: amber counter, a stripe, and a label above the old result. The result stays readable — it is simply marked as belonging to text that no longer exists. Every executed block below it goes stale too, because they may depend on what you changed. Nothing is recomputed and nothing is deleted; run the block again when you want it fresh.

At the bottom of the stack there is always an empty block with a dashed border. It is there to be typed in.

4. Choosing your language

The dropdown at the left of the header switches the interface between Português, English, Italiano and Français. Your choice is remembered the next time you open the page.

It changes the buttons, the panels and the status bar. It does not change error messages, which stay in Portuguese: they name what you wrote wrong, and they come from the engine, not the interface. If you hit one and cannot read it, chapter 10 covers the ones you are most likely to meet.

5. Starting from the gallery

The Gallery button opens a list of known spacetimes. Clicking one pastes its declarations as new, editable blocks at the end of your notebook — the same text you would have typed, never a metric hidden behind a button. Nothing runs; the blocks arrive as [ ], ready for you.

EntryWhat it isWhat you should get
SchwarzschildVacuum, static, spherically symmetricRab = 0; Kretschmann = 48M²/r⁶
Reissner–NordströmCharged, spherically symmetricR = 0 but Rab ≠ 0
KerrRotating black hole, Boyer–Lindquist coordinatesRab = 0 in all ten independent components
FRWSpatially flat cosmology, generic scale factor a(t)R = 6(a″/a + a′²/a²)
De SitterConstant positive curvatureR = 12H²; Weyl identically zero
Anti-de SitterConstant negative curvature, Poincaré coordinatesR = −12H²; Rab = −3H²gab

Every entry carries symbolic parameters — M, Q, a, H. To fix one, edit the pasted text, or write M := 1 in a block of its own before the metric.

Each of these was checked against a known closed form before it entered the list. They are a good way to confirm the engine is doing what you expect before you trust it on a metric of your own.

6. Writing your own metric

Four declarations, in this order. Each can live in its own block or share one; the notebook reads them top to bottom.

manifold M dim 4
bundle TM on M dim 4
chart schw on M coords (t, r, theta, phi)
metric g on schw bundle TM {
  [t,t] = -(1 - 2*M/r),
  [r,r] = 1/(1 - 2*M/r),
  [theta,theta] = r^2,
  [phi,phi] = r^2 * sin(theta)^2
}
LineWhat it says
manifold M dim 4A 4-dimensional manifold called M.
bundle TM on M dim 4The bundle that carries the tensor indices.
chart schw on M coords (...)The coordinates. Their number must equal the manifold's dimension.
metric g on schw bundle TM { ... }The components. Only the ones you write; everything else is zero.

Inside the braces, one row per component: [i,j] = expression, comma-separated, no comma after the last. The indices are coordinate names from your chart.

What you can write in an expression

You wantYou write
arithmetica + b, a - b, a * b, a / b; juxtaposition also multiplies (2M)
powersr^2, r^-1, r^{-2} — the exponent is always a whole number
trigonometrysin(theta), cos(theta)
hyperbolicsinh(chi), cosh(chi)
exponentialexp(H*t)
Greek lettersspell them: theta, phi, chi. LaTeX (\theta, \frac{a}{b}) is also accepted.
a shorthandf := 1 - 2*M/r in its own block, then f anywhere below
an unknown functionf(r), a(t) — the engine differentiates it as f'(r) without you defining it

Those five — sin, cos, exp, sinh, cosh — are the functions the engine knows. Others are handled deliberately rather than silently:

For a metric with no metric at all — a bare connection — you can declare the Christoffel symbols directly:

connection Gamma on flat2 {
  [x,y,y] = x
}

christoffel, riemann and ricci work from that. scalar and the other invariants do not, and say so: they need a metric to raise an index with.

7. What you can ask for

A block whose first word is one of these is a question. Write it alone, on its own line, and run it.

WriteYou get
christoffelThe Christoffel symbols Γabc.
riemannThe Riemann tensor, fully covariant.
ricciThe Ricci tensor Rab.
scalarThe Ricci scalar R — one expression.
kretschmannRabcdRabcd — the invariant that stays non-zero in vacuum.
einsteinThe Einstein tensor Gab.
weyl, weylsquareThe conformal tensor and its invariant. Undefined in 2 dimensions, and it says so.
riccisquare, gaussbonnetRabRab, and the Gauss–Bonnet density.
geodesic tauThe geodesic equations, one per coordinate. The trailing word is your affine parameter's name.
accel tauThe same equations solved for each second derivative — the form a numerical integrator eats.

Two refinements you will want eventually:

The affine parameter for geodesic/accel may not collide with a coordinate or with a symbol already in your metric. geodesic r against a chart that has r is refused, because t(r) would mean two things at once.

Long results are truncated on screen. The notebook shows the first 20 independent components and then a line saying how many more there are — ... and 10 more independent components (truncated) — plus how many are identically zero. The count is always honest; only the display is shortened.

8. Getting results out

Click any line of a result and its LaTeX goes to your clipboard — just that one equation, clean, ready to paste into a document. Not the annotation beside it, not the summary line, not the whole block. A small "copied" badge confirms it.

The Export button writes a line of code for another program. Pick a format and a query, and it inserts something like

export sympy kretschmann

into a new block. It does not run it — you run it, with Shift+Enter, like anything else. The panel shows you the exact line before you click, which is the point: the second time, you can write it yourself. Both Mathematica and SymPy are available, and export works on any of the queries in chapter 7.

Exported SymPy comes with its symbols(...) line and with reserved-word collisions renamed, so it runs where you paste it.

9. The other half: abstract indices

Everything so far computes components: you give a metric, you get expressions in r and θ. ODEROM has a second half, and it is available here too.

simplify works on tensor expressions where the indices are just labels — no metric, no coordinates, no components. Declare a tensor's symmetries with head, then ask whether an expression collapses:

manifold M dim 4
bundle TM on M dim 4
head R : TM*, TM*, TM*, TM* symmetry (1 2)- (3 4)- (1 3)(2 4)+

and then, in another block:

simplify R[a,b,c,d] + R[b,a,c,d]
0

That is antisymmetry in the first pair doing its work. Some more:

You writeYou getWhy
simplify R[a,b,c,d] - R[c,d,a,b]0The pair-exchange symmetry.
simplify 3 R[a,b,c,d] + -1 R[a,b,c,d]2 R[a,b,c,d]Like terms collect.
simplify R[a,b,c,d] + R[a,c,b,d]both terms surviveNothing declared makes them equal — and a simplifier that returned zero here would be worse than useless.

Notation: tensors are written side by side, not multiplied with *g[a,b] R[b,c,d,e]. A repeated index is a contraction. A semicolon introduces a covariant derivative: T[a,b;c].

Limit worth knowing

Multi-term identities — the Bianchi identities, metric compatibility — must be declared, and in the notebook there is no way to declare them yet. So a cyclic Bianchi sum will not collapse here, even though it is zero. It collapses on the command line, where those identities are flags. Making an .od document able to declare an axiom is an open design question, not an oversight.

What you do get in the browser is canonicalisation under declared symmetries and like-term collection — which is most of what the verb does.

10. Saving and reopening

Save downloads a file. Type a name in the path field first — that name is what the download gets, with .od appended if you left it off. A browser page cannot write to a folder you choose, so a download is what "save" means here.

Open uses your system's file picker. The path field is ignored for opening, deliberately: a page cannot read a file by path, only one you handed it, and pretending otherwise would be worse than the asymmetry. Cancelling the picker changes nothing and is not an error.

The file is plain text with %% on a line of its own between blocks. It is the same format the desktop application reads and writes, so a notebook moves between them untouched. Reopening always comes back with every block not executed — consistent with nothing recomputing by itself.

Closing the tab loses everything unsaved. There is no autosave and no server-side copy — that is the same property that means nothing you type ever leaves your machine. Save before you close.

11. When a calculation takes too long

While a block runs, the page keeps working: the other blocks accept focus and editing, and the running block offers Cancel. Only one block runs at a time; pressing a run key elsewhere is refused, with a flash on the status bar and on the block that is holding the engine.

There is no time limit in the browser. A calculation runs until it finishes or until you stop it. What does bound it is an expression-size ceiling (50 000 nodes), which stops a runaway before it exhausts your memory and reports rather than hanging forever.

Cancel costs your results

Cancelling in the browser discards every result you have computed so far — not just the block you cancelled. Your text survives intact; the results do not, and every block returns to [ ].

This is not a design choice, it is the platform: stopping WebAssembly mid-computation is only possible by terminating the worker thread it runs in, and the worker holds every result with it. Measured, not assumed: a test drives a real browser, counts four blocks with results before a cancel and zero after.

In practice: run the expensive query last, and if you expect to cancel, save first.

12. What is different from the desktop version

The language, the engine and the results are identical — the same Rust, compiled two ways. Four differences, all imposed by the browser:

HereOn the desktop
Save downloads a fileSave writes to the path you typed
Open uses the file pickerOpen reads the path you typed
Cancel discards all computed resultsCancel stops one block; other results stay
No time limit; a size ceiling insteadSame size ceiling

Everything else — the keys, the block states, staleness, the gallery, Export, click-to-copy, the language selector — behaves the same in both.

13. Going further

The full manual (ODEROM-manual.pdf) covers what this guide leaves out: the complete grammar, the command-line tools, the error-message reference, the declared axioms for abstract-index work, and nine worked examples. Read this one to get started; read that one when you want to know exactly what the program will and will not do.

Two habits worth forming early, both of which this program is built around:


ODEROM · browser guide. Every behaviour described here was verified against the running program on 20 August 2026, including the cost of cancelling, which was measured in a real browser rather than assumed.