Replace false-precision deadlines with real probability ranges.
Ballpark is a focused planning tool for tech leads, EMs, and founders sizing a roadmap. You add tasks with three‑point estimates (best / likely / worst hours), tag the risky ones, and Ballpark runs a 10,000-trial Monte Carlo simulation to show you the dates you can actually defend.
It's local-first: no account, no backend, nothing leaves your browser tab.
Most teams give single-date deadlines that are either hopelessly optimistic or padded with hidden buffer. The honest answer to "when will this ship?" is a probability distribution, not a date. PERT/Monte Carlo techniques solve this — but the existing tools are either spreadsheet macros or enterprise project software.
Ballpark is the small, focused tool in between.
- Three-point estimation table with risk tags (novel-tech, external-dep, unclear-spec, integration, design-heavy) that widen the spread on a per-task basis.
- Timeline view — same data laid out as a sequential pipeline on a date axis, with uncertainty whiskers per task and project-level P50 / P75 / P90 markers.
- Drag-and-drop reordering in both views, plus keyboard arrows for accessibility.
- 10,000-run Monte Carlo with a deterministic seed, so results are stable while you edit.
- Headline forecast — three percentile cards with opinionated copy ("the date you can defend to leadership" for P90).
- Distribution chart with hover tooltips mapping each bar to a calendar date and run percentage.
- Sensitivity panel ranking tasks by their share of total variance — directly shows where to cut to tighten the forecast.
- Multi-project sidebar with create / duplicate / delete / JSON export.
- Three realistic seeded sample projects on first load so the tool is useful in 10 seconds.
- Mobile-responsive layout.
npm install
npm run dev # http://localhost:5173
npm run build # production build into dist/
npm run preview # serve the production buildEach task samples from a triangular distribution defined by your three estimates (a, c, b) = (best, likely, worst). Sampling uses the inverse CDF — exact, fast, no rejection sampling.
Risk tags scale the spread without moving the mode: each tag adds 12% to the optimistic↔pessimistic distance (capped at 1.6×). So a task tagged novel-tech, external-dep has the same most-likely value but a meaningfully wider uncertainty range.
For each of 10,000 trials we sample every task, sum, and apply your contingency multiplier. The sorted totals give us the percentiles. Sensitivity is the closed-form variance of each task's triangular as a share of total variance (assuming task independence — fine for this use case).
A deterministic PRNG (Mulberry32) seeded from a hash of the project's task data means the histogram doesn't flicker as you edit unrelated fields.
Hours-of-work convert to calendar days via the project's Capacity (hrs/week) setting. We don't model working-days vs. weekends — most projects burn at a roughly constant rate per calendar week regardless of which days are which, and pretending we know your team's holiday schedule is false precision.
- Vite + React 18 + TypeScript (strict, with
noUnusedLocals/noUnusedParameters) - TailwindCSS
- Hand-rolled SVG charts (no chart library)
- Inline icon set (no icon library)
localStoragepersistence
Total bundle: ~187 KB JS / ~27 KB CSS.
src/
├── App.tsx # top-level layout, project CRUD
├── types.ts # Project, Task, RiskTag, SimulationResult
├── lib/
│ ├── simulate.ts # Monte Carlo, triangular sampler, date math
│ ├── format.ts # hour/date formatting
│ ├── storage.ts # localStorage wrapper
│ └── samples.ts # seeded sample projects
├── hooks/
│ └── useReorder.ts # HTML5 drag-and-drop reorder hook
└── components/
├── Sidebar.tsx # project list (desktop)
├── MobileNav.tsx # project switcher (mobile)
├── ProjectMeta.tsx # name/dates/capacity/contingency
├── HeadlineForecast.tsx # P50/P75/P90 cards
├── TasksSection.tsx # wrapper with view toggle
├── TaskTable.tsx # table view of tasks
├── TimelineView.tsx # pipeline / Gantt-style view
├── DetailedForecast.tsx # distribution chart + sensitivity
├── DistributionChart.tsx # SVG histogram
├── Sensitivity.tsx # variance-share ranking
├── GuideModal.tsx # "How Ballpark works"
├── Welcome.tsx # first-run / no-project state
└── Icons.tsx # inline SVG icon set
All data lives in localStorage under three keys:
ballpark.projects.v1— array ofProjectballpark.activeProjectId.v1— currently selected project idballpark.taskView.v1— last-used view mode (tableortimeline)ballpark.seeded.v1— first-run flag so samples only seed once
Use Export in the project header to dump a project to JSON.
- A project tracker — there are no statuses, assignees, or due dates per task.
- An estimation game (planning poker, t-shirts) — those are upstream of this tool.
- Multi-user — everything is local.
If your team needs any of those, Ballpark hands you off cleanly: the JSON export is a clean record of "here's what we estimated and why."