Skip to content
FLAVIO COPES
flaviocopes.com
2026

I launched Calculum: practical calculators for real life

By

I launched calculum.dev, a growing library of practical calculators with clear formulas, visible assumptions, and browser-only calculations.

~~~

Today I launched Calculum.

Calculum is a free library with a ton of practical calculators for real life.

It helps you answer questions like:

There are calculators for money, housing, home projects, energy, travel, cars, shopping, work, taxes, insurance, cooking, fitness, shipping, sustainability, and more.

No account is required. Your numbers stay in your browser.

Why I built it

Calculum started as a different product.

The first version was a local-first notepad calculator. You could type calculations, name values, and work through a problem one line at a time.

It worked, but the idea was too broad.

Most people do not wake up wanting a blank calculation surface. They have a specific question.

They want to know if an apartment fits their budget. How much a trip will cost. Which package is cheaper. How much material a home project needs.

So I changed the product.

Instead of one general calculator, I built a library of small calculators. Each one starts with a real decision and asks only for the numbers needed to answer it.

What makes Calculum different

A calculator should not give you one mysterious number in a box.

Every Calculum page shows the formula, the assumptions, and a useful breakdown of the result. Many calculators also include examples, edge cases, country context, and links to authoritative sources.

Changing values updates the result immediately.

You can also choose your country. Calculum adjusts currencies, number formats, dates, and measurement units while keeping volatile values visible. It does not silently invent exchange rates, tax rates, or energy prices.

The calculation happens in your browser. There is no account, database, or server receiving the numbers you enter.

I also made the catalog searchable. With a library this large and still growing, browsing a long list would get old quickly.

How I built it

The site is data-driven.

I did not build every calculator page by hand. I split the product into two layers.

The catalog contains the public metadata: slug, title, category, and the question the calculator answers.

The tool specifications contain the actual behavior: fields, default values, formula, assumptions, and a calculate() function.

Here is the complete structure of the monthly budget calculator:

'monthly-budget-planner': {
  eyebrow: 'Money left this month',
  fields: [
    field('income', 'Monthly take-home income', 4200, { prefix: '$' }),
    field('housing', 'Housing', 1400, { prefix: '$' }),
    field('food', 'Food & groceries', 650, { prefix: '$' }),
    field('transport', 'Transport', 350, { prefix: '$' }),
    field('other', 'Everything else', 900, { prefix: '$' }),
  ],
  formula: 'Income − housing − food − transport − other spending',
  assumptions: [
    'All values cover the same month.',
    'Taxes are already reflected in take-home income.',
  ],
  calculate: ({ income, housing, food, transport, other }) => {
    const spending = housing + food + transport + other
    const left = income - spending

    return result(money(left), left >= 0 ? 'left after spending' : 'over budget', [
      ['Total spending', money(spending)],
      ['Savings rate', income > 0 ? percent((left / income) * 100) : '—'],
      ['Yearly equivalent', money(left * 12)],
    ])
  },
}

The shared Astro page turns a specification into the form, result panel, formula, assumptions, examples, sources, and related links.

Astro creates every URL from one dynamic route:

export function getStaticPaths() {
  return calculators.map(calculator => ({
    params: { slug: calculator.slug },
  }))
}

At build time, the page runs calculate() with the default values. The initial answer is already in the generated HTML, together with the useful explanatory content.

JavaScript takes over when you change an input. The browser reads the form, converts displayed units back to canonical values, calls the same calculate() function, and updates the result text and breakdown.

There is no framework hydration and no request to a server.

The examples, sensitivity charts, and saved scenarios also use the real calculator functions. Saved snapshots go into localStorage, so you can compare plans without creating an account or uploading the values.

How localization works

The calculation definitions use canonical values. Measurements are stored in metric units, while money and dates are formatted at the edge of the interface.

Each country profile defines a locale, currency, and measurement system. Intl.NumberFormat and Intl.DateTimeFormat handle the display. Small conversion functions translate between kilometers and miles, liters and gallons, Celsius and Fahrenheit, and the other supported units.

When you change country, the browser first converts the current input back to its canonical value. It then converts that value into the new display unit and runs the calculator again.

This avoids a subtle bug: changing from kilometers to miles should change the number shown in the field, not the real distance being calculated.

Country-specific rules are separate from the formulas. They can change labels, visible defaults, context, and official source links, but they do not hide live tax or exchange rates inside the code.

How I test the calculators

Keeping the formulas as plain JavaScript functions means I can test them without opening a browser.

I use Node’s built-in test runner. The main catalog test loads every active calculator, builds its default input object, calls calculate(), and checks that the result has a primary value, a label, and detail rows. It also rejects NaN, Infinity, and missing values.

Then there are focused tests for the cases that usually break calculators: zero interest, payments that cannot reduce a balance, unreachable goals, negative results, unit round trips, and country-specific tax conventions.

Other tests check that:

The complete local verification command is:

npm run check

That runs the Node tests, astro check, and a full production build.

Building with AI agents

I built Calculum with AI coding agents doing much of the implementation. My job was product direction, review, and deciding what should stay.

That last part mattered.

At one point the site grew too quickly. I removed dozens of weak or duplicate calculators before launch. Generating another page was easy. Making sure it deserved to exist was the real work.

The development stack

Calculum is intentionally simple:

There is no React application, UI framework, calculation library, API, or database. The package dependency list is Astro, @astrojs/check, and TypeScript.

Astro generates the homepage, category pages, country guides, and all calculator pages as static HTML. JavaScript only takes over where interaction is needed.

Each calculator also gets its own title, description, canonical URL, breadcrumbs, WebApplication structured data, and sitemap entry during the build. Category pages use CollectionPage and ItemList structured data.

The deployment stack

The code lives in a GitHub repository and the site is deployed to Cloudflare Pages.

Cloudflare watches the main branch. Each push runs:

npm run build

That command runs astro check and the Astro build, then Cloudflare publishes the generated dist directory.

There is no Astro adapter because the output is fully static. There are also no environment variables, secrets, Workers, serverless functions, or database migrations involved in a deploy.

Cloudflare serves the pages and assets from its network, while every calculation stays on the visitor’s device.

This is my favorite kind of deployment stack: there is almost nothing to operate.

Try it

Open Calculum and search for the question you are trying to answer.

The site is free, there is no signup, and I am still adding and improving calculators.

If a result is unclear, a formula looks wrong, or a useful calculator is missing, let me know.

Tagged: News · All topics
~~~

Related posts about news: