Created
March 3, 2025 01:14
-
-
Save colorincode/46ad47e80d00c2358c5b452aaa16eaca to your computer and use it in GitHub Desktop.
measurer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import gsap from "https://esm.sh/gsap"; | |
import { TextPlugin } from "https://esm.sh/gsap/all"; | |
import { EasePack } from "https://esm.sh/gsap/EasePack"; | |
import confetti from "https://esm.sh/canvas-confetti"; | |
gsap.registerPlugin(TextPlugin, EasePack); | |
let currentStep = 1; | |
const totalSteps = 10; | |
const quizData = {}; | |
let unit = 'inches'; | |
const steps = document.querySelectorAll('.step'); | |
const prevBtn = document.getElementById('prev-btn'); | |
const nextBtn = document.getElementById('next-btn'); | |
const submitBtn = document.getElementById('submit-btn'); | |
const resultDiv = document.getElementById('result'); | |
const unitInputs = document.querySelectorAll('input[name="unit"]'); | |
const toCm = (value) => unit === 'inches' ? value * 2.54 : value; | |
const toKg = (value) => unit === 'inches' ? value * 0.453592 : value; | |
unitInputs.forEach(input => { | |
input.addEventListener('change', () => { | |
unit = input.value; | |
}); | |
}); | |
function animateStepTransition(outStep, inStep) { | |
gsap.timeline() | |
.to(outStep, { opacity: 0, x: -50, duration: 0.3, onComplete: () => outStep.style.display = 'none' }) | |
.fromTo(inStep, { opacity: 0, x: 50 }, { opacity: 1, x: 0, duration: 0.3, onStart: () => inStep.style.display = 'block' }); | |
} | |
function updateButtons() { | |
prevBtn.disabled = currentStep === 1; | |
nextBtn.style.display = currentStep === totalSteps ? 'none' : 'inline-block'; | |
submitBtn.style.display = currentStep === totalSteps ? 'inline-block' : 'none'; | |
} | |
function validateStep() { | |
const input = steps[currentStep - 1].querySelector('input, select'); | |
if (currentStep <= 9) { | |
const valueRaw = input.value ? parseFloat(input.value) : NaN; | |
if (isNaN(valueRaw)) { | |
alert(`Please enter a valid ${currentStep === 1 ? 'height' : currentStep === 2 ? 'arm span' : currentStep === 3 ? 'nose size' : currentStep === 4 ? 'finger length' : currentStep === 5 ? 'age' : currentStep === 6 ? 'weight' : currentStep === 7 ? 'number of partners' : currentStep === 8 ? 'hairiness' : 'shoe size'}.`); | |
return false; | |
} | |
let value; | |
switch (currentStep) { | |
case 1: // Height | |
value = unit === 'inches' ? Math.max(47, Math.min(98, valueRaw)) : Math.max(120, Math.min(250, valueRaw)); | |
quizData.height = toCm(value); | |
// console.log(`Height stored: ${quizData.height} cm (clamped from ${valueRaw} ${unit})`); | |
break; | |
case 2: // Arm Span | |
value = unit === 'inches' ? Math.max(43, Math.min(106, valueRaw)) : Math.max(110, Math.min(270, valueRaw)); | |
quizData.armSpan = toCm(value); | |
// console.log(`Arm Span stored: ${quizData.armSpan} cm (clamped from ${valueRaw} ${unit})`); | |
break; | |
case 3: // Nose Size | |
value = unit === 'inches' ? Math.max(0.8, Math.min(3.5, valueRaw)) : Math.max(2, Math.min(9, valueRaw)); | |
quizData.nose = toCm(value); | |
// console.log(`Nose stored: ${quizData.nose} cm (clamped from ${valueRaw} ${unit})`); | |
break; | |
case 4: // Finger Lengths | |
const indexInput = document.getElementById('index-finger'); | |
const ringInput = document.getElementById('ring-finger'); | |
const indexRaw = indexInput.value ? parseFloat(indexInput.value) : NaN; | |
const ringRaw = ringInput.value ? parseFloat(ringInput.value) : NaN; | |
if (isNaN(indexRaw)) { | |
alert('Please enter a valid index finger length.'); | |
return false; | |
} | |
if (isNaN(ringRaw)) { | |
alert('Please enter a valid ring finger length.'); | |
return false; | |
} | |
const index = unit === 'inches' ? Math.max(1.6, Math.min(4.7, indexRaw)) : Math.max(4, Math.min(12, indexRaw)); | |
const ring = unit === 'inches' ? Math.max(1.6, Math.min(4.7, ringRaw)) : Math.max(4, Math.min(12, ringRaw)); | |
quizData.indexFinger = toCm(index); | |
quizData.ringFinger = toCm(ring); | |
// console.log(`Index Finger stored: ${quizData.indexFinger} cm (clamped from ${indexRaw} ${unit}), Ring Finger stored: ${quizData.ringFinger} cm (clamped from ${ringRaw} ${unit})`); | |
break; | |
case 5: // Age | |
value = Math.max(18, Math.min(100, valueRaw)); | |
quizData.age = value; | |
// console.log(`Age stored: ${quizData.age} years (clamped from ${valueRaw})`); | |
break; | |
case 6: // Weight | |
value = unit === 'inches' ? Math.max(80, Math.min(500, valueRaw)) : Math.max(36, Math.min(227, valueRaw)); | |
quizData.weight = toKg(value); | |
// console.log(`Weight stored: ${quizData.weight} kg (clamped from ${valueRaw} ${unit === 'inches' ? 'lbs' : 'kg'})`); | |
break; | |
case 7: // Number of Partners (Decoy) | |
value = Math.max(0, Math.min(100, valueRaw)); | |
quizData.partners = value; | |
// console.log(`Partners stored: ${quizData.partners} (clamped from ${valueRaw})`); | |
break; | |
case 8: // Hairiness | |
value = Math.max(1, Math.min(5, valueRaw)); | |
quizData.hairiness = value; | |
// console.log(`Hairiness stored: ${quizData.hairiness} (clamped from ${valueRaw})`); | |
break; | |
case 9: // Shoe Size (Decoy) | |
value = Math.max(4, Math.min(18, valueRaw)); | |
quizData.shoeSize = value; | |
// console.log(`Shoe Size stored: ${quizData.shoeSize} (clamped from ${valueRaw})`); | |
break; | |
} | |
} else if (currentStep === 10) { | |
const value = input.value.trim(); | |
if (!value) { | |
alert('Please enter your first name or nickname.'); | |
return false; | |
} | |
quizData.nickname = value; | |
// console.log(`Nickname stored: ${quizData.nickname}`); | |
} | |
return true; | |
} | |
prevBtn.addEventListener('click', () => { | |
if (currentStep > 1) { | |
const current = steps[currentStep - 1]; | |
const previous = steps[currentStep - 2]; | |
currentStep--; | |
animateStepTransition(current, previous); | |
updateButtons(); | |
} | |
}); | |
nextBtn.addEventListener('click', () => { | |
if (validateStep() && currentStep < totalSteps) { | |
const current = steps[currentStep - 1]; | |
const next = steps[currentStep]; | |
currentStep++; | |
animateStepTransition(current, next); | |
updateButtons(); | |
} | |
}); | |
submitBtn.addEventListener('click', () => { | |
if (validateStep()) { | |
const { height, armSpan, nose, indexFinger, ringFinger, age, weight, hairiness, nickname } = quizData; | |
// console.log(`Final Values - Height: ${height}, Arm Span: ${armSpan}, Nose: ${nose}, Index: ${indexFinger}, Ring: ${ringFinger}, Age: ${age}, Weight: ${weight}, Hairiness: ${hairiness}, Nickname: ${nickname}`); | |
const splBase = (0.09 * height + 0.09 * armSpan + 2.8 * nose) / 3; | |
const splAge = -0.01 * (age - 30); | |
const splWeight = -0.005 * (weight - 68); | |
const splHairiness = 0.1 * (hairiness - 3); | |
const digitRatio = indexFinger / ringFinger; | |
const splDigitOffset = digitRatio < 1 ? 1.5 : 0; | |
const splFinal = splBase + splAge + splWeight + splHairiness + splDigitOffset; | |
// console.log(`SPL Breakdown - Base: ${splBase}, Age: ${splAge}, Weight: ${splWeight}, Hairiness: ${splHairiness}, Digit Offset: ${splDigitOffset}, Final: ${splFinal}`); | |
let category, message, imagePlaceholder; | |
const scalar = 2; | |
const banana = confetti.shapeFromText({ text: '๐', scalar }); | |
const eggplant = confetti.shapeFromText({ text: '๐', scalar }); | |
if (splFinal < 12) { | |
category = 'small'; | |
message = `You got smol. Here is a joke for your troubles: <br/> | |
there's these 3 lil dudes outside of the guinness book of world records, <br/> | |
first one says I'm gonna get the record for the smallest hands. walks in, comes back out hands in the air says boys i did it.<br/> | |
second one says I'm gonna get the record for the smallest feet. walks in, little bitch skips back out, fellas i got the record.<br/> | |
third one says i'm gonna get the record for the smallest dick <br/> | |
couple minutes later walks out sad as hell looking at the ground, says | |
'Bros, who TF is ${nickname}?' <br/> | |
<a href="https://x.com/ken_wheeler"> joke from @kenwheeler </a> | |
`; | |
imagePlaceholder = '<img src="./assets/small-meme.png" alt="Small Result Meme" class="result-image">'; | |
} else if (splFinal >= 12 && splFinal < 14) { | |
category = 'medium'; | |
message = `${nickname}, you're rocking an average size. Perfectly solid!`; | |
imagePlaceholder = '<img src="./assets/medium-meme.png" alt="Medium Result Meme" class="result-image">'; | |
confetti({ | |
shapes: [banana], | |
scalar, | |
particleCount: 60, | |
spread: 100, | |
colors: ['#ff0000', '#00ff00', '#0000ff'] | |
}); | |
} else { | |
category = 'large'; | |
message = `Wow ${nickname}, you're packing a schlong a dong!`; | |
imagePlaceholder = '<img src="./assets/large-meme.png" alt="Large Result Meme" class="result-image">'; | |
confetti({ | |
shapes: [eggplant], | |
scalar, | |
particleCount: 200, | |
spread: 200, | |
colors: ['#ff0000', '#00ff00', '#0000ff'] | |
}); | |
} | |
const sizeText = `Estimated Size: ${splFinal.toFixed(1)} cm (${(splFinal / 2.54).toFixed(1)} in)`; | |
const shareText = `${message} ${sizeText} Check out my result from the ultimate dick measuring quiz! https://toycode.tech`; | |
const shareUrl = `https://x.com/intent/tweet?text=${encodeURIComponent(shareText)}`; | |
resultDiv.innerHTML = ` | |
<div class="result-card"> | |
${imagePlaceholder} | |
<h3>${message}</h3> | |
<p>${sizeText}</p> | |
<a href="${shareUrl}" target="_blank" class="share-btn">Share on X</a> | |
</div> | |
`; | |
gsap.from(resultDiv, { opacity: 0, y: 20, duration: 0.5 }); | |
} | |
}); | |
updateButtons(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment