Notebook · behind the scenes · · 4 min read
Turning an Excel spreadsheet into a web calculator with Claude
How the open-source spreadsheet from SNCF, Resilio, and Wavestone became a page that calculates the electricity, carbon, and water footprint of an AI request, and the fixes it needed on mobile.
Work log written with Claude from my notes, then reviewed and approved. Translated from French.
Since October 2026, vibe.nfrancois.fr has lived on as the Projects and Notebook sections of nfrancois.fr. This entry describes the site as it was then.
The starting point
In July 2026, the SNCF group’s digital department, Resilio, and Wavestone published Impact’IA: a methodology guide and a spreadsheet calculator, open source (CC BY-NC-SA 4.0 license, GitHub repository (opens in a new tab)). The spreadsheet estimates the electricity use, carbon emissions, and water consumption of a generative AI use case, based on the model, the token volume, and the country where the servers run.
A spreadsheet is precise but hard to share. I wanted a page you can open without installing anything, one that answers a simple question: what does a request cost, for my actual use.
The stack
- Claude, as an artifact on claude.ai (Max subscription) for the port: I gave it the spreadsheet and it produced a standalone HTML page.
- HTML, CSS, and JavaScript with no dependencies: a single file, no framework, no network call to calculate.
- vibe.nfrancois.fr (Next.js on Vercel) to host it, with the site’s shared design foundation.
- Claude Code and Playwright for the fixes and the mobile checks.
The steps
Porting the “Calcul” tab
The heart of the spreadsheet is in the “Calcul” (calculation) tab. The artifact translated it into a JavaScript function, impactIA, that keeps the same constants and the same formulas. Inputs stay monthly, as in the spreadsheet (“Données” tab, Production mode), then annualized.
The calculation adds up six components: inference (the model’s answer), RAG and embedding, the application front end, training allocated in proportion to output tokens, research and test training runs (counted as four times the final training), and storage. An excerpt from the inference part:
// --- Inference: answering the requests
const mem = 1.2*PT*(16/8);
const nMin = Math.ceil((mem/80)*10 - 1e-9)/10;
let nGPU = 1; while (nGPU < nMin) nGPU *= 2;
const ePerTok = Tout>0 ? E_A*Math.exp(E_B*BATCH)*PA + E_G : 0; // Wh/token
const eGPU = (Tout*ePerTok/1000)*nGPU;The number of GPUs follows from the memory the model needs, and the energy per token from an exponential law based on the number of active parameters. The method’s 38 models are carried over with their parameters: size, active parameters, the provider’s PUE and WUE, throughput in tokens per second, release date, and country.
Adding what the spreadsheet doesn’t do
Three additions, without touching the formulas or the emission factors:
- Input per request instead of monthly volumes, which is more meaningful for a real-world use case.
- Examples to get started: a tourist office chatbot (5,000 requests a month), writing listing descriptions (2,000), and an assistant for a team of ten (4,400).
- A comparison of the 38 models on a logarithmic scale, with a breakdown of the footprint by component.
With the chatbot example and GPT-4o mini, the page shows 11.9 mg of CO₂e, 101 mWh, and 1.71 mL of water per request, or 713 g of CO₂e, 6.07 kWh, and 103 L over a year.
Integrating it into the site
The page stayed a standalone HTML file, placed in public/impact-ia/index.html. A rewrite rule serves it at a clean URL:
async rewrites() {
return [{ source: '/impact-ia', destination: '/impact-ia/index.html' }];
},It then loads the site’s shared foundation (/kit/vibe.css and /kit/theme.js): fonts, navigation bar, footer, and light and dark themes. It keeps its own data colors: yellow for electricity, slate for carbon, and blue for water.
What went wrong
The artifact worked well on claude.ai. Once online and on mobile, three flaws showed up.
- Fields overflowing the panel. The “Affiner” (refine) section is a
detailselement. In Chromium, its content goes through the::details-contentpseudo-element, which breaks the inheritance ofbox-sizing. The fields went back tocontent-boxand spilled out of their frame. Fix:::details-content { box-sizing: inherit }, and an explicitborder-boxon the fields. - Horizontal scrolling on mobile. A
1frgrid lets a child that’s too wide push the column out. It tookgrid-template-columns: minmax(0, 1fr)and a compact version of the comparison table. - A badly sized scale. The logarithmic scale was drawn for a fixed width. It’s now drawn at the actual width of its block.
Each fix was checked in Chromium with Playwright, on desktop (1440 px) and mobile (390 px), making sure the page didn’t scroll horizontally.
Time and costs
- The port was done in a Claude artifact, with my Max subscription, at no extra cost.
- The integration into the site dates from October 11, the mobile fixes and the switch to the shared foundation from October 12.
- The page makes no API calls: running it costs nothing.
Takeaways
- A well-documented open-source spreadsheet can be ported to a web page without reinterpreting the method. The “formulas, models, and factors unchanged” rule makes the result verifiable.
- An artifact that works on claude.ai isn’t a publish-ready page yet. Testing on a real phone reveals flaws that are invisible on desktop.
- The license matters: the adaptation stays under CC BY-NC-SA 4.0, with the sources and changes credited at the bottom of the page.