ONLINE
setTimeout( function() { var bot = document.getElementById( "dlcFloatingBot" ); if (!bot) { return; } bot.addEventListener( "click", function() { var status = this.querySelector( "small" ); if (!status) { return; } if ( status.textContent .trim() === "ONLINE" ) { status.textContent = "HELLO 👋"; } else { status.textContent = "ONLINE"; } } ); }, 700 ); setTimeout(function () { var bot = document.getElementById( "dlcFloatingBot" ); if (!bot) { return; } /* IMPORTANT: Move the bot outside Carrd's page/container structure and attach it directly to BODY. */ document.body.appendChild(bot); bot.style.setProperty( "position", "fixed", "important" ); bot.style.setProperty( "right", "14px", "important" ); bot.style.setProperty( "bottom", "18px", "important" ); bot.style.setProperty( "left", "auto", "important" ); bot.style.setProperty( "top", "auto", "important" ); bot.style.setProperty( "z-index", "999999", "important" ); }, 1200);
Z z z
💭 THINKING...
(function(){ var bot = document.getElementById( "dlcFloatingBot" ); var menu = document.getElementById( "dlcBotMenu" ); var zzz = document.getElementById( "dlcBotZZZ" ); var thought = document.getElementById( "dlcBotThought" ); if( !bot || !menu || !zzz || !thought ){ return; } /* move extras outside Carrd containers */ document.body.appendChild(menu); document.body.appendChild(zzz); document.body.appendChild(thought); /* ========================= STATE ========================= */ var sleeping = false; var menuOpen = false; var direction = -1; var paused = false; var pauseUntil = 0; var pauseType = ""; var centreUsed = false; /* Movement speed. Smaller = slower. 0.025 is deliberately much calmer than before. */ var speed = 0.025; var botRect = bot.getBoundingClientRect(); var x = botRect.left; if( !x || x < 8 ){ x = window.innerWidth - (bot.offsetWidth || 88) - 14; } bot.style.setProperty( "right", "auto", "important" ); bot.style.setProperty( "left", x + "px", "important" ); /* ========================= HELPERS ========================= */ function statusText(text){ var status = bot.querySelector( "small" ); if(status){ status.textContent = text; } } function positionZZZ(){ if(!sleeping){ zzz.style.display = "none"; return; } var r = bot.getBoundingClientRect(); zzz.style.display = "block"; zzz.style.left = ( r.left + r.width / 2 - 27 ) + "px"; zzz.style.top = ( r.top - 27 ) + "px"; } function positionThought(){ if( thought.style.display !== "block" ){ return; } var r = bot.getBoundingClientRect(); var w = thought.offsetWidth || 110; var bx = r.left + r.width / 2 - w / 2; if(bx < 6){ bx = 6; } if( bx + w > window.innerWidth - 6 ){ bx = window.innerWidth - w - 6; } thought.style.left = bx + "px"; thought.style.top = ( r.top - 38 ) + "px"; } /* ========================= MENU POSITION ========================= */ function positionMenu(){ if(!menuOpen){ return; } var r = bot.getBoundingClientRect(); var mw = menu.offsetWidth || 145; var mh = menu.offsetHeight || 225; var mx = r.left + r.width - mw; var my = r.top - mh - 10; if(mx < 6){ mx = 6; } if( mx + mw > window.innerWidth - 6 ){ mx = window.innerWidth - mw - 6; } /* if not enough room above */ if(my < 6){ my = Math.max( 6, r.top ); mx = r.left - mw - 10; if(mx < 6){ mx = r.right + 10; } if( mx + mw > window.innerWidth - 6 ){ mx = window.innerWidth - mw - 6; } } menu.style.left = mx + "px"; menu.style.top = my + "px"; } /* ========================= MENU ========================= */ function closeMenu(){ menuOpen = false; menu.classList.remove( "open" ); } function updateSleepButton(){ var button = menu.querySelector( '[data-action="sleep"]' ); if(!button){ return; } button.textContent = sleeping ? "☀️ Wake Up" : "😴 Sleep"; } bot.addEventListener( "click", function(event){ event.preventDefault(); event.stopPropagation(); menuOpen = !menuOpen; if(menuOpen){ updateSleepButton(); menu.classList.add( "open" ); requestAnimationFrame( positionMenu ); } else{ closeMenu(); } } ); /* ========================= SLEEP ========================= */ function sleepBot(){ sleeping = true; paused = false; thought.style.display = "none"; bot.classList.add( "dlcSleeping" ); statusText( "SLEEPING" ); positionZZZ(); } function wakeBot(){ sleeping = false; bot.classList.remove( "dlcSleeping" ); zzz.style.display = "none"; statusText( "HELLO 👋" ); } /* keep global functions for future features */ window.dlcBotSleep = sleepBot; window.dlcBotWake = wakeBot; window.dlcBotToggleSleep = function(){ if(sleeping){ wakeBot(); } else{ sleepBot(); } }; /* ========================= MENU ACTIONS ========================= */ menu.addEventListener( "click", function(event){ var button = event.target.closest( "[data-action]" ); if(!button){ return; } event.preventDefault(); event.stopPropagation(); var action = button.getAttribute( "data-action" ); /* HOME */ if(action === "home"){ closeMenu(); window.location.hash = ""; window.scrollTo({ top:0, behavior:"smooth" }); return; } /* CHARACTER */ if( action === "character" ){ closeMenu(); window.location.hash = "section08"; return; } /* BRAIN TRAINING */ if(action === "brain"){ closeMenu(); window.location.hash = "section10"; return; } /*NOTES*/ if(action === "notes"){ closeMenu(); window.location.hash = "section11"; return; } /*DRAW*/ if(action === "drawing"){ closeMenu(); window.location.hash = "section12"; return; } /* SLEEP / WAKE */ if(action === "sleep"){ if(sleeping){ wakeBot(); } else{ sleepBot(); } updateSleepButton(); closeMenu(); return; } } ); /* ========================= THINKING PAUSE ========================= */ function startThinking(now){ paused = true; pauseType = "thinking"; pauseUntil = now + 3200; thought.textContent = "💭 THINKING..."; thought.style.display = "block"; statusText( "THINKING" ); positionThought(); } /* ========================= EDGE PAUSE ========================= */ function edgePause(now){ paused = true; pauseType = "edge"; pauseUntil = now + 1100; statusText( "WAITING" ); } /* ========================= MOVEMENT LOOP ========================= */ var previousTime = performance.now(); function animate(now){ var delta = Math.min( now - previousTime, 40 ); previousTime = now; /* SLEEP */ if(sleeping){ positionZZZ(); positionMenu(); requestAnimationFrame( animate ); return; } /* PAUSE */ if(paused){ if( pauseType === "thinking" ){ var remaining = pauseUntil - now; if( remaining < 1700 ){ thought.textContent = "💡 NEED ANYTHING?"; } positionThought(); } if( now >= pauseUntil ){ paused = false; thought.style.display = "none"; statusText( "ONLINE" ); /* If this was an edge pause, turn around AFTER pause. */ if( pauseType === "edge" ){ direction *= -1; centreUsed = false; } pauseType = ""; } positionMenu(); requestAnimationFrame( animate ); return; } /* SCREEN LIMITS */ var width = bot.offsetWidth || 88; var minX = 8; var maxX = window.innerWidth - width - 8; var centre = ( minX + maxX ) / 2; /* MOVE */ x += speed * direction * delta; /* CENTRE THINK */ if( !centreUsed && Math.abs( x - centre ) < 3 ){ x = centre; centreUsed = true; startThinking(now); } /* LEFT EDGE */ else if( x <= minX ){ x = minX; edgePause(now); } /* RIGHT EDGE */ else if( x >= maxX ){ x = maxX; edgePause(now); } bot.style.setProperty( "left", x + "px", "important" ); positionMenu(); requestAnimationFrame( animate ); } requestAnimationFrame( animate ); /* ========================= RESIZE ========================= */ window.addEventListener( "resize", function(){ var maxX = window.innerWidth - (bot.offsetWidth || 88) - 8; if(x > maxX){ x = maxX; } if(x < 8){ x = 8; } positionZZZ(); positionThought(); positionMenu(); } ); })();

Useful Files

My Digital folder

Your everyday tools, organised in one place

💷 Bills tracker

Money Until Payday

Monthly Bills

Total bills: £0.00
Bills already paid: £0.00
Bills still to pay: £0.00
Money left right now
£0.00
Money left after ALL bills
£0.00
const balanceInput = document.getElementById('balance'); const addBillButton = document.getElementById('addBill'); let bills = []; /* ========================= MONEY ========================= */ function money(value){ return '£' + (parseFloat(value) || 0) .toFixed(2); } /* ========================= SAFE TEXT ========================= */ function safeText(value){ return value == null ? '' : String(value); } /* ========================= DATE HELPERS ========================= */ function getDayFromDate(value){ if(!value){ return 0; } const parts = value.split('-'); if(parts.length !== 3){ return 0; } return parseInt( parts[2], 10 ) || 0; } function getWeekNumber(value){ const day = getDayFromDate(value); if(!day){ return 0; } if(day <= 7){ return 1; } if(day <= 14){ return 2; } if(day <= 21){ return 3; } return 4; } function dateForWeek(week){ const today = new Date(); const year = today.getFullYear(); const month = String( today.getMonth() + 1 ).padStart(2,'0'); let day = '01'; if(week === 2){ day = '08'; } if(week === 3){ day = '15'; } if(week === 4){ day = '22'; } return year + '-' + month + '-' + day; } /* ========================= SAVE ========================= */ function saveBudget(){ const data = { balance: balanceInput.value, bills: bills.map( function(bill){ return { id: bill.id, name: bill.name, amount: bill.amount, dueDate: bill.dueDate, paid: bill.paid }; } ) }; localStorage.setItem( 'moneyUntilPaydayBudget', JSON.stringify(data) ); } /* ========================= CALCULATIONS ========================= */ function calculateBudget(){ const balance = parseFloat( balanceInput.value ) || 0; let totalBills = 0; let paidBills = 0; bills.forEach( function(bill){ const amount = parseFloat( bill.amount ) || 0; totalBills += amount; if(bill.paid){ paidBills += amount; } } ); const remainingBills = totalBills - paidBills; /* MONEY AVAILABLE NOW ALREADY EXCLUDES PAID BILLS */ const moneyLeftNow = balance; /* ONLY UNPAID BILLS STILL NEED TO COME OUT */ const moneyLeftAfterAll = balance - remainingBills; document .getElementById('totalBills') .textContent = money(totalBills); document .getElementById('paidBills') .textContent = money(paidBills); document .getElementById('remainingBills') .textContent = money(remainingBills); document .getElementById('moneyLeftNow') .textContent = money(moneyLeftNow); document .getElementById('moneyLeftAfterAll') .textContent = money(moneyLeftAfterAll); } /* ========================= ADD BILL TO WEEK ========================= */ function addBillToWeek(week){ bills.push({ id: 'bill_' + Date.now() + '_' + Math.random() .toString(16) .slice(2), name:'', amount:'', dueDate: dateForWeek(week), paid:false }); saveBudget(); render(); } /* ========================= CREATE BILL ROW ========================= */ function createBillRow(bill){ const row = document.createElement('div'); row.className = 'budgetBillRow'; const top = document.createElement('div'); top.className = 'budgetBillTop'; /* NAME */ const nameInput = document.createElement('input'); nameInput.type = 'text'; nameInput.value = safeText( bill.name ); nameInput.placeholder = 'Bill'; /* AMOUNT */ const amountInput = document.createElement('input'); amountInput.type = 'number'; amountInput.inputMode = 'decimal'; amountInput.step = '0.01'; amountInput.value = safeText( bill.amount ); amountInput.placeholder = '£0'; /* DATE */ const dateInput = document.createElement('input'); dateInput.type = 'date'; dateInput.value = safeText( bill.dueDate ); top.appendChild( nameInput ); top.appendChild( amountInput ); top.appendChild( dateInput ); /* ========================= BOTTOM ROW ========================= */ const bottom = document.createElement('div'); bottom.className = 'budgetBillBottom'; const paidLabel = document.createElement('label'); paidLabel.className = 'budgetPaidLabel'; const paidCheck = document.createElement('input'); paidCheck.type = 'checkbox'; paidCheck.checked = !!bill.paid; paidLabel.appendChild( paidCheck ); paidLabel.appendChild( document.createTextNode( 'Paid' ) ); const removeButton = document.createElement('button'); removeButton.type = 'button'; removeButton.className = 'budgetRemove'; removeButton.textContent = 'Remove'; bottom.appendChild( paidLabel ); bottom.appendChild( removeButton ); row.appendChild( top ); row.appendChild( bottom ); /* ========================= NAME ========================= */ nameInput .addEventListener( 'input', function(){ bill.name = nameInput.value; saveBudget(); } ); /* ========================= AMOUNT ========================= */ amountInput .addEventListener( 'input', function(){ bill.amount = amountInput.value; /* DO NOT RENDER WHILE TYPING DECIMALS */ saveBudget(); calculateBudget(); } ); amountInput .addEventListener( 'blur', function(){ render(); } ); /* ========================= DATE ========================= */ dateInput .addEventListener( 'change', function(){ bill.dueDate = dateInput.value; saveBudget(); render(); } ); /* ========================= PAID / UNPAID ========================= */ paidCheck .addEventListener( 'change', function(){ const amount = parseFloat( bill.amount ) || 0; let balance = parseFloat( balanceInput.value ) || 0; /* MARK AS PAID */ if( paidCheck.checked && !bill.paid ){ balance -= amount; } /* CHANGE BACK TO UNPAID */ else if( !paidCheck.checked && bill.paid ){ balance += amount; } balanceInput.value = balance.toFixed(2); bill.paid = paidCheck.checked; saveBudget(); render(); } ); /* ========================= REMOVE ========================= */ removeButton .addEventListener( 'click', function(){ bills = bills.filter( function(item){ return item.id !== bill.id; } ); saveBudget(); render(); } ); return row; } /* ========================= CREATE WEEK ========================= */ function createWeekBox( week, title, range ){ const section = document.getElementById( 'week' + week ); if(!section){ return; } const weekBills = bills .filter( function(bill){ return getWeekNumber( bill.dueDate ) === week; } ) .sort( function(a,b){ return getDayFromDate( a.dueDate ) - getDayFromDate( b.dueDate ); } ); let total = 0; let paid = 0; weekBills.forEach( function(bill){ const amount = parseFloat( bill.amount ) || 0; total += amount; if(bill.paid){ paid += amount; } } ); const remaining = total - paid; section.innerHTML = ''; const box = document.createElement('div'); box.className = 'budgetWeek'; const header = document.createElement('div'); header.className = 'budgetWeekHeader'; /* ========================= WEEK TITLE ========================= */ const titleLine = document.createElement('div'); titleLine.textContent = title; titleLine.style.cssText = 'display:block;' + 'width:100%;' + 'font-size:20px;' + 'font-weight:bold;' + 'line-height:1.3;' + 'margin-bottom:5px;'; /* ========================= DATE RANGE ========================= */ const rangeLine = document.createElement('div'); rangeLine.textContent = range; rangeLine.style.cssText = 'display:block;' + 'width:100%;' + 'font-size:13px;' + 'color:#aaa;' + 'line-height:1.3;' + 'margin-bottom:10px;'; /* ========================= TOTAL ========================= */ const totalLine = document.createElement('div'); totalLine.textContent = 'Total: ' + money(total); totalLine.style.cssText = 'display:block;' + 'width:100%;' + 'font-size:14px;' + 'line-height:1.5;' + 'margin-bottom:3px;'; /* ========================= PAID ========================= */ const paidLine = document.createElement('div'); paidLine.textContent = 'Paid: ' + money(paid); paidLine.style.cssText = 'display:block;' + 'width:100%;' + 'font-size:14px;' + 'line-height:1.5;' + 'margin-bottom:3px;'; /* ========================= STILL TO PAY ========================= */ const remainingLine = document.createElement('div'); remainingLine.textContent = 'Still to pay: ' + money(remaining); remainingLine.style.cssText = 'display:block;' + 'width:100%;' + 'font-size:14px;' + 'line-height:1.5;' + 'margin-bottom:9px;'; /* ========================= ADD BILL BUTTON ========================= */ const addButton = document.createElement('button'); addButton.type = 'button'; addButton.className = 'budgetWeekAdd'; addButton.textContent = '+ Add bill'; addButton .addEventListener( 'click', function(){ addBillToWeek( week ); } ); /* BUILD WEEK HEADER AS SEPARATE ELEMENTS */ header.appendChild( titleLine ); header.appendChild( rangeLine ); header.appendChild( totalLine ); header.appendChild( paidLine ); header.appendChild( remainingLine ); header.appendChild( addButton ); box.appendChild( header ); /* ========================= BILLS ========================= */ if( weekBills.length === 0 ){ const empty = document.createElement('div'); empty.className = 'budgetEmpty'; empty.textContent = 'No bills added for this week.'; box.appendChild( empty ); } else{ weekBills.forEach( function(bill){ box.appendChild( createBillRow( bill ) ); } ); } section.appendChild( box ); } /* ========================= NO DATE BILLS ========================= */ function createNoDateSection(){ const section = document.getElementById( 'noDateBills' ); if(!section){ return; } const noDate = bills.filter( function(bill){ return !bill.dueDate; } ); section.innerHTML = ''; if( noDate.length === 0 ){ return; } const box = document.createElement('div'); box.className = 'budgetWeek'; const header = document.createElement('div'); header.className = 'budgetWeekHeader'; const title = document.createElement('div'); title.textContent = 'Bills without a date'; title.style.cssText = 'display:block;' + 'width:100%;' + 'font-size:20px;' + 'font-weight:bold;'; header.appendChild( title ); box.appendChild( header ); noDate.forEach( function(bill){ box.appendChild( createBillRow( bill ) ); } ); section.appendChild( box ); } /* ========================= RENDER ========================= */ function render(){ createWeekBox( 1, 'Week 1', '1st – 7th' ); createWeekBox( 2, 'Week 2', '8th – 14th' ); createWeekBox( 3, 'Week 3', '15th – 21st' ); createWeekBox( 4, 'Week 4', '22nd – end of month' ); createNoDateSection(); calculateBudget(); } /* ========================= STARTER BILLS ========================= */ function createStarterBills(){ bills = [ { id:'bill_rent', name:'Rent / Mortgage', amount:'', dueDate:'', paid:false }, { id:'bill_car', name:'Car / Finance', amount:'', dueDate:'', paid:false }, { id:'bill_credit', name:'Credit Card', amount:'', dueDate:'', paid:false }, { id:'bill_phone', name:'Phone / Internet', amount:'', dueDate:'', paid:false } ]; } /* ========================= LOAD SAVED DATA ========================= */ function loadBudget(){ const saved = localStorage.getItem( 'moneyUntilPaydayBudget' ); if(saved){ try{ const data = JSON.parse(saved); balanceInput.value = data.balance || ''; if( Array.isArray( data.bills ) && data.bills.length ){ bills = data.bills.map( function( bill, index ){ return { id: bill.id || ( 'bill_' + Date.now() + '_' + index ), name: bill.name || '', amount: bill.amount || '', dueDate: bill.dueDate || '', paid: !!bill.paid }; } ); } else{ createStarterBills(); } } catch(error){ createStarterBills(); } } else{ createStarterBills(); } render(); } /* ========================= ADD ANOTHER BILL ========================= */ addBillButton .addEventListener( 'click', function(){ bills.push({ id: 'bill_' + Date.now() + '_' + Math.random() .toString(16) .slice(2), name:'', amount:'', dueDate:'', paid:false }); saveBudget(); render(); } ); /* ========================= BALANCE CHANGE ========================= */ balanceInput .addEventListener( 'input', function(){ calculateBudget(); saveBudget(); } ); /* ========================= START APP ========================= */ loadBudget();

