Front-load strategy mode: pocket 50% until L6, then 25% (near-identical arrival to flat 25%, ~double the early draw)
- pocketPctFor(): per-phase pocket resolution ('frontload' sentinel); computePlan/boostSim/plan-text/summary-card all honor it
- strategy select + share param mode=frontload + Sponsor Guide entry
- tests 7b: frontload matches 50%-behavior below L6 and 25%-behavior from L6, total <= flat-50
This commit is contained in:
+24
-13
@@ -1256,6 +1256,7 @@
|
||||
<select id="strategyMode">
|
||||
<option value="accelerate" selected>🚀 Accelerate — reinvest everything, fastest to 3× L7</option>
|
||||
<option value="pocket">💰 Pocket along the way — keep part of each profit</option>
|
||||
<option value="frontload">⚡ Front-load — pocket 50% until L6, then 25% (same arrival as flat 25%)</option>
|
||||
<option value="park">🏝 Park & collect — stop at a level, pocket it all</option>
|
||||
</select>
|
||||
</div>
|
||||
@@ -1511,6 +1512,7 @@
|
||||
<p style="margin:6px 0 0;font-size:0.88rem;line-height:1.5;">
|
||||
<strong>🚀 Accelerate</strong> (default): every profit reinvests — fastest path to 3× L7. Best for people who want the endgame and don't need cash along the way.<br>
|
||||
<strong>💰 Pocket along the way</strong>: they keep 25/50/75% of each cycle's profit as spending money and bank the rest. The climb honestly slows down — the timeline and tables update to show it — but they see real money the whole way. Best for people who need proof it pays before they trust the climb.<br>
|
||||
<strong>⚡ Front-load</strong>: pocket 50% of each cycle until L6, then tighten to 25% for the expensive late jumps. Because early upgrades are funded by the payout roll anyway, this arrives at 3× L7 on nearly the same date as flat 25% while paying roughly double during the early grind — usually the best effort-to-reward line for someone actively working the clicks. The share link remembers this choice too.<br>
|
||||
<strong>🏝 Park & collect</strong>: stop at a level on purpose and pocket the whole profit every cycle (e.g. L4+L3 ≈ $213/mo). Best for tight budgets who may never fund an L7 — and you still earn your 10% on every one of their cycles, forever.<br>
|
||||
The share link remembers the strategy, so the plan they open is the plan you chose for them.
|
||||
</p>
|
||||
@@ -1608,9 +1610,16 @@ const PHASE_SLOTS = {
|
||||
'L5+L4': [5, 4], 'L6': [6], 'L7': [7], '3xL7': [7, 7, 7],
|
||||
};
|
||||
|
||||
// pocketPct: number (flat) or the string 'frontload' = 50% below L6, 25%
|
||||
// from L6 up (Marty 2026-07-31: take the money early when thresholds are
|
||||
// cheap, tighten for the expensive late jumps — same arrival as flat 25%).
|
||||
function pocketPctFor(pocketPct, phaseKey) {
|
||||
if (pocketPct !== 'frontload') return pocketPct;
|
||||
return Math.max(...PHASE_SLOTS[phaseKey]) >= 6 ? 25 : 50;
|
||||
}
|
||||
|
||||
function computePlan(phases, pocketPct = 0) {
|
||||
const plan = {};
|
||||
const keepFrac = 1 - pocketPct / 100;
|
||||
let bal = 0;
|
||||
const activated = new Set();
|
||||
for (let lv = 1; lv <= Math.max(...PHASE_SLOTS[phases[0]]); lv++) activated.add(lv);
|
||||
@@ -1640,7 +1649,7 @@ function computePlan(phases, pocketPct = 0) {
|
||||
while (cycles < 500) {
|
||||
cycles++;
|
||||
if (bal + p.payout - carriedCamp >= cost) { bal += p.payout - carriedCamp - cost; break; }
|
||||
bal += p.profit * keepFrac;
|
||||
bal += p.profit * (1 - pocketPctFor(pocketPct, k) / 100);
|
||||
}
|
||||
plan[k] = { cycles, months: Math.round(cycles * p.daysPer / 30.4 * 10) / 10 };
|
||||
}
|
||||
@@ -1679,7 +1688,6 @@ function laneStats(lanes) {
|
||||
// Simulate from an arbitrary lane set + starting reserve to 3×L7.
|
||||
// Mirrors computePlan's rules exactly; capped for safety.
|
||||
function boostSim(startLanes, bal0, pocketPct = 0) {
|
||||
const keepFrac = 1 - pocketPct / 100;
|
||||
let lanes = [...startLanes].sort((a, b) => b - a);
|
||||
let bal = bal0;
|
||||
let cycles = 0;
|
||||
@@ -1709,7 +1717,7 @@ function boostSim(startLanes, bal0, pocketPct = 0) {
|
||||
while (spin++ < 500) {
|
||||
cycles++;
|
||||
if (bal + s.payout - carriedCamp >= cost) { bal += s.payout - carriedCamp - cost; break; }
|
||||
bal += s.profit * keepFrac;
|
||||
bal += s.profit * (1 - (pocketPct === 'frontload' ? (Math.max(...lanes) >= 6 ? 25 : 50) : pocketPct) / 100);
|
||||
}
|
||||
lanes = targetSlots.sort((a, b) => b - a);
|
||||
path.push(targetKey);
|
||||
@@ -1792,6 +1800,7 @@ function renderBoost(phaseKey, mode, pocketPct) {
|
||||
'Activation is charged once per level; unspent cash goes into reserves either way. ' +
|
||||
(mode === 'park' ? 'Shown on the climb-to-endgame basis; if you park, the best combo is simply the highest profit/cycle you can afford.' :
|
||||
mode === 'pocket' ? `Simulated with your ${pocketPct}% pocket setting.` :
|
||||
mode === 'frontload' ? 'Simulated with the front-load setting: pocket 50% until L6, then 25%.' :
|
||||
'Simulated in Accelerate mode, same reserve math as the rest of the calculator.');
|
||||
}
|
||||
|
||||
@@ -1901,7 +1910,8 @@ function updateAll() {
|
||||
const selfLevel = parseInt(document.getElementById('selfFundLevel').value);
|
||||
const showRef = document.getElementById('showReferral').checked;
|
||||
const mode = document.getElementById('strategyMode').value;
|
||||
const pocketPct = mode === 'pocket' ? (parseInt(document.getElementById('pocketPct').value) || 50) : 0;
|
||||
const pocketPct = mode === 'pocket' ? (parseInt(document.getElementById('pocketPct').value) || 50)
|
||||
: mode === 'frontload' ? 'frontload' : 0;
|
||||
document.getElementById('pocketPctGroup').style.display = mode === 'pocket' ? '' : 'none';
|
||||
document.getElementById('parkPhaseGroup').style.display = mode === 'park' ? '' : 'none';
|
||||
|
||||
@@ -1935,7 +1945,7 @@ function updateAll() {
|
||||
const endCutPerCycle = PI[endKey].parked ? PI[endKey].payout * (commPct / 100) : THREE_L7_YOUR_CUT * mult;
|
||||
const monthlyPassive = Math.round(endCutPerCycle * 30.4 / 19 * numPeople);
|
||||
const pocketedTotal = Math.round(phases.filter(k => k !== '3xL7' && !PI[k].parked)
|
||||
.reduce((s, k) => s + PI[k].profit * (pocketPct / 100) * PI[k].cycles, 0));
|
||||
.reduce((s, k) => s + PI[k].profit * (pocketPctFor(pocketPct, k) / 100) * PI[k].cycles, 0));
|
||||
|
||||
let totalToEGPerPerson = 0;
|
||||
for (const k of phases) {
|
||||
@@ -1980,11 +1990,11 @@ function updateAll() {
|
||||
<div class="label">${mode === 'park' ? 'Time to Park Level' : 'Time to 3× L7'}</div>
|
||||
<div class="value orange" style="font-size:1.3rem">~${totalMonths} months</div>
|
||||
</div>
|
||||
${mode === 'pocket' ? `
|
||||
${(mode === 'pocket' || mode === 'frontload') ? `
|
||||
<div class="summary-card">
|
||||
<div class="label">Pocketed Along the Way</div>
|
||||
<div class="value yellow">$${pocketedTotal.toLocaleString()}</div>
|
||||
<div class="sub">${pocketPct}% of each cycle's profit</div>
|
||||
<div class="sub">${pocketPct === 'frontload' ? "50% early, 25% from L6" : pocketPct + "% of each cycle's profit"}</div>
|
||||
</div>` : ''}
|
||||
${mode === 'park' ? `
|
||||
<div class="summary-card">
|
||||
@@ -2307,7 +2317,7 @@ document.querySelectorAll('.tab-btn').forEach(btn => {
|
||||
if (el && [...el.options].some(o => o.value === self)) el.value = self;
|
||||
}
|
||||
const mode = p.get('mode');
|
||||
if (mode === 'pocket' || mode === 'park') {
|
||||
if (mode === 'pocket' || mode === 'frontload' || mode === 'park') {
|
||||
document.getElementById('strategyMode').value = mode;
|
||||
const pk = p.get('pk');
|
||||
if (pk && [...document.getElementById('pocketPct').options].some(o => o.value === pk))
|
||||
@@ -2453,8 +2463,8 @@ function phasePlanLine(k, i, PI, mode, pocketPct) {
|
||||
return `**Phase ${i + 1}: ${p.label} — PARK HERE** 🏝\nRun these campaigns on repeat, every ~19 days, and pocket the ~$${p.profit.toFixed(2)} profit each cycle — about $${perMo.toLocaleString()}/month of spending money for a few minutes of clicking a day. No more reinvesting, no more climbing. This is your income level.`;
|
||||
}
|
||||
const base = `**Phase ${i + 1}: ${p.label}**\n${p.cycles} cycles, ~${p.months} months — $${p.payout.toFixed(2)}/cycle payout`;
|
||||
if (mode === 'pocket') {
|
||||
const pk = p.profit * pocketPct / 100;
|
||||
if (mode === 'pocket' || mode === 'frontload') {
|
||||
const pk = p.profit * pocketPctFor(pocketPct, k) / 100;
|
||||
const totalPk = Math.round(pk * p.cycles * 100) / 100;
|
||||
return `${base}\nPocket ~$${pk.toFixed(2)} of each cycle's ~$${p.profit.toFixed(2)} profit (about $${totalPk.toFixed(2)} in your pocket across this phase) and bank the rest toward the next level. The timeline above already accounts for the slower climb.`;
|
||||
}
|
||||
@@ -2471,7 +2481,8 @@ function generatePlan() {
|
||||
const selfCost = getLevelCost(selfLevel);
|
||||
const effective = getEffectiveStart(giftLevel, selfLevel);
|
||||
const mode = document.getElementById('strategyMode').value;
|
||||
const pocketPct = mode === 'pocket' ? (parseInt(document.getElementById('pocketPct').value) || 50) : 0;
|
||||
const pocketPct = mode === 'pocket' ? (parseInt(document.getElementById('pocketPct').value) || 50)
|
||||
: mode === 'frontload' ? 'frontload' : 0;
|
||||
let phases = getPhaseSequence(effective);
|
||||
if (mode === 'park') phases = phases.slice(0, phases.indexOf(document.getElementById('parkPhase').value) + 1);
|
||||
const PI = phaseInfo(phases, pocketPct);
|
||||
@@ -2479,7 +2490,7 @@ function generatePlan() {
|
||||
const totalMonths = estimateMonths(phases, pocketPct);
|
||||
const endgameBlock = PI[endKey].parked
|
||||
? `**The destination: ${PI[endKey].label}** 🏝\nYou stop climbing here on purpose — roughly $${Math.round(HYBRIDS[endKey].profit * 30.4 / 19).toLocaleString()}/month pocketed, indefinitely, for a few minutes of clicking a day. (Want more later? The calculator link above shows the full climb to 3× L7 whenever you're ready.)`
|
||||
: `**Phase ${phases.filter(x => x !== '3xL7').length + 1}: 3× L7 Endgame** 🎯\nAll three L7 campaigns running at once\n$9,720.00/cycle payout → ~$4,032/month${mode === 'pocket' ? ' — and from here it is ALL pocket money' : ' passive'}\nThis is the finish line${mode === 'pocket' ? `\n\n(CBP has a $10 minimum withdrawal and a 10% fee on external-wallet withdrawals — pocketed money accumulates in your balance until you cash out.)` : ''}`;
|
||||
: `**Phase ${phases.filter(x => x !== '3xL7').length + 1}: 3× L7 Endgame** 🎯\nAll three L7 campaigns running at once\n$9,720.00/cycle payout → ~$4,032/month${(mode === 'pocket' || mode === 'frontload') ? ' — and from here it is ALL pocket money' : ' passive'}\nThis is the finish line${(mode === 'pocket' || mode === 'frontload') ? `\n\n(CBP has a $10 minimum withdrawal and a 10% fee on external-wallet withdrawals — pocketed money accumulates in your balance until you cash out.)` : ''}`;
|
||||
const roadmapHeading = PI[endKey].parked
|
||||
? `Your roadmap to ~$${Math.round(HYBRIDS[endKey].profit * 30.4 / 19).toLocaleString()}/month pocket income:`
|
||||
: `Your full roadmap to $4,032/month:`;
|
||||
|
||||
@@ -135,6 +135,23 @@ console.log("7) strategy modes:");
|
||||
check("parked timeline runs 10 collection cycles", tl.length === 10);
|
||||
}
|
||||
|
||||
console.log("7b) Front-load strategy (pocket 50% until L6, then 25%):");
|
||||
{
|
||||
const phases = getPhaseSequence(0);
|
||||
const fl = computePlan(phases, "frontload");
|
||||
const p25 = computePlan(phases, 25);
|
||||
const p50 = computePlan(phases, 50);
|
||||
for (const k of phases) {
|
||||
if (k === "3xL7") continue;
|
||||
const isLate = Math.max(...PHASE_SLOTS[k]) >= 6;
|
||||
const want = isLate ? p25[k].cycles : p50[k].cycles;
|
||||
check(`frontload ${k} = ${isLate ? "25%" : "50%"} behavior (${fl[k].cycles}cy)`,
|
||||
fl[k].cycles === want, `want ${want}`);
|
||||
}
|
||||
const total = (plan) => phases.reduce((s, k) => s + plan[k].cycles, 0);
|
||||
check(`frontload total ${total(fl)} <= flat-50 total ${total(p50)}`, total(fl) <= total(p50));
|
||||
}
|
||||
|
||||
console.log("8) Boost Planner (extra-funds combos, Marty 2026-07-31):");
|
||||
{
|
||||
// 8a. boostSim with $0 extra must agree with computePlan for every start.
|
||||
|
||||
Reference in New Issue
Block a user