xxxxxxxxxx
327
// --- Vlog Squad Tier List Maker ---
// --- V3: Snappy Animation, Text Placement, H3 Labels in Box ---
let members = [
"David Dobrik", "Alex Ernst", "Corinna Kopf", "Scotty Sire", "Toddy Smith",
"Jason Nash", "Zane Hijazi", "Heath Hussar", "Carly Incontro", "Erin Gilfoy",
"Dom Zeglaitis", "Liza Koshy", "Gabbie Hanna", "Brandon Calvillo", "Josh Peck",
"Natalie Mariduena", "Elton Castee", "Big Nik", "Matt King", "Nick Antonyan", // Combined Jonah
"Kristen McAtee", "Trisha Paytas", "Seth Francois", "Vardan Antonyan", "Jeff Wittek",
"Chiqui", "Tana Mongeau", "Mariah Amato", "Joe Vulpis", "Ilya Fedorovich",
"Dima", "Nick (Home)", "Mike (Home)", "John (Home)", "Reggie", "Alex (Home)",
"Jason's Kids", "Jack (Manager)", "Megan (Publicist)", "Jac Anderson",
"Emma Pill", "Taylor Hudson", "Ella", "Suzie Antonyan", "Marine Antonyan",
"Dillon Francis", "Mike Sheffer", "Nabil"
];
// Remove duplicates (like Mariah Amato listed twice)
members = [new Set(members)];
let tiers = ["Ride or Die", "Core", "Core Rotating", "Likes", "Tolerates"];
let tierColors; // Background tier colors
let tierData = {}; // { "Tier Name": [ { name: "...", color: ... } ], ... } - Stores placed name data
let unplacedMembers = [];
let currentCard = null;
// UI & Animation Constants
const CARD_WIDTH = 150;
const CARD_HEIGHT = 50;
const TIER_HEIGHT = 120; // Increased height to accommodate more text lines & larger label
const TOP_MARGIN = 80;
const SIDE_MARGIN = 30; // Right-side margin mainly
const BOTTOM_AREA_HEIGHT = 100;
const FONT_SIZE_CARD = 14;
const FONT_SIZE_TIER_LABEL = 20; // Font size for the "H3" style label
const FONT_SIZE_INSTR = 12;
const EASING = 0.35; // Controls animation smoothness (higher = faster/snappier)
const TIER_LABEL_WIDTH = 180; // Width of the box for the tier label
// Constants for Placed Text Layout
const PLACED_TEXT_SIZE = 14;
const PLACED_TEXT_LEADING = 3; // Vertical space between lines (pixels)
const PLACED_TEXT_MARGIN_X = 5; // Horizontal space between names & padding from label box
const PLACED_TEXT_MARGIN_Y = 8; // Top padding within tier for text
const PLACED_TEXT_COLOR = 245; // Color for placed names (light gray/white)
let fontRegular;
let fontBold;
// function preload() {
// fontRegular = loadFont('assets/your-font.ttf');
// fontBold = loadFont('assets/your-font-bold.ttf'); // Load a bold font if you want to use it for labels
// }
function setup() {
createCanvas(windowWidth, windowHeight);
// textFont(fontRegular);
// Initialize Tier Data Structure
tiers.forEach(tierName => {
tierData[tierName] = [];
});
// Define Tier Colors (soft pastels for background indication)
tierColors = [
color(255, 100, 100, 80), // Ride or Die (light red)
color(255, 180, 100, 80), // Core (light orange)
color(255, 255, 100, 80), // Core Rotating (light yellow)
color(100, 255, 100, 80), // Likes (light green)
color(100, 150, 255, 80), // Tolerates (light blue)
];
// Prepare Member Cards
shuffle(members, true); // Randomize the order they appear
members.forEach(name => {
unplacedMembers.push({
name: name,
color: color(random(100, 240), random(100, 240), random(100, 240)),
x: width / 2,
y: height + CARD_HEIGHT,
targetY: height - BOTTOM_AREA_HEIGHT / 2 - CARD_HEIGHT / 2,
currentTierIndex: tiers.length - 1,
isPlaced: false,
targetX: width / 2
});
});
loadNextCard();
}
function draw() {
background(25, 25, 35); // Dark background
drawTiers(); // Draws labels and background bands
drawPlacedNames(); // Draws the text names in the right section
drawCurrentCard(); // Draws the floating interactive card
drawInstructions(); // Draws help text
// Check if complete
if (!currentCard && unplacedMembers.length === 0) {
drawCompletionMessage();
}
}
function drawTiers() {
push();
noStroke();
for (let i = 0; i < tiers.length; i++) {
let tierY = TOP_MARGIN + i * TIER_HEIGHT;
// --- Draw the MAIN background band for the tier ---
fill(tierColors[i]); // Use the defined tier color
rect(0, tierY, width, TIER_HEIGHT);
// --- Draw the LABEL BOX background ---
// Slightly darker shade for distinction
let labelBgColor = color(red(tierColors[i]) * 0.85, green(tierColors[i]) * 0.85, blue(tierColors[i]) * 0.85, 180);
fill(labelBgColor);
rect(0, tierY, TIER_LABEL_WIDTH, TIER_HEIGHT);
// --- Draw the dividing line between label and names ---
stroke(200, 80); // Subtle gray line
strokeWeight(1);
line(TIER_LABEL_WIDTH, tierY, TIER_LABEL_WIDTH, tierY + TIER_HEIGHT);
// --- Draw the TIER LABEL text (H3 Style) ---
fill(250); // Bright white text for the label
textSize(FONT_SIZE_TIER_LABEL); // Larger font size like H3
textAlign(CENTER, CENTER); // Center the text within the label box
// textFont(fontBold); // Uncomment if using bold font
// Use text wrapping within the label box width
text(tiers[i], 5, tierY, TIER_LABEL_WIDTH - 10, TIER_HEIGHT);
}
pop();
}
function drawPlacedNames() {
push();
textSize(PLACED_TEXT_SIZE);
textAlign(LEFT, TOP); // Align text top-left for flow
fill(PLACED_TEXT_COLOR);
noStroke();
// textFont(fontRegular); // Use regular font if loaded
drawingContext.font = `${PLACED_TEXT_SIZE}px sans-serif`; // Use canvas context for accurate text width measurement
let currentTierY = TOP_MARGIN; // Starting Y for the first tier's content area
tiers.forEach((tierName, tierIndex) => {
let namesInTier = tierData[tierName];
// **MODIFIED:** Start X after the label box
let currentX = TIER_LABEL_WIDTH + PLACED_TEXT_MARGIN_X;
// Start Y slightly inside the tier band
let currentLineY = currentTierY + PLACED_TEXT_MARGIN_Y;
let lineHeight = PLACED_TEXT_SIZE + PLACED_TEXT_LEADING;
// **MODIFIED:** Available width calculation respects label box and right margin
let availableWidth = width - TIER_LABEL_WIDTH - SIDE_MARGIN; // Space AFTER label box and BEFORE right margin
namesInTier.forEach(item => {
let name = item.name;
let textW = drawingContext.measureText(name).width;
// **MODIFIED:** Line wrapping logic uses the correct boundaries
let rightEdge = TIER_LABEL_WIDTH + availableWidth; // Calculate the right boundary for names
// Check if adding the name exceeds the right edge, AND ensure we aren't checking on the very first placement of the line
if (currentX + textW + PLACED_TEXT_MARGIN_X > rightEdge && currentX > TIER_LABEL_WIDTH + PLACED_TEXT_MARGIN_X) {
// Doesn't fit, move to the next line
// **MODIFIED:** Reset X to start after the label box
currentX = TIER_LABEL_WIDTH + PLACED_TEXT_MARGIN_X;
currentLineY += lineHeight;
}
// Check if the next line goes beyond the tier boundary
if (currentLineY + PLACED_TEXT_SIZE <= currentTierY + TIER_HEIGHT) {
text(name, currentX, currentLineY);
currentX += textW + PLACED_TEXT_MARGIN_X; // Move X for the next name
} else {
// Optional: Indicate overflow
}
});
currentTierY += TIER_HEIGHT; // Move to the next tier's Y level
});
pop();
}
function drawCurrentCard() {
if (!currentCard) return;
// Update position smoothly using lerp
currentCard.x = lerp(currentCard.x, currentCard.targetX, EASING);
currentCard.y = lerp(currentCard.y, currentCard.targetY, EASING);
push();
rectMode(CENTER);
textAlign(CENTER, CENTER);
textSize(FONT_SIZE_CARD);
// textFont(fontRegular);
// Draw highlight/glow around the active tier area (full width behind label too)
let highlightY = TOP_MARGIN + currentCard.currentTierIndex * TIER_HEIGHT;
noStroke();
fill(255, 255, 255, 35); // Semi-transparent white glow
// Make glow slightly wider than just the name area if desired, or keep it full width
rect(width/2, highlightY + TIER_HEIGHT / 2, width, TIER_HEIGHT); // Full width glow
// Subtle "pop" effect
let distanceToTarget = abs(currentCard.y - currentCard.targetY);
let scaleEffect = map(distanceToTarget, 0, height / 5, 1, 1.03, true);
// Draw Card
translate(currentCard.x, currentCard.y);
scale(scaleEffect);
fill(currentCard.color);
stroke(255, 220);
strokeWeight(2.5);
rect(0, 0, CARD_WIDTH, CARD_HEIGHT, 8);
// Draw Text on Card
noStroke();
fill(getTextColor(currentCard.color));
text(currentCard.name, 0, 0);
pop(); // Restore previous drawing state
}
function drawInstructions() {
push();
fill(200);
textSize(FONT_SIZE_INSTR);
textAlign(CENTER, BOTTOM);
let instrText = "Use UP/DOWN Arrows to select tier. Press SPACE to place name.";
if (!currentCard && unplacedMembers.length > 0) {
instrText = "Loading next card...";
} else if (currentCard) {
instrText = `Placing: ${currentCard.name}\n${instrText}`;
} else if (unplacedMembers.length === 0) {
instrText = "All members placed!";
}
text(instrText, width / 2, height - 15);
// Display remaining count
textAlign(RIGHT, BOTTOM);
text(`Remaining: ${unplacedMembers.length}`, width - SIDE_MARGIN / 2, height - 15);
pop();
}
function keyPressed() {
if (keyCode === UP_ARROW || keyCode === DOWN_ARROW || keyCode === 32) {
// return false; // Uncomment if browser scrolls on key press
}
if (!currentCard) return;
if (keyCode === UP_ARROW) {
currentCard.currentTierIndex = max(0, currentCard.currentTierIndex - 1);
updateCardTargetPosition();
} else if (keyCode === DOWN_ARROW) {
currentCard.currentTierIndex = min(tiers.length - 1, currentCard.currentTierIndex + 1);
updateCardTargetPosition();
} else if (keyCode === 32) { // Spacebar
placeCurrentCard();
loadNextCard();
}
}
function updateCardTargetPosition() {
if (!currentCard) return;
currentCard.targetY = TOP_MARGIN + currentCard.currentTierIndex * TIER_HEIGHT + TIER_HEIGHT / 2;
currentCard.targetX = width / 2; // Keep floating card centered
}
function placeCurrentCard() {
if (!currentCard) return;
let targetTierName = tiers[currentCard.currentTierIndex];
tierData[targetTierName].push({
name: currentCard.name,
// color: currentCard.color // Keep if needed later
});
currentCard = null; // Card is conceptually placed
}
function loadNextCard() {
if (unplacedMembers.length > 0) {
currentCard = unplacedMembers.shift();
currentCard.x = width / 2;
currentCard.y = height + CARD_HEIGHT;
currentCard.targetX = width / 2;
currentCard.targetY = height - BOTTOM_AREA_HEIGHT / 1.5; // Staging area
currentCard.currentTierIndex = tiers.length - 1;
currentCard.isPlaced = false;
} else {
currentCard = null;
console.log("All members placed!");
}
}
// Helper function to determine text color (black or white) based on background brightness
function getTextColor(bgColor) {
let brightness = (red(bgColor) * 299 + green(bgColor) * 587 + blue(bgColor) * 114) / 1000;
return brightness > 140 ? color(0) : color(255);
}
// Make canvas responsive
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
if (currentCard && !currentCard.isPlaced) {
currentCard.x = width / 2;
currentCard.targetX = width / 2;
updateCardTargetPosition(); // Recalculate target Y based on new height/tier positions
// Adjust staging area target if needed
if (currentCard.y > height - BOTTOM_AREA_HEIGHT - CARD_HEIGHT) {
currentCard.targetY = height - BOTTOM_AREA_HEIGHT / 1.5;
}
}
// Placed text will reflow automatically in drawPlacedNames
}