Blog

Technical notes, training science, and product updates from the pacelore team.

Six months of pacelore

What we shipped, what we learned, and where the project stands.

Backfilling a Strava history through the API

Rate limits, deduplication, and making a long import safe to re-run.

Building a workout library for Garmin and Zwift

60 structured sessions, FIT export, .zwo export, and the step schema behind them.

Why PolyForm Noncommercial over MIT

The license choice that lets anyone self-host pacelore but blocks commercial wrappers.

Segment matching with Dynamic Time Warping

How pacelore finds your effort on a segment even when GPS lines don't overlap perfectly.

Peak power curves: the mean-maximal power chart

What the MMP curve shows, how it's computed, and why it's paywalled everywhere else.

Deduplicating activities across Garmin, Zwift, and Strava

The same ride can arrive from three sources. Here's how we keep exactly one copy.

ATProto and athletic data portability

Why we wired optional Bluesky export into the ingest pipeline.

Arweave permanence: your activities should outlive any startup

One-time write to a permaweb means your FIT files survive if pacelore disappears.

Running pacelore: $0.012 per athlete per month

A line-by-line breakdown of the Cloudflare bill and how the math works at scale.

TSS three ways: power, heart rate, pace

Power TSS, hrTSS, and rTSS — the same idea computed three different ways.

Grade-Adjusted Pace and the Minetti model

How to flatten a hilly run into a comparable flat effort using metabolic cost equations.

Normalized Power in 20 lines of TypeScript

The 4th-power moving average that makes sense of variable-effort rides.

FIT, TCX, GPX: a field guide to fitness file formats

What each format contains, where it comes from, and how we parse all three.

Why we chose Cloudflare D1 over Postgres

The tradeoffs of a SQLite-at-the-edge database for a multi-tenant fitness platform.