[{"data":1,"prerenderedAt":41},["ShallowReactive",2],{"4588010":3},{"type_of":4,"id":5,"title":6,"description":7,"readable_publish_date":8,"slug":9,"path":10,"url":11,"comments_count":12,"public_reactions_count":13,"collection_id":14,"published_timestamp":15,"language":16,"subforem_id":17,"ai_disclosure_level":18,"ai_disclosure_label":19,"positive_reactions_count":13,"cover_image":14,"social_image":20,"canonical_url":11,"created_at":15,"edited_at":14,"crossposted_at":14,"published_at":15,"last_comment_at":15,"reading_time_minutes":21,"tag_list":22,"tags":23,"body_html":27,"body_markdown":28,"user":29,"organization":36},"article",4588010,"How to calculate a no-income runway without pretending expenses are constant","When someone asks “how many months can I live without a salary?”, dividing savings by monthly...","Sep 6","how-to-calculate-a-no-income-runway-without-pretending-expenses-are-constant-3dnk","/begoodtool/how-to-calculate-a-no-income-runway-without-pretending-expenses-are-constant-3dnk","https://dev.to/begoodtool/how-to-calculate-a-no-income-runway-without-pretending-expenses-are-constant-3dnk",0,8,null,"2026-09-06T13:00:03Z","en",1,"not_disclosed","Not Disclosed","https://media2.dev.to/dynamic/image/width=1200,height=627,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz16v7c9wijhq9ix2q5kx.png",4,"javascript, vue, finance",[24,25,26],"javascript","vue","finance","\u003Cp>When someone asks “how many months can I live without a salary?”, dividing savings by monthly expenses gives a useful first guess, but it hides two decisions: which expenses are essential and what happens to income during the transition. I built this calculator around explicit scenarios so a cautious budget and a current-lifestyle budget can be compared instead of blended into one optimistic number. This is aimed at anyone planning a resignation, layoff buffer, or career break and wanting to understand the model rather than trust one impressive number.\u003C/p>\n\n\u003Ch2>\n  \u003Ca name=\"net-burn-is-the-quantity-that-matters\" href=\"#net-burn-is-the-quantity-that-matters\">\n  \u003C/a>\n  Net burn is the quantity that matters\n\u003C/h2>\n\n\u003Cp>Each scenario has savings, transition income, an annual savings rate, and four expense buckets: rent or mortgage, living costs, insurance, and other essentials. The calculation sums expenses, subtracts income, then clamps negative burn to zero:\u003Cbr>\n\u003C/p>\n\n\u003Cdiv class=\"highlight js-code-highlight\">\n\u003Cpre class=\"highlight javascript\">\u003Ccode>\u003Cspan class=\"kd\">const\u003C/span> \u003Cspan class=\"nx\">monthlyExpense\u003C/span> \u003Cspan class=\"o\">=\u003C/span> \u003Cspan class=\"nf\">cleanNumber\u003C/span>\u003Cspan class=\"p\">(\u003C/span>\u003Cspan class=\"nx\">clean\u003C/span>\u003Cspan class=\"p\">.\u003C/span>\u003Cspan class=\"nx\">rent\u003C/span>\u003Cspan class=\"p\">)\u003C/span>\n  \u003Cspan class=\"o\">+\u003C/span> \u003Cspan class=\"nf\">cleanNumber\u003C/span>\u003Cspan class=\"p\">(\u003C/span>\u003Cspan class=\"nx\">clean\u003C/span>\u003Cspan class=\"p\">.\u003C/span>\u003Cspan class=\"nx\">living\u003C/span>\u003Cspan class=\"p\">)\u003C/span>\n  \u003Cspan class=\"o\">+\u003C/span> \u003Cspan class=\"nf\">cleanNumber\u003C/span>\u003Cspan class=\"p\">(\u003C/span>\u003Cspan class=\"nx\">clean\u003C/span>\u003Cspan class=\"p\">.\u003C/span>\u003Cspan class=\"nx\">insurance\u003C/span>\u003Cspan class=\"p\">)\u003C/span>\n  \u003Cspan class=\"o\">+\u003C/span> \u003Cspan class=\"nf\">cleanNumber\u003C/span>\u003Cspan class=\"p\">(\u003C/span>\u003Cspan class=\"nx\">clean\u003C/span>\u003Cspan class=\"p\">.\u003C/span>\u003Cspan class=\"nx\">other\u003C/span>\u003Cspan class=\"p\">);\u003C/span>\n\u003Cspan class=\"kd\">const\u003C/span> \u003Cspan class=\"nx\">rawNetBurn\u003C/span> \u003Cspan class=\"o\">=\u003C/span> \u003Cspan class=\"nx\">monthlyExpense\u003C/span> \u003Cspan class=\"o\">-\u003C/span> \u003Cspan class=\"nx\">income\u003C/span>\u003Cspan class=\"p\">;\u003C/span>\n\u003Cspan class=\"kd\">const\u003C/span> \u003Cspan class=\"nx\">netBurn\u003C/span> \u003Cspan class=\"o\">=\u003C/span> \u003Cspan class=\"nb\">Math\u003C/span>\u003Cspan class=\"p\">.\u003C/span>\u003Cspan class=\"nf\">max\u003C/span>\u003Cspan class=\"p\">(\u003C/span>\u003Cspan class=\"mi\">0\u003C/span>\u003Cspan class=\"p\">,\u003C/span> \u003Cspan class=\"nx\">rawNetBurn\u003C/span>\u003Cspan class=\"p\">);\u003C/span>\n\u003C/code>\u003C/pre>\n\u003Cdiv class=\"highlight__panel js-actions-panel\">\n\u003Cdiv class=\"highlight__panel-action js-fullscreen-code-action\">\n    \u003Csvg xmlns=\"http://www.w3.org/2000/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-on\">\u003Ctitle>Enter fullscreen mode\u003C/title>\n    \u003Cpath d=\"M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z\">\u003C/path>\n\u003C/svg>\n\n    \u003Csvg xmlns=\"http://www.w3.org/2000/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-off\">\u003Ctitle>Exit fullscreen mode\u003C/title>\n    \u003Cpath d=\"M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z\">\u003C/path>\n\u003C/svg>\n\n\u003C/div>\n\u003C/div>\n\u003C/div>\n\n\n\n\u003Cp>Suppose the four buckets total 50,000 and temporary income is 12,000. The model calls the burn 38,000 per month. If income is 55,000, \u003Ccode>rawNetBurn\u003C/code> is negative, but \u003Ccode>netBurn\u003C/code> becomes zero. The result is labeled theoretically indefinite rather than claiming that savings become infinite. That distinction matters: a zero modeled burn means this particular set of assumptions does not consume the starting savings; it does not mean the person's life has no expenses.\u003C/p>\n\n\u003Cp>Every numeric field passes through \u003Ccode>cleanNumber\u003C/code>, which turns non-finite or non-positive values into zero. Annual rate is also capped at 100 percent. Those choices make pasted blanks and malformed input safe, but they also mean a typo can silently become zero. I would still review the displayed monthly expense before using the result for a real decision.\u003C/p>\n\n\u003Ch2>\n  \u003Ca name=\"daily-simulation-and-the-304375day-compromise\" href=\"#daily-simulation-and-the-304375day-compromise\">\n  \u003C/a>\n  Daily simulation and the 30.4375-day compromise\n\u003C/h2>\n\n\u003Cp>For a finite runway, the component divides monthly net burn by \u003Ccode>DAYS_PER_MONTH\u003C/code>, which is exactly \u003Ccode>30.4375\u003C/code>. It then simulates one day at a time. Interest is converted from the annual rate to a daily compound rate:\u003Cbr>\n\u003C/p>\n\n\u003Cdiv class=\"highlight js-code-highlight\">\n\u003Cpre class=\"highlight javascript\">\u003Ccode>\u003Cspan class=\"kd\">const\u003C/span> \u003Cspan class=\"nx\">dailyNetBurn\u003C/span> \u003Cspan class=\"o\">=\u003C/span> \u003Cspan class=\"nx\">netBurn\u003C/span> \u003Cspan class=\"o\">/\u003C/span> \u003Cspan class=\"nx\">DAYS_PER_MONTH\u003C/span>\u003Cspan class=\"p\">;\u003C/span>\n\u003Cspan class=\"kd\">const\u003C/span> \u003Cspan class=\"nx\">dailyRate\u003C/span> \u003Cspan class=\"o\">=\u003C/span> \u003Cspan class=\"nx\">annualRate\u003C/span> \u003Cspan class=\"o\">&gt;\u003C/span> \u003Cspan class=\"mi\">0\u003C/span>\n  \u003Cspan class=\"p\">?\u003C/span> \u003Cspan class=\"nb\">Math\u003C/span>\u003Cspan class=\"p\">.\u003C/span>\u003Cspan class=\"nf\">pow\u003C/span>\u003Cspan class=\"p\">(\u003C/span>\u003Cspan class=\"mi\">1\u003C/span> \u003Cspan class=\"o\">+\u003C/span> \u003Cspan class=\"nx\">annualRate\u003C/span> \u003Cspan class=\"o\">/\u003C/span> \u003Cspan class=\"mi\">100\u003C/span>\u003Cspan class=\"p\">,\u003C/span> \u003Cspan class=\"mi\">1\u003C/span> \u003Cspan class=\"o\">/\u003C/span> \u003Cspan class=\"mi\">365\u003C/span>\u003Cspan class=\"p\">)\u003C/span> \u003Cspan class=\"o\">-\u003C/span> \u003Cspan class=\"mi\">1\u003C/span>\n  \u003Cspan class=\"p\">:\u003C/span> \u003Cspan class=\"mi\">0\u003C/span>\u003Cspan class=\"p\">;\u003C/span>\n\n\u003Cspan class=\"kd\">let\u003C/span> \u003Cspan class=\"nx\">balance\u003C/span> \u003Cspan class=\"o\">=\u003C/span> \u003Cspan class=\"nx\">savings\u003C/span>\u003Cspan class=\"p\">;\u003C/span>\n\u003Cspan class=\"kd\">let\u003C/span> \u003Cspan class=\"nx\">totalDays\u003C/span> \u003Cspan class=\"o\">=\u003C/span> \u003Cspan class=\"mi\">0\u003C/span>\u003Cspan class=\"p\">;\u003C/span>\n\u003Cspan class=\"k\">while \u003C/span>\u003Cspan class=\"p\">(\u003C/span>\u003Cspan class=\"nx\">balance\u003C/span> \u003Cspan class=\"o\">&gt;\u003C/span> \u003Cspan class=\"mi\">0\u003C/span> \u003Cspan class=\"o\">&amp;&amp;\u003C/span> \u003Cspan class=\"nx\">totalDays\u003C/span> \u003Cspan class=\"o\">&lt;\u003C/span> \u003Cspan class=\"mi\">36500\u003C/span>\u003Cspan class=\"p\">)\u003C/span> \u003Cspan class=\"p\">{\u003C/span>\n  \u003Cspan class=\"nx\">balance\u003C/span> \u003Cspan class=\"o\">=\u003C/span> \u003Cspan class=\"nx\">balance\u003C/span> \u003Cspan class=\"o\">*\u003C/span> \u003Cspan class=\"p\">(\u003C/span>\u003Cspan class=\"mi\">1\u003C/span> \u003Cspan class=\"o\">+\u003C/span> \u003Cspan class=\"nx\">dailyRate\u003C/span>\u003Cspan class=\"p\">)\u003C/span> \u003Cspan class=\"o\">-\u003C/span> \u003Cspan class=\"nx\">dailyNetBurn\u003C/span>\u003Cspan class=\"p\">;\u003C/span>\n  \u003Cspan class=\"nx\">totalDays\u003C/span> \u003Cspan class=\"o\">+=\u003C/span> \u003Cspan class=\"mi\">1\u003C/span>\u003Cspan class=\"p\">;\u003C/span>\n\u003Cspan class=\"p\">}\u003C/span>\n\u003C/code>\u003C/pre>\n\u003Cdiv class=\"highlight__panel js-actions-panel\">\n\u003Cdiv class=\"highlight__panel-action js-fullscreen-code-action\">\n    \u003Csvg xmlns=\"http://www.w3.org/2000/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-on\">\u003Ctitle>Enter fullscreen mode\u003C/title>\n    \u003Cpath d=\"M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z\">\u003C/path>\n\u003C/svg>\n\n    \u003Csvg xmlns=\"http://www.w3.org/2000/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-off\">\u003Ctitle>Exit fullscreen mode\u003C/title>\n    \u003Cpath d=\"M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z\">\u003C/path>\n\u003C/svg>\n\n\u003C/div>\n\u003C/div>\n\u003C/div>\n\n\n\n\u003Cp>Applying growth before that day's burn gives the balance a small amount of interest before expenses leave it. The loop stops once the balance is no longer positive or after 36,500 days, a defensive ten-year ceiling. The displayed runway converts the resulting days back into months and days using the same 30.4375 average. This is more honest than pretending every month has 30 days, but it is still an average: rent due dates, quarterly bills, and leap years are not modeled individually.\u003C/p>\n\n\u003Cp>The zero date is calculated by adding the rounded simulated days to \u003Ccode>Date.now()\u003C/code>. Treat it as a planning marker, not a promised payday. A real account may earn interest monthly, pay bills on different dates, or receive a severance payment that belongs in transition income.\u003C/p>\n\n\u003Ch2>\n  \u003Ca name=\"the-monthly-preview-is-a-second-bounded-view\" href=\"#the-monthly-preview-is-a-second-bounded-view\">\n  \u003C/a>\n  The monthly preview is a second, bounded view\n\u003C/h2>\n\n\u003Cp>The result also builds \u003Ccode>balanceRows\u003C/code> for a monthly preview. It uses a monthly rate and applies interest before subtracting the same monthly burn:\u003Cbr>\n\u003C/p>\n\n\u003Cdiv class=\"highlight js-code-highlight\">\n\u003Cpre class=\"highlight javascript\">\u003Ccode>\u003Cspan class=\"kd\">const\u003C/span> \u003Cspan class=\"nx\">monthlyRate\u003C/span> \u003Cspan class=\"o\">=\u003C/span> \u003Cspan class=\"nf\">cleanNumber\u003C/span>\u003Cspan class=\"p\">(\u003C/span>\u003Cspan class=\"nx\">scenario\u003C/span>\u003Cspan class=\"p\">.\u003C/span>\u003Cspan class=\"nx\">annualRate\u003C/span>\u003Cspan class=\"p\">)\u003C/span> \u003Cspan class=\"o\">/\u003C/span> \u003Cspan class=\"mi\">100\u003C/span> \u003Cspan class=\"o\">/\u003C/span> \u003Cspan class=\"mi\">12\u003C/span>\u003Cspan class=\"p\">;\u003C/span>\n\u003Cspan class=\"kd\">let\u003C/span> \u003Cspan class=\"nx\">balance\u003C/span> \u003Cspan class=\"o\">=\u003C/span> \u003Cspan class=\"nx\">savings\u003C/span>\u003Cspan class=\"p\">;\u003C/span>\n\u003Cspan class=\"kd\">const\u003C/span> \u003Cspan class=\"nx\">maxMonths\u003C/span> \u003Cspan class=\"o\">=\u003C/span> \u003Cspan class=\"nb\">Math\u003C/span>\u003Cspan class=\"p\">.\u003C/span>\u003Cspan class=\"nf\">min\u003C/span>\u003Cspan class=\"p\">(\u003C/span>\u003Cspan class=\"mi\">36\u003C/span>\u003Cspan class=\"p\">,\u003C/span>\n  \u003Cspan class=\"nb\">Math\u003C/span>\u003Cspan class=\"p\">.\u003C/span>\u003Cspan class=\"nf\">max\u003C/span>\u003Cspan class=\"p\">(\u003C/span>\u003Cspan class=\"mi\">1\u003C/span>\u003Cspan class=\"p\">,\u003C/span> \u003Cspan class=\"nb\">Math\u003C/span>\u003Cspan class=\"p\">.\u003C/span>\u003Cspan class=\"nf\">ceil\u003C/span>\u003Cspan class=\"p\">((\u003C/span>\u003Cspan class=\"nx\">totalDays\u003C/span> \u003Cspan class=\"o\">||\u003C/span> \u003Cspan class=\"mi\">0\u003C/span>\u003Cspan class=\"p\">)\u003C/span> \u003Cspan class=\"o\">/\u003C/span> \u003Cspan class=\"nx\">DAYS_PER_MONTH\u003C/span>\u003Cspan class=\"p\">)));\u003C/span>\n\u003Cspan class=\"k\">for \u003C/span>\u003Cspan class=\"p\">(\u003C/span>\u003Cspan class=\"kd\">let\u003C/span> \u003Cspan class=\"nx\">month\u003C/span> \u003Cspan class=\"o\">=\u003C/span> \u003Cspan class=\"mi\">1\u003C/span>\u003Cspan class=\"p\">;\u003C/span> \u003Cspan class=\"nx\">month\u003C/span> \u003Cspan class=\"o\">&lt;=\u003C/span> \u003Cspan class=\"nx\">maxMonths\u003C/span>\u003Cspan class=\"p\">;\u003C/span> \u003Cspan class=\"nx\">month\u003C/span>\u003Cspan class=\"o\">++\u003C/span>\u003Cspan class=\"p\">)\u003C/span> \u003Cspan class=\"p\">{\u003C/span>\n  \u003Cspan class=\"nx\">balance\u003C/span> \u003Cspan class=\"o\">=\u003C/span> \u003Cspan class=\"nb\">Math\u003C/span>\u003Cspan class=\"p\">.\u003C/span>\u003Cspan class=\"nf\">max\u003C/span>\u003Cspan class=\"p\">(\u003C/span>\u003Cspan class=\"mi\">0\u003C/span>\u003Cspan class=\"p\">,\u003C/span> \u003Cspan class=\"nx\">balance\u003C/span> \u003Cspan class=\"o\">*\u003C/span> \u003Cspan class=\"p\">(\u003C/span>\u003Cspan class=\"mi\">1\u003C/span> \u003Cspan class=\"o\">+\u003C/span> \u003Cspan class=\"nx\">monthlyRate\u003C/span>\u003Cspan class=\"p\">)\u003C/span> \u003Cspan class=\"o\">-\u003C/span> \u003Cspan class=\"nx\">netBurn\u003C/span>\u003Cspan class=\"p\">);\u003C/span>\n  \u003Cspan class=\"nx\">balanceRows\u003C/span>\u003Cspan class=\"p\">.\u003C/span>\u003Cspan class=\"nf\">push\u003C/span>\u003Cspan class=\"p\">({\u003C/span> \u003Cspan class=\"nx\">month\u003C/span>\u003Cspan class=\"p\">,\u003C/span> \u003Cspan class=\"nx\">balance\u003C/span> \u003Cspan class=\"p\">});\u003C/span>\n  \u003Cspan class=\"k\">if \u003C/span>\u003Cspan class=\"p\">(\u003C/span>\u003Cspan class=\"nx\">balance\u003C/span> \u003Cspan class=\"o\">&lt;=\u003C/span> \u003Cspan class=\"mi\">0\u003C/span>\u003Cspan class=\"p\">)\u003C/span> \u003Cspan class=\"k\">break\u003C/span>\u003Cspan class=\"p\">;\u003C/span>\n\u003Cspan class=\"p\">}\u003C/span>\n\u003C/code>\u003C/pre>\n\u003Cdiv class=\"highlight__panel js-actions-panel\">\n\u003Cdiv class=\"highlight__panel-action js-fullscreen-code-action\">\n    \u003Csvg xmlns=\"http://www.w3.org/2000/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-on\">\u003Ctitle>Enter fullscreen mode\u003C/title>\n    \u003Cpath d=\"M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z\">\u003C/path>\n\u003C/svg>\n\n    \u003Csvg xmlns=\"http://www.w3.org/2000/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-off\">\u003Ctitle>Exit fullscreen mode\u003C/title>\n    \u003Cpath d=\"M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z\">\u003C/path>\n\u003C/svg>\n\n\u003C/div>\n\u003C/div>\n\u003C/div>\n\n\n\n\u003Cp>This can differ slightly from the daily answer because it is a monthly summary with a monthly rate, not a replay of every daily balance. The 36-month cap keeps the page readable and avoids pretending a long-horizon projection is precise. If the daily calculation says 14 months, the preview stops around that point; if a balance lasts longer, the preview intentionally shows only the first three years.\u003C/p>\n\n\u003Cp>The two views answer slightly different questions. The daily loop is the source for the runway duration and zero date, while the rows are a communication layer for scanning how the balance changes month by month. That separation is useful when building a financial UI: a chart should not quietly become a second, conflicting calculator. If I changed the month preview to drive the headline number, I would also have to decide how to reconcile daily interest, bill timing, and the fractional average month.\u003C/p>\n\n\u003Ch2>\n  \u003Ca name=\"scenarios-are-saved-locally-so-assumptions-can-evolve\" href=\"#scenarios-are-saved-locally-so-assumptions-can-evolve\">\n  \u003C/a>\n  Scenarios are saved locally so assumptions can evolve\n\u003C/h2>\n\n\u003Cp>The page supports adding, duplicating, deleting, clearing, and switching scenarios. A watcher serializes the scenario array to \u003Ccode>begoodtool_noIncomeRunwayCalculator_v1\u003C/code> in \u003Ccode>localStorage\u003C/code>, and the comparison table runs the same calculation for every scenario. That makes “what if I cut rent?” a side-by-side change rather than a memory exercise. A useful walkthrough is to duplicate a baseline, set income to zero in one copy, then reduce living costs in another; the table exposes which assumption actually moves the zero date.\u003C/p>\n\n\u003Cp>Important edges remain: positive cash flow is reported as indefinite, a zero-savings positive-burn case is zero days, annual taxes must be translated into a monthly bucket, and changing devices loses local scenarios. I turned this scenario model into a small free tool: \u003Ca href=\"https://begoodtool.com/no-income-runway-calculator/en\" target=\"_blank\" rel=\"noopener noreferrer\">No-Income Runway Calculator\u003C/a>.\u003C/p>\n\n","When someone asks “how many months can I live without a salary?”, dividing savings by monthly expenses gives a useful first guess, but it hides two decisions: which expenses are essential and what happens to income during the transition. I built this calculator around explicit scenarios so a cautious budget and a current-lifestyle budget can be compared instead of blended into one optimistic number. This is aimed at anyone planning a resignation, layoff buffer, or career break and wanting to understand the model rather than trust one impressive number.\r\n\r\n## Net burn is the quantity that matters\r\n\r\nEach scenario has savings, transition income, an annual savings rate, and four expense buckets: rent or mortgage, living costs, insurance, and other essentials. The calculation sums expenses, subtracts income, then clamps negative burn to zero:\r\n\r\n```js\r\nconst monthlyExpense = cleanNumber(clean.rent)\r\n  + cleanNumber(clean.living)\r\n  + cleanNumber(clean.insurance)\r\n  + cleanNumber(clean.other);\r\nconst rawNetBurn = monthlyExpense - income;\r\nconst netBurn = Math.max(0, rawNetBurn);\r\n```\r\n\r\nSuppose the four buckets total 50,000 and temporary income is 12,000. The model calls the burn 38,000 per month. If income is 55,000, `rawNetBurn` is negative, but `netBurn` becomes zero. The result is labeled theoretically indefinite rather than claiming that savings become infinite. That distinction matters: a zero modeled burn means this particular set of assumptions does not consume the starting savings; it does not mean the person's life has no expenses.\r\n\r\nEvery numeric field passes through `cleanNumber`, which turns non-finite or non-positive values into zero. Annual rate is also capped at 100 percent. Those choices make pasted blanks and malformed input safe, but they also mean a typo can silently become zero. I would still review the displayed monthly expense before using the result for a real decision.\r\n\r\n## Daily simulation and the 30.4375-day compromise\r\n\r\nFor a finite runway, the component divides monthly net burn by `DAYS_PER_MONTH`, which is exactly `30.4375`. It then simulates one day at a time. Interest is converted from the annual rate to a daily compound rate:\r\n\r\n```js\r\nconst dailyNetBurn = netBurn / DAYS_PER_MONTH;\r\nconst dailyRate = annualRate > 0\r\n  ? Math.pow(1 + annualRate / 100, 1 / 365) - 1\r\n  : 0;\r\n\r\nlet balance = savings;\r\nlet totalDays = 0;\r\nwhile (balance > 0 && totalDays \u003C 36500) {\r\n  balance = balance * (1 + dailyRate) - dailyNetBurn;\r\n  totalDays += 1;\r\n}\r\n```\r\n\r\nApplying growth before that day's burn gives the balance a small amount of interest before expenses leave it. The loop stops once the balance is no longer positive or after 36,500 days, a defensive ten-year ceiling. The displayed runway converts the resulting days back into months and days using the same 30.4375 average. This is more honest than pretending every month has 30 days, but it is still an average: rent due dates, quarterly bills, and leap years are not modeled individually.\r\n\r\nThe zero date is calculated by adding the rounded simulated days to `Date.now()`. Treat it as a planning marker, not a promised payday. A real account may earn interest monthly, pay bills on different dates, or receive a severance payment that belongs in transition income.\r\n\r\n## The monthly preview is a second, bounded view\r\n\r\nThe result also builds `balanceRows` for a monthly preview. It uses a monthly rate and applies interest before subtracting the same monthly burn:\r\n\r\n```js\r\nconst monthlyRate = cleanNumber(scenario.annualRate) / 100 / 12;\r\nlet balance = savings;\r\nconst maxMonths = Math.min(36,\r\n  Math.max(1, Math.ceil((totalDays || 0) / DAYS_PER_MONTH)));\r\nfor (let month = 1; month \u003C= maxMonths; month++) {\r\n  balance = Math.max(0, balance * (1 + monthlyRate) - netBurn);\r\n  balanceRows.push({ month, balance });\r\n  if (balance \u003C= 0) break;\r\n}\r\n```\r\n\r\nThis can differ slightly from the daily answer because it is a monthly summary with a monthly rate, not a replay of every daily balance. The 36-month cap keeps the page readable and avoids pretending a long-horizon projection is precise. If the daily calculation says 14 months, the preview stops around that point; if a balance lasts longer, the preview intentionally shows only the first three years.\r\n\r\nThe two views answer slightly different questions. The daily loop is the source for the runway duration and zero date, while the rows are a communication layer for scanning how the balance changes month by month. That separation is useful when building a financial UI: a chart should not quietly become a second, conflicting calculator. If I changed the month preview to drive the headline number, I would also have to decide how to reconcile daily interest, bill timing, and the fractional average month.\r\n\r\n## Scenarios are saved locally so assumptions can evolve\r\n\r\nThe page supports adding, duplicating, deleting, clearing, and switching scenarios. A watcher serializes the scenario array to `begoodtool_noIncomeRunwayCalculator_v1` in `localStorage`, and the comparison table runs the same calculation for every scenario. That makes “what if I cut rent?” a side-by-side change rather than a memory exercise. A useful walkthrough is to duplicate a baseline, set income to zero in one copy, then reduce living costs in another; the table exposes which assumption actually moves the zero date.\r\n\r\nImportant edges remain: positive cash flow is reported as indefinite, a zero-savings positive-burn case is zero days, annual taxes must be translated into a monthly bucket, and changing devices loses local scenarios. I turned this scenario model into a small free tool: [No-Income Runway Calculator](https://begoodtool.com/no-income-runway-calculator/en).",{"name":30,"username":31,"twitter_username":14,"github_username":14,"user_id":32,"website_url":33,"profile_image":34,"profile_image_90":35},"Joe Lin","yuntao_lin",4066889,"https://begoodtool.com/home/en","https://media2.dev.to/dynamic/image/width=640,height=640,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4066889%2Fcbfd5bde-d893-4635-97d5-aea05722cb26.jpeg","https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4066889%2Fcbfd5bde-d893-4635-97d5-aea05722cb26.jpeg",{"name":37,"username":38,"slug":38,"profile_image":39,"profile_image_90":40},"BeGoodTool.com","begoodtool","https://media2.dev.to/dynamic/image/width=640,height=640,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F14295%2Fd519278f-433a-4dab-9489-447ef51fc6d4.jpg","https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F14295%2Fd519278f-433a-4dab-9489-447ef51fc6d4.jpg",1788921586542]