💾 Backup & Restore

✅ Your bills are saved automatically on this device as you make changes.

You do not need to press Backup every time. Use this optional backup if you want an extra copy of your bills, or if you want to move them to another device.

⚠️ Restoring a backup will replace the bills currently saved on this device.
(function(){ var STORAGE_KEY = "moneyUntilPaydayBudget"; var backupButton = document.getElementById( "backupBudgetButton" ); var restoreInput = document.getElementById( "restoreBudgetFile" ); var status = document.getElementById( "budgetBackupStatus" ); if( !backupButton || !restoreInput || !status ){ return; } /* ========================= BACKUP ========================= */ backupButton.addEventListener( "click", function(){ var saved = localStorage.getItem( STORAGE_KEY ); if(!saved){ status.textContent = "⚠️ No saved bill data found."; return; } var parsed; try{ parsed = JSON.parse( saved ); } catch(e){ status.textContent = "❌ Could not read the saved bill data."; return; } /* CREATE BACKUP FILE */ var backupData = { type: "DLC_BILL_TRACKER_BACKUP", version: 1, created: new Date() .toISOString(), data: parsed }; var blob = new Blob( [ JSON.stringify( backupData, null, 2 ) ], { type: "application/json" } ); var url = URL.createObjectURL( blob ); var link = document.createElement( "a" ); var today = new Date(); var dateName = today.getFullYear() + "-" + String( today.getMonth()+1 ).padStart(2,"0") + "-" + String( today.getDate() ).padStart(2,"0"); link.href = url; link.download = "dlc-bill-tracker-backup-" + dateName + ".json"; document.body.appendChild( link ); link.click(); document.body.removeChild( link ); URL.revokeObjectURL( url ); status.textContent = "✅ Backup created successfully"; } ); /* ========================= RESTORE ========================= */ restoreInput.addEventListener( "change", function(){ var file = restoreInput.files && restoreInput.files[0]; if(!file){ return; } /* CONFIRM BEFORE REPLACING CURRENT SAVED DATA */ var confirmed = window.confirm( "Restore this backup?\n\n" + "This will replace the bills currently saved on this device." ); if(!confirmed){ restoreInput.value = ""; status.textContent = "Restore cancelled."; return; } var reader = new FileReader(); reader.onload = function(event){ try{ var backup = JSON.parse( event.target.result ); /* CHECK VALID BACKUP */ if( !backup || backup.type !== "DLC_BILL_TRACKER_BACKUP" || !backup.data ){ status.textContent = "❌ This does not look like a valid bill-tracker backup."; restoreInput.value = ""; return; } /* RESTORE DATA */ localStorage.setItem( STORAGE_KEY, JSON.stringify( backup.data ) ); status.textContent = "✅ Backup restored — reloading..."; setTimeout( function(){ window.location.reload(); }, 700 ); } catch(e){ status.textContent = "❌ Could not restore this backup file."; } restoreInput.value = ""; }; reader.readAsText( file ); } ); })();

Income Shortfall Calculator

See how much extra you need to earn to cover the gap.

Extra needed per month
£0.00
Extra needed per week
£0.00
Extra needed per working day
£0.00
const shortAmount = document.getElementById('shortAmount'); const workDays = document.getElementById('workDays'); function shortfallMoney(value) { return '£' + (parseFloat(value) || 0).toFixed(2); } function calculateShortfall() { const amount = parseFloat(shortAmount.value) || 0; const days = parseInt(workDays.value, 10) || 5; const monthly = amount; const weekly = amount / 4.33; const daily = weekly / days; document.getElementById( 'needMonth' ).textContent = shortfallMoney(monthly); document.getElementById( 'needWeek' ).textContent = shortfallMoney(weekly); document.getElementById( 'needDay' ).textContent = shortfallMoney(daily); localStorage.setItem( 'shortfallAmount', shortAmount.value ); localStorage.setItem( 'shortfallWorkDays', workDays.value ); } function loadShortfall() { const savedAmount = localStorage.getItem( 'shortfallAmount' ); const savedDays = localStorage.getItem( 'shortfallWorkDays' ); if (savedAmount !== null) { shortAmount.value = savedAmount; } if (savedDays !== null) { workDays.value = savedDays; } calculateShortfall(); } shortAmount.addEventListener( 'input', calculateShortfall ); workDays.addEventListener( 'change', calculateShortfall ); loadShortfall();

📑 Tax Help

🧾

VAT Calculator

Quickly add or remove 20% VAT

£
YOUR RESULT
Enter an amount above
£0.00
function getVATAmount() { return parseFloat( document.getElementById("vatAmount").value ); } function displayResult(title, total, vatLabel, vat) { document.getElementById("vatResult").innerHTML = `
YOUR RESULT
${title}
£${total.toFixed(2)}
${vatLabel}
£${vat.toFixed(2)}
`; } function addVAT() { const amount = getVATAmount(); if (isNaN(amount) || amount < 0) { alert("Please enter a valid amount."); return; } const vat = amount * 0.20; const total = amount + vat; displayResult( "Total including VAT", total, "VAT added", vat ); } function removeVAT() { const amount = getVATAmount(); if (isNaN(amount) || amount < 0) { alert("Please enter a valid amount."); return; } const beforeVAT = amount / 1.20; const vat = amount - beforeVAT; displayResult( "Amount before VAT", beforeVAT, "VAT included", vat ); }
🧾

20% Tax Calculator

Deduct 20% or reverse a 20% deduction

£
YOUR RESULT
Enter an amount above
£0.00
Tax amount
£0.00
function getTaxAmount() { return parseFloat( document.getElementById("taxAmount").value ); } function showTaxResult(title, result, taxLabel, taxAmount) { document.getElementById("taxResult").innerHTML = `
YOUR RESULT
${title}
£${result.toFixed(2)}
${taxLabel}
£${taxAmount.toFixed(2)}
`; } /* TAKE 20% OFF */ function deductTax() { const amount = getTaxAmount(); if (isNaN(amount) || amount < 0) { alert("Please enter a valid amount."); return; } const tax = amount * 0.20; const afterTax = amount - tax; showTaxResult( "After 20% deduction", afterTax, "20% deducted", tax ); } /* ADD IT BACK */ function reverseTax() { const amount = getTaxAmount(); if (isNaN(amount) || amount < 0) { alert("Please enter a valid amount."); return; } const amountAdded = amount * 0.25; const originalAmount = amount + amountAdded; showTaxResult( "Before 20% deduction", originalAmount, "Amount added back", amountAdded ); }

📝Recipts Manager

📥 Receipt Manager

Track purchases and expenses

