This simple time estimator for projects takes a CSV file and runs a monte carlo simulation to help understand the project's future. It will give you projections of both time required and costs. It is inspired by ideas from Joel Spolsky's piece of Evidence Based Estimates with my own tweaks and adjustments.
Use it online: Visit https://spinningcode.org/estimates to use the tool without downloading anything.
Run it locally: Clone this repository and run:
npm install
npm start
The simulator supports three types of project estimates:
- Hours-Based Estimates: Provide a minimum and maximum hour estimate for each task
- Fibonacci-Based Estimates: Use Fibonacci story points (1, 2, 3, 5, 8, 13, 21, 34) for each task
- T-Shirt Size Estimates: Use t-shirt sizes (XS, S, M, L, XL, XXL) for each task
Choose the estimation mode that matches your team's planning methodology. The tool automatically maps Fibonacci numbers and t-shirt sizes to hour ranges for simulation purposes.
You can enter your project tasks in two ways:
- Open the application in your browser
- Select your estimation mode (Hours, Fibonacci, or T-Shirt)
- Fill in the data fields for each task:
- Task: Name or description of the task
- Min Time (hours mode): Minimum hours estimate
- Max Time (hours mode): Maximum hours estimate
- Fibonacci (Fibonacci mode): Story point value (mutually exclusive with hours)
- T-Shirt (T-Shirt mode): Size value (mutually exclusive with hours/fibonacci)
- Confidence: Your confidence level as a percentage (0-100)
- Cost: Hourly rate for this task
- Click "Run Simulation" to generate results
Upload a CSV file with your task data. The format depends on your estimation mode:
Hours Mode CSV:
Task,Max,Min,Confidence,Cost
Setup,5,2,90,120
Page,20,10,90,120
Blog Post,20,10,90,100
Fibonacci Mode CSV:
Task,Fibonacci,Confidence,Cost
Setup,2,90,120
Page,8,90,120
Blog Post,8,90,100
T-Shirt Mode CSV:
Task,TShirt,Confidence,Cost
Setup,S,90,120
Page,L,90,120
Blog Post,L,90,100
Sample files are available:
The tool runs a Monte Carlo simulation with 10,000+ iterations to generate statistical projections:
-
For each task, the simulation:
- Within your confidence threshold: randomly selects a value between min and max
- Outside your confidence threshold: has a 50% chance of underrunning (0 to min) or overrunning (max to upper bound)
-
Upper Bound Calculation: Lower confidence means higher risk of overrun
- 90% confidence: upper bound = max × 1
- 80% confidence: upper bound = max × 2
- 70% confidence: upper bound = max × 3
- And so on...
-
Result Aggregation: All task estimates are summed for each simulation run
-
Statistical Analysis: The tool calculates and displays:
- Median estimate (the middle value across all simulations)
- Standard deviation (how much variance to expect)
- Visual histogram showing the distribution of outcomes
- Higher confidence (90-100%): Tighter estimates, results cluster closer to your min-max range
- Lower confidence (50-80%): Wider variance, higher risk of significant overruns
- The confidence percentage represents how often the actual time falls within your estimated range
- Narrow range (e.g., 5-6 hours): Indicates well-understood tasks with predictable outcomes
- Wide range (e.g., 10-40 hours): Reflects uncertainty or complexity; increases variance in results
Important: Story points are estimated in calendar days, not hours. This reflects how Agile teams actually work, accounting for meetings, reviews, and all the overhead of real-world development.
The tool offers two mapping modes:
Each Fibonacci number maps to a calendar day range:
- 1 → 0.5-1 days
- 2 → 1-2 days
- 3 → 2-3 days
- 5 → 3-5 days
- 8 → 5-8 days (1-1.6 weeks)
- 13 → 8-13 days (1.6-2.6 weeks)
- 21 → 13-21 days (2.6-4.2 weeks)
- 34 → 21-34 days (4.2-6.8 weeks)
Maps story points to days based on your team's historical velocity:
- Points Per Sprint: Average story points your team completes
- Sprint Length: Your sprint duration in working days
- Calculation: Points ÷ (Points Per Sprint ÷ Sprint Days) = Base Days ± 30% variance
Example: With 25 points/sprint over 10 days:
- Velocity ratio: 2.5 points/day
- 8-point story: 8 ÷ 2.5 = 3.2 days → 2.24 to 4.16 days
Tip: Use velocity-based mode if your team tracks historical velocity. Use calendar days mode if you don't have velocity data or prefer standard agile time estimates.
T-shirt sizes map to hour ranges:
- XS → 1-2 hours
- S → 2-3 hours
- M → 3-5 hours
- L → 5-8 hours
- XL → 8-13 hours
- XXL → 13-21 hours
- When enabled, calculates total project cost based on each task's hourly rate
- Provides both time and budget projections
- Can be toggled on/off as needed
Median Value: Use this as your most likely outcome (50% of simulations came in at or below this)
Standard Deviation: Indicates the spread of results:
- Low standard deviation: Consistent, predictable project
- High standard deviation: High uncertainty, greater risk
Histogram: Shows the distribution of all simulation outcomes:
- Narrow peak: Predictable outcomes
- Wide spread: High variability; consider contingency planning
- Multiple peaks: May indicate tasks with very different confidence levels
The project leverages D3 for the histogram visualization.
For power users who want to customize the visualization appearance, the tool includes an Advanced Graph Settings panel located in the simulation section.
- Scroll to the simulation controls area
- Click on "Advanced Graph Settings" to expand the panel
- Modify any settings you wish to change
- Click "Apply Settings" to use your custom values
- Click "Reset to Defaults" to restore original values
- Width (px): Width of the main time/cost histogram graphs (default: 800px, range: 400-2000)
- Height (px): Height of the main histogram graphs (default: 500px, range: 300-1000)
- Bar/Scatter Cutoff: Number of data points before switching from bar chart to scatter plot (default: 600, range: 100-2000)
- Bar charts work well for smaller datasets
- Scatter plots with KDE curves are used for large, complex distributions
- Max Preview Buckets: Maximum number of buckets for histogram preview during progressive simulation (default: 120, range: 20-500)
- Reduces rendering complexity during live updates as simulation runs
- Final histograms display full detail without bucketing (up to the bar/scatter cutoff)
Each task row displays a compact histogram showing that individual task's distribution:
- Width (px): Width of mini task row graphs (default: 140px, range: 50-300)
- Height (px): Height of mini task row graphs (default: 26px, range: 10-100)
- Max Buckets: Maximum number of bars in mini graphs (default: 24, range: 5-50)
- Bar Gap (px): Spacing between bars in mini graphs (default: 1px, range: 0-5)
- Large displays: Increase width/height for better visibility on high-resolution monitors
- Presentations: Adjust dimensions to match your presentation format
- Print layouts: Modify sizes to optimize for printed reports
- Performance tuning: Reduce max preview buckets if progressive simulation updates are slow
- Dense data: Increase bar/scatter cutoff if you prefer bar charts for larger datasets
- Settings persist only for your current session
- Changes apply to new simulations; existing graphs are not retroactively updated
- All settings are validated to prevent invalid configurations
- The collapsible panel keeps the interface clean for casual users
- Node.js (v20 or higher recommended)
- npm
- Clone the repository:
git clone https://github.com/acrosman/simple-project-estimates.git
cd simple-project-estimates- Install dependencies:
npm installnpm start- Start development server with hot reloadnpm test- Run test suite with coveragenpm run lint- Check code style with ESLintnpm run lint-fix- Automatically fix linting issuesnpm run build- Build for developmentnpx webpack --mode=production- Build optimized production bundle
The project uses Jest for testing. Tests are located in src/tests/:
stats.test.js- Tests for pure math and statistics functions (getMedian,getStandardDeviation,calculateKDE,taskUpperBound,taskLowerBound, etc.)charts.test.js- Tests for graph configuration and D3 histogram builders (GRAPH_CONFIG,buildHistogramPreview,buildTaskRowHistogram)simulation.test.js- Tests for the simulation engine (runSimulation,runSimulationProgressive, Fibonacci utilities)csv-parser.test.js- Tests for CSV parsing and data validationdata-input-ui.test.js- Tests for data entry form generation and UI interactionsdom-helpers.test.js- Tests for reusable DOM element factory functionsexport-utils.test.js- Tests for CSV/SVG/PNG export utilitiesfibonacci-config.test.js- Tests for Fibonacci/velocity configuration UIgraph-settings.test.js- Tests for graph settings and configuration helpersindex.test.js- Tests for UI orchestration functions and DOM manipulationlayout.test.js- Tests for page layout constructionstate.test.js- Tests for application state managementtask-table.test.js- Tests for task data-entry table creation and row lifecycletshirt-config.test.js- Tests for T-shirt size mapping configuration UIhtml-template.test.js- Tests for HTML template structure and accessibilityaccessibility.test.js- Tests for accessibility compliance
Run tests with coverage report:
npm test- ESLint configured with Airbnb style guide
- All functions include JSDoc documentation
- Comprehensive test coverage for core simulation logic
- Accessible UI with ARIA labels and keyboard navigation
src/
├── index.js # UI orchestration and event handlers
├── style.css # Styling
├── index.html # HTML template
├── core/
│ ├── simulation.js # Simulation engine (runSimulation, runSimulationProgressive,
│ │ # Fibonacci utilities), uses stats helpers internally
│ ├── stats.js # Pure math and statistics (getMedian, getStandardDeviation,
│ │ # calculateKDE, taskUpperBound, taskLowerBound, generateEstimate)
│ └── state.js # Application state management (AppState class)
├── ui/
│ ├── data-input-ui.js # Data entry form generation and UI interactions
│ ├── fibonacci-config.js # Fibonacci/velocity configuration UI panel
│ ├── graph-settings.js # Graph settings UI and configuration helpers
│ ├── layout.js # Page layout construction
│ ├── simulation-handler.js # Simulation results display
│ ├── task-table.js # Task data-entry table and row lifecycle
│ └── tshirt-config.js # T-shirt size mapping configuration UI
├── utils/
│ ├── csv-parser.js # CSV parsing and data validation
│ ├── dom-helpers.js # Reusable DOM element factory functions
│ └── export-utils.js # CSV/SVG/PNG export utilities
├── visualization/
│ └── charts.js # D3 visualization (buildHistogram, buildHistogramPreview,
│ # buildTaskRowHistogram, GRAPH_CONFIG, GRAPH_CONFIG_DEFAULTS)
├── data/ # Sample CSV files
└── tests/
├── stats.test.js # Math and statistics function tests
├── charts.test.js # Graph configuration and rendering tests
├── simulation.test.js # Simulation engine and Fibonacci tests
├── csv-parser.test.js # CSV parsing and validation tests
├── data-input-ui.test.js # Data entry form generation tests
├── dom-helpers.test.js # DOM element factory function tests
├── export-utils.test.js # Export utility tests
├── fibonacci-config.test.js # Fibonacci config UI tests
├── graph-settings.test.js # Graph settings tests
├── index.test.js # UI orchestration function tests
├── layout.test.js # Page layout tests
├── state.test.js # Application state tests
├── task-table.test.js # Task table and row lifecycle tests
├── tshirt-config.test.js # T-shirt config UI tests
├── html-template.test.js # HTML template and accessibility tests
└── accessibility.test.js # Accessibility compliance tests
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Run tests and linting (
npm test && npm run lint) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
