Skip to content

Instantly share code, notes, and snippets.

View jamesplease's full-sized avatar
🍕
yum

James Please jamesplease

🍕
yum
  • USA
View GitHub Profile

FI Calc 2.0

Three years ago I released FI Calc ( https://ficalc.app ), a free retirement calculator: . In this time FI Calc has become one of the most-relied-upon retirement calculators in the FIRE community.

I just launched the biggest overhaul of the app since it launched, which I’m calling version 2.0. The app continues to be free, and there are a ton of new features that I wanted to share with you.

Going beyond Success Rate

Many calculators focus on the success rate. FI Calc 2.0 provides 5 additional qualities that provide you with a more thorough analysis of your retirement plan:

if (changeInY > 0 && restraints.down !== null) {
const dampFactor =
1 -
linearScale({
domain: [0, restraints.down * 2],
range: [0, 0.5],
value: changeInY,
});
let dampedChangeInY = changeInY * dampFactor;
// The function
function subscribe(promises, cb) {
let result = Array.from({ length: promises.length }).fill(null);
promises.forEach((promise, index) => {
promise.then(val => {
const clonedResult = [...result];
clonedResult[index] = val;
cb(clonedResult);
result = clonedResult;
{
// The value that the Promise resolved or rejected to
value: any,
// `true` when the Promise has either resolved or rejected
complete: Boolean,
// `true` until the Promise resolves or rejects
pending: Boolean,
// `true` when the Promise is resolved
let statusTooltip;
if (processStatus.processing) {
statusTooltip = 'Processing';
} else if (processStatus.processed) {
statusTooltip = 'Processed';
} else if (processStatus.error) {
statusTooltip = 'Error';
}
accent-height
additive
alignment-baseline
allowReorder
alphabetic
amplitude
arabic-form
ascent
attributeName
attributeType
import rotation from "./rotation";
const coordinatesMap = {
"top-left": [0, 0],
top: [0.5, 0],
"top-right": [1, 0],
left: [0, 0.5],
center: [0.5, 0.5],
right: [1, 0.5],
"bottom-left": [0, 1],
function adjustedBoundingBox(boundingBox) {
const overflowTop = Math.min(boundingBox.top, 0);
const overflowLeft = Math.min(boundingBox.left, 0);
const overflowRight = Math.min(window.innerWidth - boundingBox.right, 0);
const overflowBottom = Math.min(window.innerHeight - boundingBox.bottom, 0);
return {
top: Math.max(boundingBox.top, 0),
left: Math.max(boundingBox.left, 0),
height: boundingBox.height + overflowTop + overflowBottom,
positionMap(coordinates, tileHeight, tileWidth) {
// At (0, 0), where do we render? It is as these coordinates.
const initialX = tileWidth / 2;
const initialY = tileHeight / 2;
const xPositionFromX = coordinates.x * (tileWidth);
const xPositionFromY = coordinates.y * (-tileWidth);
const yPositionFromX = coordinates.x * (-tileHeight);
const yPositionFromY = coordinates.y * (-tileHeight);
<MergeProvider value={{ movieId: 2000 }}>
<MergeProvider value={{ countryCode: 'US' }}>
<MergeProvider value={{ languageCode: 'en' }}>
<MergeConsumer>
{(val) => {
console.log('Got the value', val);
// {
// movieId: 2000,
// countryCode: 'US',
// languageCode: 'en'