This Month
£0.00
Total Receipts
0
window.DLCReceiptTest = { receipts: [], storageKey: "DLCReceiptSimpleTest", start: function() { try { var saved = localStorage.getItem( this.storageKey ); if (saved) { this.receipts = JSON.parse(saved); } } catch(e) { this.receipts = []; } var dateBox = document.getElementById( "testReceiptDate" ); if (dateBox && !dateBox.value) { var now = new Date(); var year = now.getFullYear(); var month = String( now.getMonth() + 1 ).padStart(2,"0"); var day = String( now.getDate() ).padStart(2,"0"); dateBox.value = year + "-" + month + "-" + day; } this.render(); }, add: function() { var nameBox = document.getElementById( "testReceiptName" ); var amountBox = document.getElementById( "testReceiptAmount" ); var dateBox = document.getElementById( "testReceiptDate" ); var categoryBox = document.getElementById( "testReceiptCategory" ); var status = document.getElementById( "testReceiptStatus" ); status.textContent = "Add button pressed ✓"; var name = nameBox.value.trim(); var amount = parseFloat( amountBox.value ); var date = dateBox.value; var category = categoryBox.value; if (!name) { status.textContent = "Please enter a receipt name"; return; } if (isNaN(amount)) { status.textContent = "Please enter an amount"; return; } if (!date) { status.textContent = "Please select a date"; return; } this.receipts.push({ id: Date.now(), name: name, amount: amount, date: date, category: category }); try { localStorage.setItem( this.storageKey, JSON.stringify( this.receipts ) ); } catch(e) { status.textContent = "Receipt added but could not save"; } nameBox.value = ""; amountBox.value = ""; status.textContent = "Receipt added ✓"; this.render(); }, render: function() { var list = document.getElementById( "testReceiptList" ); var totalBox = document.getElementById( "testMonthTotal" ); var countBox = document.getElementById( "testReceiptCount" ); if ( !list || !totalBox || !countBox ) { return; } list.innerHTML = ""; var now = new Date(); var currentYear = now.getFullYear(); var currentMonth = now.getMonth(); var monthlyTotal = 0; for ( var i = 0; i < this.receipts.length; i++ ) { var receipt = this.receipts[i]; var parts = receipt.date.split("-"); if ( Number(parts[0]) === currentYear && Number(parts[1]) - 1 === currentMonth ) { monthlyTotal += Number( receipt.amount ); } var card = document.createElement( "div" ); card.style.cssText = "background:#1b1b1b;" + "border:1px solid #3a3a3a;" + "border-radius:13px;" + "padding:15px;" + "margin-bottom:10px;"; card.innerHTML = "" + receipt.name + "" + "" + "£" + Number( receipt.amount ).toFixed(2) + "" + "
" + "📅 " + receipt.date + "   •   " + receipt.category + "
"; list.appendChild( card ); } totalBox.textContent = "£" + monthlyTotal.toFixed(2); countBox.textContent = this.receipts.length; }, clearAll: function() { if ( !confirm( "Delete all receipts?" ) ) { return; } this.receipts = []; localStorage.removeItem( this.storageKey ); document.getElementById( "testReceiptStatus" ).textContent = "All receipts cleared ✓"; this.render(); } }; setTimeout( function() { DLCReceiptTest.start(); }, 300 );

🎯Savings Goals

🎯

Savings Goal

Plan what you want and see exactly how much to save

Still Needed
£0.00
Already Saved
£0.00
Progress 0%
💰 Amount to Save
Per Day
£0
Per Week
£0
Per Month
£0
⏳ Countdown to Your Goal
0 Days
0 Hours
0 Minutes
0 Seconds
(function() { var storageKey = "DLCSavingsGoalV1"; var countdownTimer = null; function get(id) { return document.getElementById( id ); } /* MONEY */ function money(value) { return ( "£" + Number(value) .toFixed(2) ); } /* SAVE */ function saveGoal() { var data = { name: get( "dlcSaveGoalName" ).value, target: get( "dlcSaveTarget" ).value, current: get( "dlcSaveCurrent" ).value, date: get( "dlcSaveDate" ).value }; try { localStorage.setItem( storageKey, JSON.stringify( data ) ); } catch(error) { } } /* LOAD */ function loadGoal() { try { var saved = localStorage.getItem( storageKey ); if (!saved) { return; } var data = JSON.parse( saved ); get( "dlcSaveGoalName" ).value = data.name || ""; get( "dlcSaveTarget" ).value = data.target || ""; get( "dlcSaveCurrent" ).value = data.current || ""; get( "dlcSaveDate" ).value = data.date || ""; if ( data.target && data.date ) { calculateGoal(); } } catch(error) { } } /* CALCULATE */ function calculateGoal() { var status = get( "dlcSaveStatus" ); var name = get( "dlcSaveGoalName" ).value .trim(); var target = parseFloat( get( "dlcSaveTarget" ).value ); var current = parseFloat( get( "dlcSaveCurrent" ).value ); var targetDateValue = get( "dlcSaveDate" ).value; if ( isNaN(current) ) { current = 0; } if ( isNaN(target) || target <= 0 ) { status.textContent = "Please enter your target amount"; return; } if (!targetDateValue) { status.textContent = "Please choose your target date"; return; } var now = new Date(); var targetDate = new Date( targetDateValue + "T23:59:59" ); var difference = targetDate.getTime() - now.getTime(); if ( difference <= 0 ) { status.textContent = "Please choose a future date"; return; } var remaining = target - current; if ( remaining < 0 ) { remaining = 0; } var days = difference / 86400000; var weeks = days / 7; var months = days / 30.4375; var daily = remaining / days; var weekly = remaining / weeks; var monthly = remaining / months; var percentage = target > 0 ? ( current / target ) * 100 : 0; if ( percentage > 100 ) { percentage = 100; } if ( percentage < 0 ) { percentage = 0; } get( "dlcGoalTitle" ).textContent = name ? "🎯 " + name : "🎯 My Savings Goal"; get( "dlcGoalTitle" ).style.display = "block"; get( "dlcSaveResults" ).style.display = "block"; get( "dlcSaveRemaining" ).textContent = money( remaining ); get( "dlcSaveSaved" ).textContent = money( current ); get( "dlcSaveDaily" ).textContent = money( daily ); get( "dlcSaveWeekly" ).textContent = money( weekly ); get( "dlcSaveMonthly" ).textContent = money( monthly ); get( "dlcSavePercent" ).textContent = percentage.toFixed( 1 ) + "%"; get( "dlcSaveProgress" ).style.width = percentage + "%"; if ( remaining === 0 ) { status.textContent = "🎉 Goal reached!"; } else { status.textContent = "Goal calculated and saved ✓"; } saveGoal(); startCountdown(); } /* COUNTDOWN */ function startCountdown() { if ( countdownTimer ) { clearInterval( countdownTimer ); } updateCountdown(); countdownTimer = setInterval( updateCountdown, 1000 ); } /* UPDATE TIMER */ function updateCountdown() { var dateValue = get( "dlcSaveDate" ).value; if (!dateValue) { return; } var target = new Date( dateValue + "T23:59:59" ); var now = new Date(); var distance = target.getTime() - now.getTime(); if ( distance <= 0 ) { get( "dlcCountDays" ).textContent = "0"; get( "dlcCountHours" ).textContent = "0"; get( "dlcCountMinutes" ).textContent = "0"; get( "dlcCountSeconds" ).textContent = "0"; return; } var days = Math.floor( distance / 86400000 ); var hours = Math.floor( ( distance % 86400000 ) / 3600000 ); var minutes = Math.floor( ( distance % 3600000 ) / 60000 ); var seconds = Math.floor( ( distance % 60000 ) / 1000 ); get( "dlcCountDays" ).textContent = days; get( "dlcCountHours" ).textContent = hours; get( "dlcCountMinutes" ).textContent = minutes; get( "dlcCountSeconds" ).textContent = seconds; } /* RESET */ function resetGoal() { var answer = confirm( "Reset this savings goal?" ); if (!answer) { return; } localStorage.removeItem( storageKey ); get( "dlcSaveGoalName" ).value = ""; get( "dlcSaveTarget" ).value = ""; get( "dlcSaveCurrent" ).value = ""; get( "dlcSaveDate" ).value = ""; get( "dlcSaveResults" ).style.display = "none"; get( "dlcGoalTitle" ).style.display = "none"; get( "dlcSaveStatus" ).textContent = "Goal reset"; if ( countdownTimer ) { clearInterval( countdownTimer ); } } /* BUTTONS */ get( "dlcSaveCalculate" ).addEventListener( "click", calculateGoal ); get( "dlcSaveReset" ).addEventListener( "click", resetGoal ); loadGoal(); })();

📈Debt Planner

📉

Debt Planner

See where you can save money and use it to reduce debt faster

✂️ Cut Back & Save

💳 Debt Payoff Planner

window.DLCDebt = { monthlySaving: 0, calculateSavings: function() { var oldSpend = parseFloat( document.getElementById( "currentSpend" ).value ); var newSpend = parseFloat( document.getElementById( "newSpend" ).value ); var name = document.getElementById( "cutName" ).value.trim(); if ( isNaN(oldSpend) || isNaN(newSpend) ) { document.getElementById( "debtStatus" ).textContent = "Please enter both monthly amounts"; return; } var saving = oldSpend - newSpend; if ( saving < 0 ) { saving = 0; } this.monthlySaving = saving; var yearly = saving * 12; var weekly = yearly / 52; var daily = yearly / 365; document.getElementById( "saveMonth" ).textContent = "£" + saving.toFixed(2); document.getElementById( "saveYear" ).textContent = "£" + yearly.toFixed(2); document.getElementById( "saveWeek" ).textContent = "£" + weekly.toFixed(2); document.getElementById( "saveDay" ).textContent = "£" + daily.toFixed(2); document.getElementById( "savingTitle" ).textContent = name ? "💰 Saving From " + name : "💰 Your Saving"; document.getElementById( "savingResult" ).style.display = "block"; document.getElementById( "debtStatus" ).textContent = "Saving calculated ✓"; }, calculateDebt: function() { var balance = parseFloat( document.getElementById( "debtBalance" ).value ); var payment = parseFloat( document.getElementById( "normalPayment" ).value ); var name = document.getElementById( "debtName" ).value.trim(); if ( isNaN(balance) || balance <= 0 ) { document.getElementById( "debtStatus" ).textContent = "Please enter your debt balance"; return; } if ( isNaN(payment) || payment <= 0 ) { document.getElementById( "debtStatus" ).textContent = "Please enter your monthly payment"; return; } var extra = this.monthlySaving; var combined = payment + extra; document.getElementById( "normalPayDisplay" ).textContent = "£" + payment.toFixed(2); document.getElementById( "extraPayDisplay" ).textContent = "£" + extra.toFixed(2); document.getElementById( "combinedPayment" ).textContent = "£" + combined.toFixed(2); document.getElementById( "debtResultTitle" ).textContent = name ? "📉 " + name + " Plan" : "📉 Debt Plan"; var months = Math.ceil( balance / combined ); document.getElementById( "monthsToClear" ).textContent = months + ( months === 1 ? " month" : " months" ); var finish = new Date(); finish.setMonth( finish.getMonth() + months ); document.getElementById( "debtFreeDate" ).textContent = finish.toLocaleDateString( "en-GB", { month: "long", year: "numeric" } ); document.getElementById( "debtResult" ).style.display = "block"; this.drawChart( balance, combined, months ); document.getElementById( "debtStatus" ).textContent = "Debt plan calculated ✓"; }, drawChart: function( startingBalance, monthlyPayment, months ) { var canvas = document.getElementById( "debtChart" ); var box = canvas.getBoundingClientRect(); var ratio = window.devicePixelRatio || 1; canvas.width = box.width * ratio; canvas.height = box.height * ratio; var ctx = canvas.getContext( "2d" ); ctx.scale( ratio, ratio ); var width = box.width; var height = box.height; ctx.clearRect( 0, 0, width, height ); /* BACKGROUND */ ctx.fillStyle = "#05070a"; ctx.fillRect( 0, 0, width, height ); /* GRID */ ctx.strokeStyle = "rgba(255,255,255,0.07)"; ctx.lineWidth = 1; for ( var y = 20; y < height; y += 40 ) { ctx.beginPath(); ctx.moveTo( 0, y ); ctx.lineTo( width, y ); ctx.stroke(); } for ( var x = 40; x < width; x += 60 ) { ctx.beginPath(); ctx.moveTo( x, 0 ); ctx.lineTo( x, height ); ctx.stroke(); } var points = []; var displayMonths = Math.min( months, 60 ); for ( var i = 0; i <= displayMonths; i++ ) { var remaining = Math.max( startingBalance - ( monthlyPayment * i ), 0 ); points.push( remaining ); } var padding = 22; var chartWidth = width - padding * 2; var chartHeight = height - padding * 2; /* LINE */ ctx.beginPath(); for ( var p = 0; p < points.length; p++ ) { var px = padding + ( p / Math.max( points.length - 1, 1 ) ) * chartWidth; var py = padding + ( 1 - points[p] / startingBalance ) * chartHeight; if ( p === 0 ) { ctx.moveTo( px, py ); } else { ctx.lineTo( px, py ); } } ctx.strokeStyle = "#ff5656"; ctx.lineWidth = 3; ctx.shadowColor = "#ff3333"; ctx.shadowBlur = 8; ctx.stroke(); ctx.shadowBlur = 0; /* £0 LINE */ ctx.strokeStyle = "rgba(80,220,140,0.4)"; ctx.beginPath(); ctx.moveTo( padding, height - padding ); ctx.lineTo( width - padding, height - padding ); ctx.stroke(); /* LABEL */ ctx.fillStyle = "#6fe3a2"; ctx.font = "12px Arial"; ctx.fillText( "£0", padding, height - 5 ); } };

🧮Calculator

🧮

Calculator

Everyday calculations made simple

0
⚡ Quick Percentage
window.DLCNormalCalc = { display: document.getElementById( "calcDisplay" ), expression: document.getElementById( "calcExpression" ), current: "0", firstValue: null, operator: null, waitingForSecond: false, updateDisplay: function() { var number = Number( this.current ); if ( !isNaN(number) && this.current !== "" ) { this.display.textContent = number.toLocaleString( "en-GB", { maximumFractionDigits: 10 } ); } else { this.display.textContent = this.current; } }, number: function(value) { if ( this.waitingForSecond ) { this.current = value; this.waitingForSecond = false; } else { if ( this.current === "0" ) { this.current = value; } else { this.current += value; } } this.updateDisplay(); }, decimal: function() { if ( this.waitingForSecond ) { this.current = "0."; this.waitingForSecond = false; this.updateDisplay(); return; } if ( this.current.indexOf(".") === -1 ) { this.current += "."; } this.updateDisplay(); }, chooseOperator: function(nextOperator) { var inputValue = parseFloat( this.current ); if ( this.operator && !this.waitingForSecond ) { this.calculate(); inputValue = parseFloat( this.current ); } this.firstValue = inputValue; this.operator = nextOperator; this.waitingForSecond = true; this.expression.textContent = this.formatOperator( nextOperator ); }, calculate: function() { if ( this.firstValue === null || this.operator === null ) { return; } var secondValue = parseFloat( this.current ); var result = 0; if ( this.operator === "+" ) { result = this.firstValue + secondValue; } else if ( this.operator === "-" ) { result = this.firstValue - secondValue; } else if ( this.operator === "*" ) { result = this.firstValue * secondValue; } else if ( this.operator === "/" ) { if ( secondValue === 0 ) { this.display.textContent = "Cannot divide by 0"; this.current = "0"; this.firstValue = null; this.operator = null; return; } result = this.firstValue / secondValue; } this.expression.textContent = this.firstValue + " " + this.formatOperator( this.operator ) + " " + secondValue + " ="; this.current = String( Number( result.toFixed(10) ) ); this.firstValue = null; this.operator = null; this.waitingForSecond = true; this.updateDisplay(); }, clearAll: function() { this.current = "0"; this.firstValue = null; this.operator = null; this.waitingForSecond = false; this.expression.textContent = ""; this.updateDisplay(); }, backspace: function() { if ( this.waitingForSecond ) { return; } if ( this.current.length <= 1 ) { this.current = "0"; } else { this.current = this.current.slice( 0, -1 ); } this.updateDisplay(); }, toggleSign: function() { if ( this.current === "0" ) { return; } if ( this.current.charAt(0) === "-" ) { this.current = this.current.substring(1); } else { this.current = "-" + this.current; } this.updateDisplay(); }, quickPercent: function(percent) { var amount = parseFloat( this.current ); if ( isNaN(amount) ) { return; } var result = amount + ( amount * percent / 100 ); this.expression.textContent = amount + " " + ( percent >= 0 ? "+" : "" ) + percent + "%"; this.current = String( Number( result.toFixed(10) ) ); this.updateDisplay(); }, customAddPercent: function() { var percent = parseFloat( document.getElementById( "customPercent" ).value ); if ( isNaN(percent) ) { document.getElementById( "calcStatus" ).textContent = "Enter a percentage"; return; } this.quickPercent( Math.abs(percent) ); }, customRemovePercent: function() { var percent = parseFloat( document.getElementById( "customPercent" ).value ); if ( isNaN(percent) ) { document.getElementById( "calcStatus" ).textContent = "Enter a percentage"; return; } this.quickPercent( -Math.abs(percent) ); }, formatOperator: function(operator) { if ( operator === "*" ) { return "×"; } if ( operator === "/" ) { return "÷"; } if ( operator === "-" ) { return "−"; } return operator; } }; DLCNormalCalc.updateDisplay();

📚Learn & Guides

📚

Learn & Guides

Helpful tips, guides and your own personal sticky notes

➕ Add My Note
DLC GUIDE 📱 Add to Home Screen Make My Digital Folder feel more like an app. Tap to read →

📱 Add My Digital Folder to your Home Screen

iPhone / iPad

1. Open My Digital Folder in Safari.

2. Press the Share button.

3. Scroll down and choose Add to Home Screen.

4. Press Add.

Android

1. Open My Digital Folder in your browser.

2. Open the browser menu.

3. Choose Add to Home screen or Install app.

4. Confirm.

⭐ You can now open My Digital Folder directly from your phone like an app.

MONEY TIP 💷 Start Small Small regular savings can build into something much bigger. Tap to read →

💷 Small amounts still matter

You don't always need to start with a huge savings amount.

Regular small amounts can gradually build into something much larger.

Try the Savings Goals section to see how much a target works out at per day, per week and per month.

⭐ A target that looks difficult can feel much easier when broken into smaller amounts.

ORGANISING 🧾 Keep Receipts Record purchases while they are still fresh in your mind. Tap to read →

🧾 Keep purchases organised

Try adding a purchase to the Receipt Manager soon after you make it.

That can make it easier to remember what the purchase was actually for.

Categories such as Materials, Fuel, Bills and Work Expense can help separate different spending.

BILLS TIP 💡 Check Outgoings Small monthly costs can become surprisingly large over a year. Tap to read →

💡 Check regular payments

Look through subscriptions, memberships and other regular bills occasionally.

A payment that looks small each month can become a much larger figure over twelve months.

Use the calculators inside My Digital Folder to compare monthly and yearly costs.

GOAL TIP 🎯 Give Goals a Date A target date turns an idea into a proper plan. Tap to read →

🎯 Give your target a deadline

Instead of only deciding how much you want to save, choose when you want to reach the target.

Your Savings Goals calculator can then show approximately how much you need per day, week and month.

Try changing the target date until the required saving amount feels realistic.

DID YOU KNOW? 📂 Your Digital Folder Some saved information stays inside this browser. Tap to read →

📂 Saving information

Some tools inside My Digital Folder use browser storage.

This allows information to remain available when you return using the same browser and device.

Information may not automatically appear on another phone, tablet, computer or browser.

⭐ Important information should still be backed up separately.

(function() { var storageKey = "DLCGuidePersonalNotesV3"; var notes = []; function getEl(id) { return document.getElementById( id ); } /* ========================= LOAD NOTES ========================= */ function loadNotes() { try { var saved = localStorage.getItem( storageKey ); if (saved) { var parsed = JSON.parse( saved ); if ( Array.isArray( parsed ) ) { notes = parsed; } } } catch(error) { notes = []; } renderNotes(); } /* ========================= SAVE STORAGE ========================= */ function saveStorage() { try { localStorage.setItem( storageKey, JSON.stringify( notes ) ); return true; } catch(error) { return false; } } /* ========================= ADD NOTE ========================= */ function addNote() { var titleBox = getEl( "lgPersonalTitle" ); var textBox = getEl( "lgPersonalText"

⭐️Extras

🤖 DLC Character Snap Test

Drag the HEAD and BODY into their matching slots

Pieces fitted0/2
HEAD
BODY
HEAD
DIGITAL
BODY
🤖 DLC DIGITAL READY!
Drag either piece towards its matching slot
var DLCTwoSnap = { area:null, status:null, countBox:null, completeBox:null, active:null, dragging:false, offsetX:0, offsetY:0, fittedHead:false, fittedBody:false, headStart:null, bodyStart:null, topLayer:20, start:function() { this.area = document.getElementById( "twoSnapArea" ); this.status = document.getElementById( "twoSnapStatus" ); this.countBox = document.getElementById( "twoSnapCount" ); this.completeBox = document.getElementById( "twoComplete" ); var head = document.getElementById( "twoHeadPiece" ); var body = document.getElementById( "twoBodyPiece" ); if ( !this.area || !head || !body ) { return; } /* Record their real starting positions after Carrd loads. */ this.headStart = { left: head.offsetLeft, top: head.offsetTop }; this.bodyStart = { left: body.offsetLeft, top: body.offsetTop }; head.addEventListener( "pointerdown", this.down.bind(this) ); body.addEventListener( "pointerdown", this.down.bind(this) ); document.addEventListener( "pointermove", this.move.bind(this) ); document.addEventListener( "pointerup", this.up.bind(this) ); document.addEventListener( "pointercancel", this.up.bind(this) ); this.updateCount(); this.status.textContent = "✅ Two-piece test loaded"; }, down:function(event) { event.preventDefault(); this.active = event.currentTarget; this.dragging = true; var name = this.active.getAttribute( "data-piece" ); /* If fitted already, grabbing it removes it from fitted state. */ if ( name === "HEAD" && this.fittedHead ) { this.fittedHead = false; this.active.classList.remove( "twoFitted" ); } if ( name === "BODY" && this.fittedBody ) { this.fittedBody = false; this.active.classList.remove( "twoFitted" ); } this.updateCount(); var rect = this.active .getBoundingClientRect(); this.offsetX = event.clientX - rect.left; this.offsetY = event.clientY - rect.top; this.topLayer++; this.active.style.zIndex = this.topLayer; this.active.style.cursor = "grabbing"; this.status.textContent = "✋ Moving " + name; }, move:function(event) { if ( !this.dragging || !this.active ) { return; } event.preventDefault(); var areaRect = this.area .getBoundingClientRect(); var x = event.clientX - areaRect.left - this.offsetX; var y = event.clientY - areaRect.top - this.offsetY; var maxX = this.area.clientWidth - this.active.offsetWidth; var maxY = this.area.clientHeight - this.active.offsetHeight; if (x < 0) { x = 0; } if (y < 0) { y = 0; } if (x > maxX) { x = maxX; } if (y > maxY) { y = maxY; } this.active.style.left = x + "px"; this.active.style.top = y + "px"; this.active.style.right = "auto"; this.active.style.bottom = "auto"; }, up:function() { if ( !this.dragging || !this.active ) { return; } this.dragging = false; var piece = this.active; this.active = null; piece.style.cursor = "grab"; this.checkSnap( piece ); }, checkSnap:function(piece) { var name = piece.getAttribute( "data-piece" ); var target; if ( name === "HEAD" ) { target = document.getElementById( "twoHeadTarget" ); } if ( name === "BODY" ) { target = document.getElementById( "twoBodyTarget" ); } if (!target) { return; } var pieceRect = piece .getBoundingClientRect(); var targetRect = target .getBoundingClientRect(); /* Check whether the middle of the piece has entered the target area. */ var centreX = pieceRect.left + pieceRect.width / 2; var centreY = pieceRect.top + pieceRect.height / 2; var inside = centreX > targetRect.left - 20 && centreX < targetRect.right + 20 && centreY > targetRect.top - 20 && centreY < targetRect.bottom + 20; if (!inside) { this.status.textContent = "❌ Not in the slot — try again"; return; } this.snap( piece, target, name ); }, snap:function( piece, target, name ) { var areaRect = this.area .getBoundingClientRect(); var targetRect = target .getBoundingClientRect(); var x = targetRect.left - areaRect.left + ( targetRect.width - piece.offsetWidth ) / 2; var y = targetRect.top - areaRect.top + ( targetRect.height - piece.offsetHeight ) / 2; piece.style.left = x + "px"; piece.style.top = y + "px"; piece.style.right = "auto"; piece.style.bottom = "auto"; piece.classList.add( "twoFitted" ); if ( name === "HEAD" ) { this.fittedHead = true; } if ( name === "BODY" ) { this.fittedBody = true; } this.status.textContent = "🎉 CLICK! " + name + " FITTED!"; this.updateCount(); }, updateCount:function() { var count = 0; if ( this.fittedHead ) { count++; } if ( this.fittedBody ) { count++; } if ( this.countBox ) { this.countBox.textContent = count; } if ( count === 2 ) { this.status.textContent = "🎉 CHARACTER TEST COMPLETE!"; this.completeBox.classList.add( "showTwoComplete" ); this.area.style.boxShadow = "inset 0 0 45px rgba(0,255,145,0.20)"; } else { this.completeBox.classList.remove( "showTwoComplete" ); this.area.style.boxShadow = ""; } }, reset:function() { var head = document.getElementById( "twoHeadPiece" ); var body = document.getElementById( "twoBodyPiece" ); this.dragging = false; this.active = null; this.fittedHead = false; this.fittedBody = false; head.classList.remove( "twoFitted" ); body.classList.remove( "twoFitted" ); head.style.right = "auto"; head.style.bottom = "auto"; head.style.left = this.headStart.left + "px"; head.style.top = this.headStart.top + "px"; body.style.right = "auto"; body.style.bottom = "auto"; body.style.left = this.bodyStart.left + "px"; body.style.top = this.bodyStart.top + "px"; this.updateCount(); this.status.textContent = "↺ Test reset"; } }; setTimeout( function() { DLCTwoSnap.start(); var button = document.getElementById( "twoSnapReset" ); if (button) { button.addEventListener( "click", function() { DLCTwoSnap.reset(); } ); } }, 600 );
setTimeout(function() { var area = document.getElementById( "twoSnapArea" ); var count = document.getElementById( "twoSnapCount" ); var status = document.getElementById( "twoSnapStatus" ); if ( !area || !window.DLCTwoSnap ) { return; } /* CHANGE COUNTER TO /3 */ if (count) { var parent = count.parentElement; if (parent) { parent.innerHTML = '' + '0' + '/3'; } } /* CREATE ARM TARGET */ var target = document.createElement( "div" ); target.id = "twoLeftArmTarget"; target.textContent = "ARM"; area.appendChild( target ); /* CREATE ARM */ var arm = document.createElement( "div" ); arm.id = "twoLeftArmPiece"; arm.setAttribute( "data-piece", "ARM" ); arm.innerHTML = '
' + '
' + 'LEFT'; area.appendChild( arm ); /* STORE START */ DLCTwoSnap.armStart = { left:arm.offsetLeft, top:arm.offsetTop }; DLCTwoSnap.fittedArm = false; /* CONNECT ARM TO EXISTING DRAG */ arm.addEventListener( "pointerdown", DLCTwoSnap.down.bind( DLCTwoSnap ) ); /* SAVE ORIGINAL CHECK SNAP */ var oldCheckSnap = DLCTwoSnap.checkSnap.bind( DLCTwoSnap ); DLCTwoSnap.checkSnap = function(piece) { var name = piece.getAttribute( "data-piece" ); if ( name !== "ARM" ) { oldCheckSnap( piece ); return; } var armTarget = document.getElementById( "twoLeftArmTarget" ); var pieceRect = piece.getBoundingClientRect(); var targetRect = armTarget.getBoundingClientRect(); var centreX = pieceRect.left + pieceRect.width / 2; var centreY = pieceRect.top + pieceRect.height / 2; var inside = centreX > targetRect.left - 20 && centreX < targetRect.right + 20 && centreY > targetRect.top - 20 && centreY < targetRect.bottom + 20; if (!inside) { status.textContent = "❌ Not in the slot — try again"; return; } var areaRect = area.getBoundingClientRect(); var x = targetRect.left - areaRect.left + ( targetRect.width - piece.offsetWidth ) / 2; var y = targetRect.top - areaRect.top + ( targetRect.height - piece.offsetHeight ) / 2; piece.style.left = x + "px"; piece.style.top = y + "px"; piece.style.right = "auto"; piece.style.bottom = "auto"; piece.classList.add( "twoFitted" ); DLCTwoSnap.fittedArm = true; status.textContent = "🎉 CLICK! LEFT ARM FITTED!"; updateThreeCount(); }; /* NEW 3 PIECE COUNTER */ function updateThreeCount() { var total = 0; if ( DLCTwoSnap.fittedHead ) { total++; } if ( DLCTwoSnap.fittedBody ) { total++; } if ( DLCTwoSnap.fittedArm ) { total++; } var newCount = document.getElementById( "twoSnapCount" ); if (newCount) { newCount.textContent = total; } if ( total === 3 ) { status.textContent = "🎉 3 PIECES FITTED!"; area.style.boxShadow = "inset 0 0 45px rgba(0,255,145,0.20)"; } } /* EXTEND ORIGINAL UPDATE */ var oldUpdate = DLCTwoSnap.updateCount.bind( DLCTwoSnap ); DLCTwoSnap.updateCount = function() { oldUpdate(); updateThreeCount(); }; status.textContent = "✅ LEFT ARM added — try dragging it"; },1000);
setTimeout(function() { if ( !window.DLCTwoSnap ) { return; } var oldReset = DLCTwoSnap.reset.bind( DLCTwoSnap ); DLCTwoSnap.reset = function() { /* First run the ORIGINAL HEAD + BODY reset. */ oldReset(); /* Then reset the LEFT ARM. */ var arm = document.getElementById( "twoLeftArmPiece" ); if ( arm && this.armStart ) { this.fittedArm = false; arm.classList.remove( "twoFitted" ); arm.style.right = "auto"; arm.style.bottom = "auto"; arm.style.left = this.armStart.left + "px"; arm.style.top = this.armStart.top + "px"; arm.style.zIndex = "10"; arm.style.cursor = "grab"; } /* Make sure counter goes back to zero. */ var count = document.getElementById( "twoSnapCount" ); if (count) { count.textContent = "0"; } var status = document.getElementById( "twoSnapStatus" ); if (status) { status.textContent = "↺ Test reset"; } var area = document.getElementById( "twoSnapArea" ); if (area) { area.style.boxShadow = ""; } }; },1400);
setTimeout(function() { var area = document.getElementById( "twoSnapArea" ); var countBox = document.getElementById( "twoSnapCount" ); var status = document.getElementById( "twoSnapStatus" ); if ( !area || !window.DLCTwoSnap ) { return; } /* ========================= CREATE RIGHT TARGET ========================= */ if ( !document.getElementById( "twoRightArmTarget" ) ) { var target = document.createElement( "div" ); target.id = "twoRightArmTarget"; target.textContent = "ARM"; area.appendChild( target ); } /* ========================= CREATE RIGHT ARM ========================= */ if ( !document.getElementById( "twoRightArmPiece" ) ) { var arm = document.createElement( "div" ); arm.id = "twoRightArmPiece"; arm.setAttribute( "data-piece", "RIGHT ARM" ); arm.textContent = "RIGHT"; area.appendChild( arm ); } var arm = document.getElementById( "twoRightArmPiece" ); var target = document.getElementById( "twoRightArmTarget" ); /* SAVE START POSITION */ DLCTwoSnap.rightArmStart = { left: arm.offsetLeft, top: arm.offsetTop }; DLCTwoSnap.fittedRightArm = false; /* ========================= DRAG RIGHT ARM ========================= */ arm.addEventListener( "pointerdown", DLCTwoSnap.down.bind( DLCTwoSnap ) ); /* ========================= EXTEND SNAP CHECK ========================= */ var oldCheckSnap = DLCTwoSnap.checkSnap.bind( DLCTwoSnap ); DLCTwoSnap.checkSnap = function(piece) { var name = piece.getAttribute( "data-piece" ); if ( name !== "RIGHT ARM" ) { oldCheckSnap( piece ); return; } var pieceRect = piece.getBoundingClientRect(); var targetRect = target.getBoundingClientRect(); var centreX = pieceRect.left + pieceRect.width / 2; var centreY = pieceRect.top + pieceRect.height / 2; var inside = centreX > targetRect.left - 20 && centreX < targetRect.right + 20 && centreY > targetRect.top - 20 && centreY < targetRect.bottom + 20; if (!inside) { status.textContent = "❌ Not in the slot — try again"; return; } var areaRect = area.getBoundingClientRect(); var x = targetRect.left - areaRect.left + ( targetRect.width - piece.offsetWidth ) / 2; var y = targetRect.top - areaRect.top + ( targetRect.height - piece.offsetHeight ) / 2; piece.style.left = x + "px"; piece.style.top = y + "px"; piece.style.right = "auto"; piece.style.bottom = "auto"; piece.classList.add( "twoFitted" ); this.fittedRightArm = true; status.textContent = "🎉 CLICK! RIGHT ARM FITTED!"; this.updateCount(); }; /* ========================= NEW COUNTER ========================= */ DLCTwoSnap.updateCount = function() { var fittedPieces = area.querySelectorAll( ".twoFitted" ); var count = fittedPieces.length; if (countBox) { countBox.textContent = count; } var progress = countBox ? countBox.parentElement : null; if (progress) { progress.innerHTML = '' + count + '/4'; countBox = document.getElementById( "twoSnapCount" ); } if ( count === 4 ) { status.textContent = "🎉 4 PIECES FITTED!"; area.style.boxShadow = "inset 0 0 45px rgba(0,255,145,0.20)"; } else { area.style.boxShadow = ""; } }; /* ========================= EXTEND RESET ========================= */ var oldReset = DLCTwoSnap.reset.bind( DLCTwoSnap ); DLCTwoSnap.reset = function() { oldReset(); this.fittedRightArm = false; arm.classList.remove( "twoFitted" ); arm.style.left = this.rightArmStart.left + "px"; arm.style.top = this.rightArmStart.top + "px"; arm.style.right = "auto"; arm.style.bottom = "auto"; arm.style.zIndex = "10"; this.updateCount(); status.textContent = "↺ Test reset"; }; /* CHANGE DISPLAY TO /4 */ var strong = countBox.parentElement; strong.innerHTML = '0/4'; countBox = document.getElementById( "twoSnapCount" ); status.textContent = "✅ RIGHT ARM added — 4 piece test ready"; },1500);
setTimeout(function() { var area = document.getElementById( "twoSnapArea" ); var status = document.getElementById( "twoSnapStatus" ); var countBox = document.getElementById( "twoSnapCount" ); if ( !area || !window.DLCTwoSnap ) { return; } /* ========================= FIX ARM GLOW WHEN PICKED UP ========================= */ var oldDown = DLCTwoSnap.down.bind( DLCTwoSnap ); DLCTwoSnap.down = function(event) { var piece = event.currentTarget; var name = piece.getAttribute( "data-piece" ); if ( name === "LEFT ARM" || name === "RIGHT ARM" ) { piece.classList.remove( "twoFitted" ); if ( name === "LEFT ARM" ) { this.fittedLeftArm = false; } if ( name === "RIGHT ARM" ) { this.fittedRightArm = false; } if ( this.updateCount ) { this.updateCount(); } } oldDown( event ); }; /* Reconnect the existing arms to the new pickup behaviour. */ var leftArm = document.getElementById( "twoLeftArmPiece" ); var rightArm = document.getElementById( "twoRightArmPiece" ); if (leftArm) { leftArm.onpointerdown = function(event) { DLCTwoSnap.down( event ); }; } if (rightArm) { rightArm.onpointerdown = function(event) { DLCTwoSnap.down( event ); }; } /* ========================= CREATE LEFT LEG TARGET ========================= */ if ( !document.getElementById( "twoLeftLegTarget" ) ) { var target = document.createElement( "div" ); target.id = "twoLeftLegTarget"; target.textContent = "LEG"; area.appendChild( target ); } /* ========================= CREATE LEFT LEG ========================= */ if ( !document.getElementById( "twoLeftLegPiece" ) ) { var leg = document.createElement( "div" ); leg.id = "twoLeftLegPiece"; leg.setAttribute( "data-piece", "LEFT LEG" ); area.appendChild( leg ); } var leg = document.getElementById( "twoLeftLegPiece" ); var legTarget = document.getElementById( "twoLeftLegTarget" ); DLCTwoSnap.leftLegStart = { left: leg.offsetLeft, top: leg.offsetTop }; DLCTwoSnap.fittedLeftLeg = false; /* ========================= LEFT LEG PICKUP ========================= */ leg.addEventListener( "pointerdown", function(event) { if ( DLCTwoSnap.fittedLeftLeg ) { DLCTwoSnap.fittedLeftLeg = false; leg.classList.remove( "twoFitted" ); if ( DLCTwoSnap.updateCount ) { DLCTwoSnap.updateCount(); } } DLCTwoSnap.down( event ); } ); /* ========================= EXTEND SNAP ========================= */ var previousSnap = DLCTwoSnap.checkSnap.bind( DLCTwoSnap ); DLCTwoSnap.checkSnap = function(piece) { var name = piece.getAttribute( "data-piece" ); if ( name !== "LEFT LEG" ) { previousSnap( piece ); return; } var pieceRect = piece.getBoundingClientRect(); var targetRect = legTarget.getBoundingClientRect(); var centreX = pieceRect.left + pieceRect.width / 2; var centreY = pieceRect.top + pieceRect.height / 2; var inside = centreX > targetRect.left - 22 && centreX < targetRect.right + 22 && centreY > targetRect.top - 22 && centreY < targetRect.bottom + 22; if (!inside) { status.textContent = "❌ Not in the slot — try again"; return; } var areaRect = area.getBoundingClientRect(); var x = targetRect.left - areaRect.left + ( targetRect.width - piece.offsetWidth ) / 2; var y = targetRect.top - areaRect.top + ( targetRect.height - piece.offsetHeight ) / 2; piece.style.left = x + "px"; piece.style.top = y + "px"; piece.style.right = "auto"; piece.style.bottom = "auto"; piece.classList.add( "twoFitted" ); this.fittedLeftLeg = true; status.textContent = "🎉 CLICK! LEFT LEG FITTED!"; this.updateCount(); }; /* ========================= COUNTER = /5 ========================= */ DLCTwoSnap.updateCount = function() { var count = area.querySelectorAll( ".twoFitted" ).length; var box = document.getElementById( "twoSnapCount" ); if (box) { box.textContent = count; } var strong = box ? box.parentElement : null; if (strong) { strong.innerHTML = '' + count + '/5'; } if ( count === 5 ) { status.textContent = "🎉 5 PIECES FITTED!"; area.style.boxShadow = "inset 0 0 45px rgba(0,255,145,0.20)"; } else { area.style.boxShadow = ""; } }; /* ========================= EXTEND RESET ========================= */ var oldReset = DLCTwoSnap.reset.bind( DLCTwoSnap ); DLCTwoSnap.reset = function() { oldReset(); this.fittedLeftLeg = false; leg.classList.remove( "twoFitted" ); leg.style.left = this.leftLegStart.left + "px"; leg.style.top = this.leftLegStart.top + "px"; leg.style.right = "auto"; leg.style.bottom = "auto"; leg.style.zIndex = "10"; this.updateCount(); status.textContent = "↺ Test reset"; }; /* SET DISPLAY TO /5 */ var box = document.getElementById( "twoSnapCount" ); if (box) { box.parentElement.innerHTML = '0/5'; } status.textContent = "✅ LEFT LEG added — 5 piece test ready"; },1800);
setTimeout(function() { var game = window.DLCTwoSnap; var area = document.getElementById( "twoSnapArea" ); var status = document.getElementById( "twoSnapStatus" ); if ( !game || !area ) { return; } /* ================================= FIX LEFT ARM GREEN GLOW ================================= */ var leftArm = document.getElementById( "twoLeftArmPiece" ) || area.querySelector( '[data-piece="LEFT ARM"]' ); if ( leftArm && !leftArm.dataset.glowFixAdded ) { leftArm.dataset.glowFixAdded = "yes"; leftArm.addEventListener( "pointerdown", function() { leftArm.classList.remove( "twoFitted" ); game.fittedLeftArm = false; setTimeout( function() { leftArm.classList.remove( "twoFitted" ); if ( game.updateCount ) { game.updateCount(); } }, 10 ); }, true ); } /* ================================= CREATE RIGHT LEG TARGET ================================= */ if ( !document.getElementById( "twoRightLegTarget" ) ) { var target = document.createElement( "div" ); target.id = "twoRightLegTarget"; target.textContent = "LEG"; area.appendChild( target ); } /* ================================= CREATE RIGHT LEG PIECE ================================= */ if ( !document.getElementById( "twoRightLegPiece" ) ) { var leg = document.createElement( "div" ); leg.id = "twoRightLegPiece"; leg.setAttribute( "data-piece", "RIGHT LEG" ); area.appendChild( leg ); } var rightLeg = document.getElementById( "twoRightLegPiece" ); var rightTarget = document.getElementById( "twoRightLegTarget" ); /* ================================= SAVE START POSITION ================================= */ game.rightLegStart = { left: rightLeg.offsetLeft, top: rightLeg.offsetTop }; game.fittedRightLeg = false; /* ================================= RIGHT LEG DRAG ================================= */ rightLeg.addEventListener( "pointerdown", function(event) { /* If already fitted, picking it up removes the green glow. */ if ( game.fittedRightLeg ) { game.fittedRightLeg = false; rightLeg.classList.remove( "twoFitted" ); if ( game.updateCount ) { game.updateCount(); } } /* Use the SAME working drag system as all the other character pieces. */ game.down( event ); } ); /* ================================= EXTEND SNAP SYSTEM ================================= */ var previousCheckSnap = game.checkSnap.bind( game ); game.checkSnap = function(piece) { var name = piece.getAttribute( "data-piece" ); /* All existing pieces still use their existing code. */ if ( name !== "RIGHT LEG" ) { previousCheckSnap( piece ); return; } var pieceRect = piece.getBoundingClientRect(); var targetRect = rightTarget.getBoundingClientRect(); var centreX = pieceRect.left + pieceRect.width / 2; var centreY = pieceRect.top + pieceRect.height / 2; /* Slightly generous target area for phone dragging. */ var inside = centreX > targetRect.left - 22 && centreX < targetRect.right + 22 && centreY > targetRect.top - 22 && centreY < targetRect.bottom + 22; if (!inside) { status.textContent = "❌ Not in the slot — try again"; return; } var areaRect = area.getBoundingClientRect(); var x = targetRect.left - areaRect.left + ( targetRect.width - piece.offsetWidth ) / 2; var y = targetRect.top - areaRect.top + ( targetRect.height - piece.offsetHeight ) / 2; piece.style.left = x + "px"; piece.style.top = y + "px"; piece.style.right = "auto"; piece.style.bottom = "auto"; piece.classList.add( "twoFitted" ); this.fittedRightLeg = true; status.textContent = "🎉 CLICK! RIGHT LEG FITTED!"; this.updateCount(); }; /* ================================= UPDATE COUNTER TO 6 ================================= */ game.updateCount = function() { var fittedPieces = area.querySelectorAll( ".twoFitted" ); var count = fittedPieces.length; var countBox = document.getElementById( "twoSnapCount" ); if ( countBox ) { countBox.textContent = count; if ( countBox.parentElement ) { countBox.parentElement.innerHTML = '' + count + '/6'; } } if ( count === 6 ) { status.textContent = "🎉 DLC DIGITAL CHARACTER COMPLETE!"; area.style.boxShadow = "inset 0 0 55px rgba(0,255,145,0.25)"; var complete = document.getElementById( "twoComplete" ); if ( complete ) { complete.textContent = "🤖 DLC DIGITAL READY!"; complete.classList.add( "showTwoComplete" ); } } else { area.style.boxShadow = ""; var complete = document.getElementById( "twoComplete" ); if ( complete ) { complete.classList.remove( "showTwoComplete" ); } } }; /* ================================= EXTEND RESET ================================= */ var previousReset = game.reset.bind( game ); game.reset = function() { previousReset(); this.fittedRightLeg = false; rightLeg.classList.remove( "twoFitted" ); rightLeg.style.right = "auto"; rightLeg.style.bottom = "auto"; rightLeg.style.left = this.rightLegStart.left + "px"; rightLeg.style.top = this.rightLegStart.top + "px"; rightLeg.style.zIndex = "10"; /* Extra left-arm glow fix during reset too. */ if ( leftArm ) { leftArm.classList.remove( "twoFitted" ); } this.fittedLeftArm = false; this.updateCount(); status.textContent = "↺ Test reset"; }; /* ================================= INITIAL DISPLAY ================================= */ game.updateCount(); status.textContent = "✅ RIGHT LEG added — build all 6 pieces"; },1800);

🎨 Character Colour

Choose your DLC Digital colour

Current colour: Blue
setTimeout(function () { var buttons = document.querySelectorAll( ".dlcColourChoice" ); var status = document.getElementById( "dlcColourStatus" ); function changeCharacter(colour) { var main; var dark; if (colour === "blue") { main = "linear-gradient(145deg,#244dff,#251090)"; dark = "linear-gradient(145deg,#2631c6,#100c50)"; } if (colour === "purple") { main = "linear-gradient(145deg,#9b35ff,#3b087d)"; dark = "linear-gradient(145deg,#6720d8,#21064f)"; } if (colour === "red") { main = "linear-gradient(145deg,#ff3b4d,#8f0714)"; dark = "linear-gradient(145deg,#c52031,#52030b)"; } if (colour === "green") { main = "linear-gradient(145deg,#18c978,#075934)"; dark = "linear-gradient(145deg,#11975a,#033820)"; } if (colour === "gold") { main = "linear-gradient(145deg,#ffd84d,#9b6500)"; dark = "linear-gradient(145deg,#d9aa20,#684900)"; } /* Find ALL robot pieces, including pieces added later. */ var pieces = document.querySelectorAll( "#twoSnapArea [data-piece]" ); for ( var i = 0; i < pieces.length; i++ ) { var piece = pieces[i]; var name = ( piece.getAttribute( "data-piece" ) || "" ).toUpperCase(); /* Arms + legs use darker shade. */ if ( name.indexOf("ARM") !== -1 || name.indexOf("LEG") !== -1 ) { piece.style.background = dark; } else { piece.style.background = main; } } if (status) { var display = colour.charAt(0) .toUpperCase() + colour.slice(1); status.textContent = "🎨 Character changed to " + display; } } for ( var i = 0; i < buttons.length; i++ ) { buttons[i].addEventListener( "click", function () { /* Remove selected outline. */ for ( var x = 0; x < buttons.length; x++ ) { buttons[x] .classList .remove( "activeColour" ); } this.classList.add( "activeColour" ); var colour = this.getAttribute( "data-colour" ); changeCharacter( colour ); } ); } if (status) { status.textContent = "✅ Colour changer loaded"; } }, 900);
setTimeout(function() { var area = document.getElementById( "twoSnapArea" ); var palette = document.getElementById( "dlcMiniPaletteV2" ); if ( !area || !palette ) { return; } /* MOVE THE PALETTE INTO THE CHARACTER BOX */ area.appendChild( palette ); var paint = document.getElementById( "dlcMiniPaint" ); var eyesButton = document.getElementById( "dlcMiniEyes" ); var colours = document.getElementById( "dlcMiniColours" ); var faces = document.getElementById( "dlcMiniFaces" ); paint.onclick = function() { colours.classList.toggle( "openMini" ); faces.classList.remove( "openMini" ); }; eyesButton.onclick = function() { faces.classList.toggle( "openMini" ); colours.classList.remove( "openMini" ); }; /* MINI COLOUR BUTTONS USE EXISTING WORKING COLOUR CHANGER */ var colourButtons = palette.querySelectorAll( "[data-mcolour]" ); colourButtons.forEach( function(button) { button.onclick = function() { var colour = button.getAttribute( "data-mcolour" ); var oldButton = document.querySelector( '.dlcColourChoice[data-colour="' + colour + '"]' ); if (oldButton) { oldButton.click(); } colours.classList.remove( "openMini" ); }; } ); /* FACE CHANGER DIRECTLY CHANGES THE ROBOT EYES */ function changeEyes( style ) { var eyes = area.querySelectorAll( ".twoEye" ); if (!eyes.length) { return; } eyes.forEach( function(eye) { eye.style.width = "11px"; eye.style.height = "11px"; eye.style.border = "0"; eye.style.borderRadius = "50%"; eye.style.background = "#1ef4df"; eye.style.transform = "none"; eye.style.boxShadow = "0 0 12px #1ef4df"; } ); /* HAPPY */ if ( style === "happy" ) { eyes.forEach( function(eye) { eye.style.width = "17px"; eye.style.height = "8px"; eye.style.background = "transparent"; eye.style.borderBottom = "4px solid #1ef4df"; eye.style.borderRadius = "50%"; } ); } /* ROBOT */ if ( style === "robot" ) { eyes.forEach( function(eye) { eye.style.width = "13px"; eye.style.height = "13px"; eye.style.borderRadius = "2px"; } ); } /* ANGRY */ if ( style === "angry" ) { eyes.forEach( function(eye,index) { eye.style.width = "17px"; eye.style.height = "7px"; eye.style.borderRadius = "8px"; eye.style.background = "#ff5f79"; eye.style.boxShadow = "0 0 10px #ff5f79"; if (index === 0) { eye.style.transform = "rotate(14deg)"; } else { eye.style.transform = "rotate(-14deg)"; } } ); } } var faceButtons = palette.querySelectorAll( "[data-mface]" ); faceButtons.forEach( function(button) { button.onclick = function() { var face = button.getAttribute( "data-mface" ); changeEyes( face ); faces.classList.remove( "openMini" ); }; } ); },1000);
setTimeout(function() { var body = document.getElementById( "twoBodyPiece" ); if (!body) { return; } /* DON'T ADD IT TWICE */ if ( document.getElementById( "dlcChestScreen" ) ) { return; } var screen = document.createElement( "div" ); screen.id = "dlcChestScreen"; screen.className = "dlcChestScreen"; screen.textContent = "DLC READY"; /* Put screen inside BODY above BODY label */ var bodyLabel = body.querySelector( "small" ); if (bodyLabel) { body.insertBefore( screen, bodyLabel ); } else { body.appendChild( screen ); } var messages = [ "DLC READY", "HELLO 👋", "ONLINE", "NEED HELP?", "DIGITAL 25" ]; var current = 0; screen.addEventListener( "pointerdown", function(event) { /* Stops touching the screen from accidentally dragging the whole body. */ event.stopPropagation(); } ); screen.addEventListener( "click", function(event) { event.stopPropagation(); current++; if ( current >= messages.length ) { current = 0; } screen.textContent = messages[ current ]; screen.classList.add( "dlcChestActive" ); setTimeout( function() { screen.classList.remove( "dlcChestActive" ); }, 350 ); } ); },1100);
setTimeout(function () { var body = document.getElementById("twoBodyPiece"); if (!body) return; /* ========================= CREATE CHEST TAP BUTTON ========================= */ var tap = document.createElement("div"); tap.className = "dlcChestTap"; tap.textContent = "DLC READY"; tap.style.position = "absolute"; tap.style.left = "50%"; tap.style.bottom = "31px"; tap.style.transform = "translateX(-50%)"; tap.style.width = "76px"; tap.style.height = "22px"; tap.style.display = "flex"; tap.style.alignItems = "center"; tap.style.justifyContent = "center"; tap.style.borderRadius = "7px"; tap.style.background = "#06131d"; tap.style.border = "1px solid #17566c"; tap.style.color = "#38cbe5"; tap.style.fontSize = "7px"; tap.style.fontWeight = "bold"; tap.style.letterSpacing = "1px"; tap.style.zIndex = "999"; tap.style.cursor = "pointer"; body.appendChild(tap); /* ========================= STOP BODY DRAG ========================= */ tap.addEventListener( "pointerdown", function(event) { event.preventDefault(); event.stopPropagation(); event.stopImmediatePropagation(); } ); tap.addEventListener( "pointerup", function(event) { event.preventDefault(); event.stopPropagation(); } ); /* ========================= SCREEN MESSAGES ========================= */ var messages = [ "DLC READY", "HELLO 👋", "ONLINE", "NEED HELP?", "SYSTEM OK" ]; var messageNumber = 0; tap.addEventListener( "click", function(event) { event.preventDefault(); event.stopPropagation(); messageNumber++; if ( messageNumber >= messages.length ) { messageNumber = 0; } tap.textContent = messages[ messageNumber ]; } ); /* ========================= CONNECTION LIGHT ========================= */ var light = body.querySelector( ".twoChestLight" ); function updateLight() { if (!light) return; if ( body.classList.contains( "twoFitted" ) ) { /* CONNECTED */ light.style.background = "#00e384"; light.style.boxShadow = "0 0 14px #00e384"; } else { /* DISCONNECTED */ light.style.background = "#ff304f"; light.style.boxShadow = "0 0 14px #ff304f"; } } updateLight(); /* Watch body snapping/unsnapping */ var observer = new MutationObserver( function() { updateLight(); } ); observer.observe( body, { attributes:true, attributeFilter:[ "class" ] } ); }, 1000);
setTimeout( function() { function blinkDlcEyes() { /* Look for whichever eye class exists in your current robot. */ var eyes = document.querySelectorAll( ".twoEye, .dlc3Eye, .dlc4Eye, .threeEye" ); if ( !eyes.length ) { return; } for ( var i = 0; i < eyes.length; i++ ) { eyes[i] .classList .remove( "dlcEyeBlink" ); /* Forces browser to restart the animation each time. */ void eyes[i].offsetWidth; eyes[i] .classList .add( "dlcEyeBlink" ); } } /* First blink after 2 seconds */ setTimeout( blinkDlcEyes, 2000 ); /* Then blink every 4 seconds */ setInterval( blinkDlcEyes, 4000 ); }, 1200 );
var music = document.getElementById("dlcMusic"); function headphonesOn() { music.currentTime = 0; music.play(); } function headphonesOff() { music.pause(); music.currentTime = 0; }
setTimeout(function() { var area = document.getElementById( "twoSnapArea" ); var headphones = document.getElementById( "dlcHeadphones" ); var head = document.getElementById( "twoHeadPiece" ); if ( !area || !headphones || !head ) { return; } /* Move headphones into the same game area. */ area.appendChild( headphones ); headphones.style.left = "20px"; headphones.style.top = ( area.clientHeight - 100 ) + "px"; var dragging = false; var offsetX = 0; var offsetY = 0; headphones.addEventListener( "pointerdown", function(event) { event.preventDefault(); dragging = true; var rect = headphones .getBoundingClientRect(); offsetX = event.clientX - rect.left; offsetY = event.clientY - rect.top; headphones.style.cursor = "grabbing"; } ); document.addEventListener( "pointermove", function(event) { if (!dragging) { return; } event.preventDefault(); var areaRect = area.getBoundingClientRect(); var x = event.clientX - areaRect.left - offsetX; var y = event.clientY - areaRect.top - offsetY; var maxX = area.clientWidth - headphones.offsetWidth; var maxY = area.clientHeight - headphones.offsetHeight; if (x < 0) { x = 0; } if (y < 0) { y = 0; } if (x > maxX) { x = maxX; } if (y > maxY) { y = maxY; } headphones.style.left = x + "px"; headphones.style.top = y + "px"; } ); document.addEventListener( "pointerup", function() { if (!dragging) { return; } dragging = false; headphones.style.cursor = "grab"; var headphoneRect = headphones .getBoundingClientRect(); var headRect = head .getBoundingClientRect(); var headphoneX = headphoneRect.left + headphoneRect.width / 2; var headphoneY = headphoneRect.top + headphoneRect.height / 2; var headX = headRect.left + headRect.width / 2; var headY = headRect.top + headRect.height / 2; var dx = Math.abs( headphoneX - headX ); var dy = Math.abs( headphoneY - headY ); /* If headphones are close to the robot head... */ if ( dx < 90 && dy < 80 ) { var areaRect = area.getBoundingClientRect(); headphones.style.left = ( headX - areaRect.left - headphones.offsetWidth / 2 ) + "px"; headphones.style.top = ( headRect.top - areaRect.top + 20 ) - "px"; headphones.classList.add( "headphonesOn" ); } else { headphones.classList.remove( "headphonesOn" ); } } ); }, 1000);
setTimeout( function() { var headphones = document.getElementById( "dlcHeadphones" ); if (!headphones) { return; } /* Add the missing right ear cup only once. */ if ( !headphones.querySelector( ".dlcRightCupVisual" ) ) { var rightCup = document.createElement( "div" ); rightCup.className = "dlcRightCupVisual"; headphones.appendChild( rightCup ); } }, 1200 );

ℹ️Terms and Conditions

📁 About DLC Digital Folder
Your everyday tools, organised in one place.
DLC Digital Folder is designed to make everyday organisation simpler.
The website brings together useful tools for managing money, bills, receipts, savings, calculations, notes and other everyday tasks — all inside one easy-to-use digital folder.
We're continually developing and improving DLC Digital Folder, with new tools and features being added over time.
Our aim is simple: create useful tools that are quick, straightforward and easy to access when you need them.
Some features may be experimental or updated as we continue to improve the website.
🔒 Privacy
Your privacy is important to us.
DLC Digital Folder aims to collect only the information necessary to operate and improve the website.
Some tools may save information locally within your browser or device so that your information can remain available when you return. Where information is stored locally, it may be removed if you clear your browser data, use another device or browser, or reset the relevant tool.
We may use website analytics to understand general information such as page visits, popular features, device/browser types and how visitors use the website. This helps us improve DLC Digital Folder.
If you contact us, we may receive information that you voluntarily provide, such as your name, email address and message, so that we can respond to your enquiry.
We do not intentionally sell your personal information.
Third-party services used by the website may operate under their own privacy policies.
Important: Please avoid entering highly sensitive information such as passwords, full payment-card details, PIN numbers or online banking login details into notes or other general-purpose fields on the website.
📜 Terms of Use
By using DLC Digital Folder, you agree to use the website and its tools responsibly.
The tools and information provided on this website are intended for general organisational and informational purposes.
Although we aim to make our calculators and tools as accurate and useful as possible, we cannot guarantee that every calculation, result or piece of information will always be complete or error-free.
You should check important financial calculations and information before making decisions based upon them.
Information provided by DLC Digital Folder should not be considered professional financial, tax, legal or investment advice.
You remain responsible for decisions you make using information or calculations provided by the website.
Features may be changed, improved, replaced or removed as DLC Digital Folder continues to develop.
We may also introduce new free or paid features in the future.
✉️ Contact
Need help, have a question, or found something that isn't working?
We'd love to hear from you.
You can also contact us if you have an idea for a feature you'd like to see added to DLC Digital Folder.
Email:
[ADD YOUR CONTACT EMAIL HERE]
You can also use the website contact form where available.
When reporting a problem, it can be helpful to tell us which device and browser you were using.
📢 Advertise With Us
Interested in advertising your business or service on DLC Digital Folder?
We may offer selected advertising and promotional spaces throughout the website.
Advertising opportunities could include business listings, featured placements or promotional areas within relevant sections of DLC Digital Folder.
We aim to keep advertising appropriate to the website and useful to our visitors.
Interested in advertising?
Contact us at:
[ADD YOUR ADVERTISING EMAIL HERE]
Please include your business name, website or social-media page and a short description of what you would like to advertise.
Advertising availability, placement and pricing may vary.
🤖 DLC Digital Folder
Useful tools. One digital folder.
DLC Digital Folder is continually evolving, so check back for new tools, improvements and features.

🧠Brain Training

🧠

Daily Brain Training

5 quick challenges to wake up your brain

TODAY--
BEST--
STREAK0 🔥
🧠

Today's Brain Workout

Logic • Numbers • Patterns • Attention • Reasoning

🤖 Come back tomorrow for a new challenge
window.dlcBrainQuestions = [ { category:"LOGIC", q:"Which number comes next? 2, 4, 8, 16, ?", answers:["18","24","32","36"], correct:2 }, { category:"NUMBERS", q:"What is 15% of 200?", answers:["20","25","30","35"], correct:2 }, { category:"PATTERN", q:"What comes next? ▲ ● ▲ ● ▲ ?", answers:["▲","●","■","◆"], correct:1 }, { category:"ATTENTION", q:"How many letters are in the word CONCENTRATION?", answers:["11","12","13","14"], correct:2 }, { category:"REASONING", q:"All Bloops are Razzies. All Razzies are Lazzies. Therefore all Bloops are...", answers:[ "Lazzies", "Not Lazzies", "Both", "Impossible to know" ], correct:0 }, { category:"NUMBERS", q:"Which number is missing? 5, 10, 20, 40, ?", answers:["50","60","70","80"], correct:3 }, { category:"LOGIC", q:"If yesterday was Monday, what day is tomorrow?", answers:[ "Monday", "Tuesday", "Wednesday", "Thursday" ], correct:2 }, { category:"PATTERN", q:"Which number comes next? 1, 4, 9, 16, ?", answers:["20","24","25","32"], correct:2 }, { category:"ATTENTION", q:"Which word is different?", answers:[ "APPLE", "APPLE", "APPEL", "APPLE" ], correct:2 }, { category:"NUMBERS", q:"A £40 item is reduced by £10. What percentage discount is that?", answers:[ "10%", "20%", "25%", "30%" ], correct:2 }, { category:"LOGIC", q:"A farmer has 12 sheep. All but 5 run away. How many remain?", answers:["5","7","12","17"], correct:0 }, { category:"PATTERN", q:"What comes next? 3, 6, 12, 24, ?", answers:["30","36","42","48"], correct:3 }, { category:"REASONING", q:"Which one does not belong?", answers:[ "Car", "Bus", "Train", "Apple" ], correct:3 }, { category:"NUMBERS", q:"What is half of 86?", answers:["41","42","43","44"], correct:2 }, { category:"ATTENTION", q:"How many times does the letter E appear in 'EVERY EVENING'?", answers:["3","4","5","6"], correct:1 }, { category:"LOGIC", q:"If 3 cats catch 3 mice in 3 minutes, how many cats are needed to catch 6 mice in 3 minutes?", answers:["3","4","6","9"], correct:2 }, { category:"PATTERN", q:"Which number comes next? 10, 9, 7, 4, ?", answers:["0","1","2","3"], correct:0 }, { category:"NUMBERS", q:"What is 7 × 8?", answers:["48","54","56","64"], correct:2 }, { category:"REASONING", q:"Book is to reading as fork is to...", answers:[ "Drawing", "Eating", "Walking", "Sleeping" ], correct:1 }, { category:"ATTENTION", q:"Which number appears twice? 17, 28, 39, 46, 28, 51", answers:["17","28","39","51"], correct:1 }, { category:"PATTERN", q:"What comes next? A, C, E, G, ?", answers:["H","I","J","K"], correct:1 }, { category:"NUMBERS", q:"If you save £5 each day for 7 days, how much have you saved?", answers:[ "£25", "£30", "£35", "£40" ], correct:2 }, { category:"LOGIC", q:"Which is heavier: 1kg of steel or 1kg of feathers?", answers:[ "Steel", "Feathers", "They weigh the same", "Cannot know" ], correct:2 }, { category:"ATTENTION", q:"Which spelling is correct?", answers:[ "Definately", "Definitely", "Definatly", "Definetly" ], correct:1 }, { category:"REASONING", q:"If every Zog is blue and this object is a Zog, what colour must it be?", answers:[ "Red", "Green", "Blue", "Unknown" ], correct:2 }, { category:"NUMBERS", q:"What is 144 divided by 12?", answers:["10","11","12","14"], correct:2 }, { category:"PATTERN", q:"Which number comes next? 100, 90, 80, 70, ?", answers:["50","55","60","65"], correct:2 }, { category:"LOGIC", q:"You have three apples and take away two. How many apples do you have?", answers:["1","2","3","5"], correct:1 }, { category:"REASONING", q:"Hand is to glove as foot is to...", answers:[ "Hat", "Sock", "Scarf", "Belt" ], correct:1 }, { category:"ATTENTION", q:"Which symbol appears most? ★ ◆ ★ ● ★ ◆", answers:[ "★", "◆", "●", "All equal" ], correct:0 } ];
(function(){ var attempts = 0; function startBrainGame(){ attempts++; /* WAIT FOR QUESTION BANK */ var questions = window.dlcBrainQuestions || []; /* WAIT FOR HTML */ var startScreen = document.getElementById( "brainStart" ); var gameScreen = document.getElementById( "brainGame" ); var resultScreen = document.getElementById( "brainResults" ); var startButton = document.getElementById( "brainStartButton" ); if( !questions.length || !startScreen || !gameScreen || !resultScreen || !startButton ){ if(attempts < 50){ setTimeout( startBrainGame, 100 ); } return; } /* STOP THIS BLOCK FROM INITIALISING TWICE */ if( startButton.dataset.brainReady === "yes" ){ return; } startButton.dataset.brainReady = "yes"; var questionText = document.getElementById( "brainQuestion" ); var answerArea = document.getElementById( "brainAnswers" ); var categoryText = document.getElementById( "brainCategory" ); var feedback = document.getElementById( "brainFeedback" ); var questionCount = document.getElementById( "brainQuestionCount" ); var liveScore = document.getElementById( "brainLiveScore" ); var progressBar = document.getElementById( "brainProgressBar" ); /* ========================= DATE ========================= */ var today = new Date(); var dateKey = today.getFullYear() + "-" + String( today.getMonth()+1 ).padStart(2,"0") + "-" + String( today.getDate() ).padStart(2,"0"); var dateDisplay = document.getElementById( "brainDate" ); if(dateDisplay){ dateDisplay.textContent = today.toLocaleDateString( "en-GB", { weekday:"long", day:"numeric", month:"long" } ); } /* ========================= DAILY QUESTION SELECTION ========================= */ function dateSeed(){ return ( today.getFullYear() * 10000 + (today.getMonth()+1) * 100 + today.getDate() ); } function seededRandom(seed){ var x = Math.sin(seed) * 10000; return x - Math.floor(x); } function getDailyQuestions(){ var pool = questions.slice(); var selected = []; var seed = dateSeed(); while( selected.length < 5 && pool.length ){ var random = seededRandom( seed + selected.length * 71 ); var index = Math.floor( random * pool.length ); selected.push( pool[index] ); pool.splice( index, 1 ); } return selected; } var dailyQuestions = getDailyQuestions(); /* ========================= STORAGE ========================= */ var storageKey = "dlcBrainScores"; var scores = {}; try{ scores = JSON.parse( localStorage.getItem( storageKey ) ) || {}; } catch(e){ scores = {}; } function saveScores(){ try{ localStorage.setItem( storageKey, JSON.stringify( scores ) ); } catch(e){ } } function getBest(){ var values = Object.values( scores ); if(!values.length){ return 0; } return Math.max.apply( null, values ); } function dayKeyOffset(offset){ var d = new Date(); d.setDate( d.getDate() + offset ); return d.getFullYear() + "-" + String( d.getMonth()+1 ).padStart(2,"0") + "-" + String( d.getDate() ).padStart(2,"0"); } function calculateStreak(){ var streak = 0; var offset = 0; if( scores[dateKey] === undefined ){ offset = -1; } while(true){ var key = dayKeyOffset( offset ); if( scores[key] === undefined ){ break; } streak++; offset--; } return streak; } /* ========================= TOP STATS ========================= */ function updateStats(){ var todayScore = scores[dateKey]; document.getElementById( "brainToday" ).textContent = todayScore !== undefined ? todayScore + "/100" : "--"; var best = getBest(); document.getElementById( "brainBest" ).textContent = best ? best + "/100" : "--"; document.getElementById( "brainStreak" ).textContent = calculateStreak() + " 🔥"; } window.dlcBrainScores = scores; window.dlcBrainDateKey = dateKey; window.dlcBrainGetBest = getBest; window.dlcBrainGetStreak = calculateStreak; updateStats(); /* ========================= GAME STATE ========================= */ var current = 0; var correct = 0; var score = 0; var locked = false; /* ALREADY DONE TODAY */ if( scores[dateKey] !== undefined ){ document.getElementById( "brainAlreadyDone" ).textContent = "✅ Today's challenge already completed"; startButton.textContent = "📈 View Today's Result"; } /* ========================= START BUTTON ========================= */ startButton.addEventListener( "click", function(){ /* TODAY ALREADY COMPLETED */ if( scores[dateKey] !== undefined ){ showResultSafely( scores[dateKey], Math.round( scores[dateKey] / 20 ) ); return; } /* START NEW GAME */ current = 0; correct = 0; score = 0; startScreen.style.display = "none"; gameScreen.style.display = "block"; resultScreen.style.display = "none"; showQuestion(); } ); /* ========================= SHOW QUESTION ========================= */ function showQuestion(){ locked = false; var item = dailyQuestions[ current ]; questionCount.textContent = "Question " + (current + 1) + " of 5"; liveScore.textContent = score + " points"; progressBar.style.width = ( (current + 1) * 20 ) + "%"; categoryText.textContent = item.category; questionText.textContent = item.q; feedback.textContent = ""; answerArea.innerHTML = ""; for( var i = 0; i < item.answers.length; i++ ){ var button = document.createElement( "button" ); button.type = "button"; button.className = "brainAnswer"; button.textContent = item.answers[i]; button.dataset.index = i; button.addEventListener( "click", answerQuestion ); answerArea.appendChild( button ); } } /* ========================= ANSWER QUESTION ========================= */ function answerQuestion(){ if(locked){ return; } locked = true; var chosen = parseInt( this.dataset.index ); var item = dailyQuestions[ current ]; var buttons = answerArea.querySelectorAll( ".brainAnswer" ); if( chosen === item.correct ){ correct++; score += 20; this.classList.add( "correct" ); feedback.textContent = "✅ Correct! +20"; } else{ this.classList.add( "wrong" ); buttons[ item.correct ] .classList.add( "correct" ); feedback.textContent = "❌ Not quite"; } liveScore.textContent = score + " points"; setTimeout( function(){ current++; if( current >= 5 ){ scores[ dateKey ] = score; saveScores(); window.dlcBrainScores = scores; updateStats(); showResultSafely( score, correct ); } else{ showQuestion(); } }, 850 ); } /* ========================= WAIT FOR RESULTS BLOCK ========================= */ function showResultSafely( finalScore, correctAnswers ){ var start = document.getElementById( "brainStart" ); var game = document.getElementById( "brainGame" ); var results = document.getElementById( "brainResults" ); if( !start || !game || !results ){ return; } /* OPEN RESULT SCREEN DIRECTLY */ start.style.display = "none"; game.style.display = "none"; results.style.display = "block"; /* SCORE */ var scoreBox = document.getElementById( "brainFinalScore" ); if(scoreBox){ scoreBox.textContent = finalScore; } /* CORRECT ANSWERS */ var correctBox = document.getElementById( "resultCorrect" ); if(correctBox){ correctBox.textContent = correctAnswers + "/5"; } /* BEST SCORE */ var bestBox = document.getElementById( "resultBest" ); if(bestBox){ bestBox.textContent = getBest(); } /* STREAK */ var streakBox = document.getElementById( "resultStreak" ); if(streakBox){ streakBox.textContent = calculateStreak() + " 🔥"; } /* RESULT MESSAGE */ var title = document.getElementById( "brainResultTitle" ); var message = document.getElementById( "brainResultMessage" ); if(finalScore === 100){ if(title){ title.textContent = "Perfect score! 🏆"; } if(message){ message.textContent = "5 out of 5 — excellent work."; } } else if(finalScore >= 80){ if(title){ title.textContent = "Excellent work! ⚡"; } if(message){ message.textContent = "Your brain is definitely switched on."; } } else if(finalScore >= 60){ if(title){ title.textContent = "Nice work! 👏"; } if(message){ message.textContent = "A solid daily brain workout."; } } else{ if(title){ title.textContent = "Brain activated 🧠"; } if(message){ message.textContent = "Come back tomorrow and try again."; } } /* NOW ASK BLOCK 4 TO DRAW THE GRAPH, IF IT IS READY. */ setTimeout( function(){ if( typeof window .dlcBrainDrawGraph === "function" ){ window.dlcBrainDrawGraph(); } }, 150 ); } /* ========================= DONE BUTTON ========================= */ var doneButton = document.getElementById( "brainDoneButton" ); if(doneButton){ doneButton.addEventListener( "click", function(){ resultScreen.style.display = "none"; gameScreen.style.display = "none"; startScreen.style.display = "block"; document.getElementById( "brainAlreadyDone" ).textContent = "✅ Today's challenge completed — come back tomorrow"; startButton.textContent = "📈 View Today's Result"; } ); } /* SUCCESS MESSAGE FOR TESTING — SAFE TO KEEP */ console.log( "DLC Brain Training loaded ✓" ); } /* START, BUT ALLOW CARRD TIME TO LOAD BLOCKS */ setTimeout( startBrainGame, 100 ); })();
(function(){ var STORAGE = "dlcBrainScores"; /* ========================= GET SCORES ========================= */ function getScores(){ try{ return JSON.parse( localStorage.getItem( STORAGE ) ) || {}; } catch(e){ return {}; } } /* ========================= TODAY KEY ========================= */ function getTodayKey(){ var d = new Date(); return d.getFullYear() + "-" + String( d.getMonth()+1 ).padStart(2,"0") + "-" + String( d.getDate() ).padStart(2,"0"); } /* ========================= BEST SCORE ========================= */ function getBest(scores){ var values = Object.values( scores ); if(!values.length){ return 0; } return Math.max.apply( null, values ); } /* ========================= STREAK ========================= */ function getStreak(scores){ var streak = 0; var d = new Date(); if( scores[getTodayKey()] === undefined ){ d.setDate( d.getDate()-1 ); } while(true){ var key = d.getFullYear() + "-" + String( d.getMonth()+1 ).padStart(2,"0") + "-" + String( d.getDate() ).padStart(2,"0"); if( scores[key] === undefined ){ break; } streak++; d.setDate( d.getDate()-1 ); } return streak; } /* ========================= SHOW RESULT ========================= */ function showResult( score, correct ){ var start = document.getElementById( "brainStart" ); var game = document.getElementById( "brainGame" ); var results = document.getElementById( "brainResults" ); if( !start || !game || !results ){ return; } start.style.display = "none"; game.style.display = "none"; results.style.display = "block"; var finalScore = document.getElementById( "brainFinalScore" ); if(finalScore){ finalScore.textContent = score; } /* RESULT TEXT */ var title = "Brain warmed up!"; var message = "Come back tomorrow and try to beat today's score."; if(score === 100){ title = "Perfect score! 🏆"; message = "5 out of 5 — excellent work."; } else if(score >= 80){ title = "Excellent work! ⚡"; message = "Your brain is definitely switched on."; } else if(score >= 60){ title = "Nice work! 👏"; message = "A solid daily brain workout."; } else if(score >= 40){ title = "Good warm-up 👍"; message = "Tomorrow gives you another chance."; } else{ title = "Brain activated 🧠"; message = "Daily practice is what matters."; } var resultTitle = document.getElementById( "brainResultTitle" ); if(resultTitle){ resultTitle.textContent = title; } var resultMessage = document.getElementById( "brainResultMessage" ); if(resultMessage){ resultMessage.textContent = message; } /* RESULT STATS */ var scores = getScores(); var bestBox = document.getElementById( "resultBest" ); if(bestBox){ bestBox.textContent = getBest( scores ); } var streakBox = document.getElementById( "resultStreak" ); if(streakBox){ streakBox.textContent = getStreak( scores ) + " 🔥"; } var correctBox = document.getElementById( "resultCorrect" ); if(correctBox){ correctBox.textContent = correct + "/5"; } /* WAIT BRIEFLY UNTIL THE RESULT PANEL IS VISIBLE */ setTimeout( drawGraph, 100 ); } /* MAKE RESULT FUNCTION AVAILABLE TO BLOCK 3 */ window.dlcBrainShowResult = showResult; /* ========================= VIEW TODAY'S RESULT BUTTON ========================= */ function connectButton(){ var button = document.getElementById( "brainStartButton" ); if(!button){ setTimeout( connectButton, 150 ); return; } if( button.dataset.resultController === "yes" ){ return; } button.dataset.resultController = "yes"; button.addEventListener( "click", function(event){ var scores = getScores(); var key = getTodayKey(); if( scores[key] === undefined ){ return; } event.preventDefault(); event.stopImmediatePropagation(); var score = scores[key]; showResult( score, Math.round( score / 20 ) ); }, true ); } connectButton(); /* ========================= SIMPLE HTML WEEK GRAPH ========================= */ function drawGraph(){ var chart = document.getElementById( "brainWeekBars" ); if(!chart){ return; } var scores = getScores(); /* CLEAR OLD BARS */ chart.innerHTML = ""; var dayNames = [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ]; var completed = []; /* ========================= LAST 7 DAYS ========================= */ for( var offset=-6; offset<=0; offset++ ){ var d = new Date(); /* NOON HELPS AVOID DATE/DST ODDITIES */ d.setHours( 12, 0, 0, 0 ); d.setDate( d.getDate() + offset ); var key = d.getFullYear() + "-" + String( d.getMonth()+1 ).padStart(2,"0") + "-" + String( d.getDate() ).padStart(2,"0"); var storedScore = scores[key]; var hasScore = storedScore !== undefined; var score = hasScore ? storedScore : 0; /* ONE DAY COLUMN */ var day = document.createElement( "div" ); day.className = "brainDayBar"; if(offset === 0){ day.classList.add( "today" ); } if(!hasScore){ day.classList.add( "empty" ); } else{ completed.push( score ); } /* SCORE NUMBER */ var scoreLabel = document.createElement( "div" ); scoreLabel.className = "brainBarScore"; scoreLabel.textContent = hasScore ? score : "--"; /* BAR */ var bar = document.createElement( "div" ); bar.className = "brainBarFill"; bar.style.setProperty( "--brain-score", score ); /* DAY NAME */ var dayLabel = document.createElement( "div" ); dayLabel.className = "brainDayName"; dayLabel.textContent = dayNames[ d.getDay() ]; /* BUILD DAY */ day.appendChild( scoreLabel ); day.appendChild( bar ); day.appendChild( dayLabel ); chart.appendChild( day ); } /* ========================= TREND ========================= */ var trend = document.getElementById( "brainTrend" ); if(!trend){ return; } if( completed.length === 0 ){ trend.textContent = ""; } else if( completed.length === 1 ){ trend.textContent = "Day 1"; } else{ var latest = completed[ completed.length - 1 ]; var previous = completed[ completed.length - 2 ]; var difference = latest - previous; if( difference > 0 ){ trend.textContent = "↑ +" + difference; } else if( difference < 0 ){ trend.textContent = "↓ " + Math.abs( difference ); } else{ trend.textContent = "→ Same"; } } } /* MAKE GRAPH AVAILABLE TO BLOCK 3 */ window.dlcBrainDrawGraph = drawGraph; /* ========================= REDRAW ON RESIZE ========================= */ window.addEventListener( "resize", function(){ var results = document.getElementById( "brainResults" ); if( results && results.style.display !== "none" ){ drawGraph(); } } ); })();

📝 Notes

📝 My Notes

const notesBox = document.getElementById("myNotes"); notesBox.value = localStorage.getItem("binderNotes") || ""; function saveNotes() { localStorage.setItem("binderNotes", notesBox.value); document.getElementById("noteStatus").innerText = "Saved ✓"; } function clearNotes() { notesBox.value = ""; localStorage.removeItem("binderNotes"); document.getElementById("noteStatus").innerText = "Cleared"; }

✏️Draw

🎨

Drawing Pad

Draw, write, highlight and save your ideas

const canvas = document.getElementById( "drawingCanvas" ); const ctx = canvas.getContext("2d"); const toolSelect = document.getElementById( "toolSelect" ); const sizeSelect = document.getElementById( "sizeSelect" ); const colourPicker = document.getElementById( "colourPicker" ); const statusText = document.getElementById( "drawStatus" ); let drawing = false; let startX = 0; let startY = 0; let lastX = 0; let lastY = 0; let undoStack = []; let shapeSnapshot = null; /* ========================= SET UP CANVAS SIZE ========================= */ function setupCanvas() { const rect = canvas.getBoundingClientRect(); const ratio = window.devicePixelRatio || 1; canvas.width = Math.round( rect.width * ratio ); canvas.height = Math.round( rect.height * ratio ); ctx.setTransform( ratio, 0, 0, ratio, 0, 0 ); ctx.fillStyle = "#ffffff"; ctx.fillRect( 0, 0, rect.width, rect.height ); } /* wait until Carrd has laid out page */ setTimeout( setupCanvas, 200 ); /* ========================= STOP MOBILE SCROLLING WHILE DRAWING ========================= */ canvas.addEventListener( "touchstart", function(e) { e.preventDefault(); }, { passive: false } ); canvas.addEventListener( "touchmove", function(e) { e.preventDefault(); }, { passive: false } ); /* ========================= SAVE STATE ========================= */ function saveState() { if ( undoStack.length >= 20 ) { undoStack.shift(); } undoStack.push( canvas.toDataURL() ); } /* ========================= POINTER POSITION ========================= */ function getPosition(e) { const rect = canvas.getBoundingClientRect(); return { x: e.clientX - rect.left, y: e.clientY - rect.top }; } /* ========================= DRAWING STYLE ========================= */ function applyToolStyle( tool, size ) { ctx.globalAlpha = 1; ctx.lineJoin = "round"; ctx.lineCap = "round"; /* PEN */ if ( tool === "pen" ) { ctx.strokeStyle = colourPicker.value; ctx.lineWidth = size; } /* FELT TIP */ else if ( tool === "felt" ) { ctx.strokeStyle = colourPicker.value; ctx.lineWidth = size * 1.8; ctx.globalAlpha = 0.9; } /* HIGHLIGHTER */ else if ( tool === "highlighter" ) { ctx.strokeStyle = colourPicker.value; ctx.lineWidth = size * 3; ctx.globalAlpha = 0.28; ctx.lineCap = "square"; } /* ERASER */ else if ( tool === "eraser" ) { ctx.strokeStyle = "#ffffff"; ctx.lineWidth = size * 3; } /* SHAPES */ else { ctx.strokeStyle = colourPicker.value; ctx.lineWidth = size; ctx.globalAlpha = 1; } } /* ========================= START DRAWING ========================= */ canvas.addEventListener( "pointerdown", function(e) { e.preventDefault(); saveState(); drawing = true; const pos = getPosition(e); startX = pos.x; startY = pos.y; lastX = pos.x; lastY = pos.y; const tool = toolSelect.value; /* save image before shape */ if ( tool === "line" || tool === "rectangle" || tool === "circle" || tool === "triangle" ) { shapeSnapshot = ctx.getImageData( 0, 0, canvas.width, canvas.height ); } try { canvas.setPointerCapture( e.pointerId ); } catch (err) { /* some browsers do not need this */ } } ); /* ========================= DRAW ========================= */ canvas.addEventListener( "pointermove", function(e) { if (!drawing) { return; } e.preventDefault(); const pos = getPosition(e); const tool = toolSelect.value; const size = parseFloat( sizeSelect.value ); /* ===================== FREEHAND ===================== */ if ( tool === "pen" || tool === "felt" || tool === "highlighter" || tool === "eraser" ) { applyToolStyle( tool, size ); ctx.beginPath(); ctx.moveTo( lastX, lastY ); ctx.lineTo( pos.x, pos.y ); ctx.stroke(); lastX = pos.x; lastY = pos.y; return; } /* ===================== SHAPE PREVIEW ===================== */ if ( shapeSnapshot ) { ctx.putImageData( shapeSnapshot, 0, 0 ); } applyToolStyle( tool, size ); /* LINE */ if ( tool === "line" ) { ctx.beginPath(); ctx.moveTo( startX, startY ); ctx.lineTo( pos.x, pos.y ); ctx.stroke(); } /* RECTANGLE */ else if ( tool === "rectangle" ) { ctx.strokeRect( startX, startY, pos.x - startX, pos.y - startY ); } /* CIRCLE / OVAL */ else if ( tool === "circle" ) { const centreX = (startX + pos.x) / 2; const centreY = (startY + pos.y) / 2; const radiusX = Math.abs( pos.x - startX ) / 2; const radiusY = Math.abs( pos.y - startY ) / 2; ctx.beginPath(); ctx.ellipse( centreX, centreY, radiusX, radiusY, 0, 0, Math.PI * 2 ); ctx.stroke(); } /* TRIANGLE */ else if ( tool === "triangle" ) { const midpointX = ( startX + pos.x ) / 2; ctx.beginPath(); ctx.moveTo( midpointX, startY ); ctx.lineTo( pos.x, pos.y ); ctx.lineTo( startX, pos.y ); ctx.closePath(); ctx.stroke(); } } ); /* ========================= STOP DRAWING ========================= */ function stopDrawing() { drawing = false; shapeSnapshot = null; ctx.globalAlpha = 1; } canvas.addEventListener( "pointerup", stopDrawing ); canvas.addEventListener( "pointercancel", stopDrawing ); /* don't use pointerleave here — pointer capture lets you keep drawing naturally to the edge */ /* ========================= QUICK COLOURS ========================= */ document .querySelectorAll( ".colour-dot" ) .forEach( function(button) { button.addEventListener( "click", function() { colourPicker.value = this.dataset.colour; } ); } ); /* ========================= UNDO ========================= */ function undoDrawing() { if ( undoStack.length === 0 ) { statusText.textContent = "Nothing to undo"; return; } const previous = undoStack.pop(); const img = new Image(); img.onload = function() { ctx.globalAlpha = 1; ctx.setTransform( 1, 0, 0, 1, 0, 0 ); ctx.clearRect( 0, 0, canvas.width, canvas.height ); ctx.drawImage( img, 0, 0, canvas.width, canvas.height ); const ratio = window.devicePixelRatio || 1; ctx.setTransform( ratio, 0, 0, ratio, 0, 0 ); statusText.textContent = "Undone ✓"; }; img.src = previous; } /* ========================= CLEAR ========================= */ function clearDrawing() { saveState(); const rect = canvas.getBoundingClientRect(); ctx.globalAlpha = 1; ctx.fillStyle = "#ffffff"; ctx.fillRect( 0, 0, rect.width, rect.height ); statusText.textContent = "Canvas cleared ✓"; } /* ========================= SAVE DRAWING ========================= */ function saveDrawing() { const link = document.createElement( "a" ); link.download = "my-drawing.png"; link.href = canvas.toDataURL( "image/png" ); link.click(); statusText.textContent = "Drawing saved ✓"; }
setTimeout(function() { /* ========================= FIND EXISTING DRAWING PAD ========================= */ var fillCanvas = document.getElementById( "drawingCanvas" ); var fillToolSelect = document.getElementById( "toolSelect" ); var fillColourPicker = document.getElementById( "colourPicker" ); var fillStatus = document.getElementById( "drawStatus" ); if ( !fillCanvas || !fillToolSelect || !fillColourPicker ) { return; } var fillCtx = fillCanvas.getContext( "2d" ); /* ========================= ADD FILL TO TOOL MENU ========================= */ var existingFill = fillToolSelect.querySelector( 'option[value="fill"]' ); if (!existingFill) { var fillOption = document.createElement( "option" ); fillOption.value = "fill"; fillOption.textContent = "🪣 Fill"; /* Put Fill before Eraser */ var eraserOption = fillToolSelect.querySelector( 'option[value="eraser"]' ); if (eraserOption) { fillToolSelect.insertBefore( fillOption, eraserOption ); } else { fillToolSelect.appendChild( fillOption ); } } /* ========================= TOOL CURSOR ========================= */ fillToolSelect.addEventListener( "change", function() { if ( fillToolSelect.value === "fill" ) { fillCanvas.classList.add( "dlc-fill-mode" ); if (fillStatus) { fillStatus.textContent = "🪣 Tap inside a closed area to fill it"; } } else { fillCanvas.classList.remove( "dlc-fill-mode" ); } } ); /* ========================= HEX COLOUR TO RGB ========================= */ function fillHexToRGB(hex) { hex = hex.replace( "#", "" ); if ( hex.length === 3 ) { hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; } return { r: parseInt( hex.substring( 0, 2 ), 16 ), g: parseInt( hex.substring( 2, 4 ), 16 ), b: parseInt( hex.substring( 4, 6 ), 16 ), a:255 }; } /* ========================= PIXEL MATCH ========================= */ function fillMatches( data, index, colour ) { /* Small tolerance helps with slightly anti-aliased pixels. */ var tolerance = 18; return ( Math.abs( data[index] - colour.r ) <= tolerance && Math.abs( data[index + 1] - colour.g ) <= tolerance && Math.abs( data[index + 2] - colour.b ) <= tolerance && Math.abs( data[index + 3] - colour.a ) <= tolerance ); } /* ========================= PAINT ONE PIXEL ========================= */ function fillPixel( data, index, colour ) { data[index] = colour.r; data[index + 1] = colour.g; data[index + 2] = colour.b; data[index + 3] = 255; } /* ========================= FLOOD FILL ========================= */ function floodFill( startX, startY, newColour ) { var width = fillCanvas.width; var height = fillCanvas.height; if ( startX < 0 || startY < 0 || startX >= width || startY >= height ) { return; } var imageData = fillCtx.getImageData( 0, 0, width, height ); var data = imageData.data; var startIndex = ( startY * width + startX ) * 4; var oldColour = { r: data[ startIndex ], g: data[ startIndex + 1 ], b: data[ startIndex + 2 ], a: data[ startIndex + 3 ] }; /* Don't refill an area that is already basically this colour. */ if ( Math.abs( oldColour.r - newColour.r ) < 5 && Math.abs( oldColour.g - newColour.g ) < 5 && Math.abs( oldColour.b - newColour.b ) < 5 ) { if (fillStatus) { fillStatus.textContent = "That area is already this colour"; } return; } /* Scan-line flood fill. Much faster than checking every pixel with a normal recursive function. */ var stack = [ startX, startY ]; while ( stack.length ) { var y = stack.pop(); var x = stack.pop(); var currentY = y; var pixelIndex = ( currentY * width + x ) * 4; /* Move upward until we reach the boundary. */ while ( currentY >= 0 && fillMatches( data, pixelIndex, oldColour ) ) { currentY--; pixelIndex -= width * 4; } currentY++; pixelIndex = ( currentY * width + x ) * 4; var leftFound = false; var rightFound = false; /* Now travel downward, painting the vertical line. */ while ( currentY < height && fillMatches( data, pixelIndex, oldColour ) ) { fillPixel( data, pixelIndex, newColour ); /* LEFT */ if ( x > 0 ) { var leftIndex = pixelIndex - 4; if ( fillMatches( data, leftIndex, oldColour ) ) { if ( !leftFound ) { stack.push( x - 1, currentY ); leftFound = true; } } else { leftFound = false; } } /* RIGHT */ if ( x < width - 1 ) { var rightIndex = pixelIndex + 4; if ( fillMatches( data, rightIndex, oldColour ) ) { if ( !rightFound ) { stack.push( x + 1, currentY ); rightFound = true; } } else { rightFound = false; } } currentY++; pixelIndex += width * 4; } } fillCtx.putImageData( imageData, 0, 0 ); if (fillStatus) { fillStatus.textContent = "🪣 Area filled ✓"; } } /* ========================= INTERCEPT FILL TAP ========================= */ fillCanvas.addEventListener( "pointerdown", function(event) { if ( fillToolSelect.value !== "fill" ) { return; } /* VERY IMPORTANT: Stop the original drawing code from treating this tap as a normal drawing stroke. */ event.preventDefault(); event.stopPropagation(); event.stopImmediatePropagation(); /* Save into your existing Undo system before filling. */ if ( typeof saveState === "function" ) { saveState(); } var rect = fillCanvas .getBoundingClientRect(); /* Convert screen position to actual canvas pixels. This keeps it accurate on Samsung Fold, iPhone, desktop and high-DPI screens. */ var scaleX = fillCanvas.width / rect.width; var scaleY = fillCanvas.height / rect.height; var x = Math.floor( ( event.clientX - rect.left ) * scaleX ); var y = Math.floor( ( event.clientY - rect.top ) * scaleY ); var colour = fillHexToRGB( fillColourPicker.value ); floodFill( x, y, colour ); }, true ); if (fillStatus) { fillStatus.textContent = "✅ Fill tool added"; } }, 700);