Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 86 additions & 1 deletion hackx/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -279,32 +279,117 @@ <h1 class="glitch-text" data-text="// TIMELINE">// TIMELINE</h1>
<div class="timeline-item" data-aos>
<div class="timeline-dot"></div>
<div class="timeline-date">MAR 15</div>
<div class="timetable-align">
<div class="timeline-event">REGISTRATION OPENS</div>
<div class="timeline-timetable"></div>
</div>
</div>
<div class="timeline-item" data-aos>
<div class="timeline-dot"></div>
<div class="timeline-date">APR 08</div>
<div class="timeline-date">APR 04</div>
<div class="timetable-align">
<div class="timeline-event">REGISTRATION CLOSES</div>
<div class="timeline-timetable"></div>
</div>
</div>
<div class="timeline-item" data-aos>
<div class="timeline-dot"></div>
<div class="timeline-date">APR 11</div>
<div class="timetable-align">
<div class="timeline-event">OPENING CEREMONY</div>
<div class="timeline-timetable">
<div class="timetable-event">
<span class="event-time">08:30 AM</span>
<span class="event-desc">Reporting</span>
</div>
<div class="timetable-event">
<span class="event-time">09:30 AM</span>
<span class="event-desc">Inauguration Ceremony in KJSSE Auditorium</span>
</div>
</div>
</div>
</div>
<div class="timeline-item active" data-aos>
<div class="timeline-dot"></div>
<div class="timeline-date">APR 11-12</div>
<div class="timetable-align">
<div class="timeline-event">24 HOURS OF HACKING</div>
<div class="timeline-timetable">
<div class="timetable-event">
<span class="event-time">11:00 AM</span>
<span class="event-desc">Hacking Period Starts</span>
</div>
<div class="timetable-event">
<span class="event-time">01:00 PM</span>
<span class="event-desc">Lunch</span>
</div>
<div class="timetable-event">
<span class="event-time">04:30 PM</span>
<span class="event-desc">Evening Snacks</span>
</div>
<div class="timetable-event">
<span class="event-time">06:00 PM</span>
<span class="event-desc">Mentoring Round 1</span>
</div>
<div class="timetable-event">
<span class="event-time">08:30 PM</span>
<span class="event-desc">Dinner</span>
</div>
<div class="timetable-event">
<span class="event-time">12:00 AM</span>
<span class="event-desc">Midnight Snacks</span>
</div>
<div class="timetable-event">
<span class="event-time">01:00 AM</span>
<span class="event-desc">Mentoring Round 2</span>
</div>
<div class="timetable-event">
<span class="event-time">08:00 AM</span>
<span class="event-desc">Breakfast</span>
</div>
<div class="timetable-event">
<span class="event-time">11:00 AM</span>
<span class="event-desc">Hacking Period Ends</span>
</div>
</div>
</div>
</div>
<div class="timeline-item" data-aos>
<div class="timeline-dot"></div>
<div class="timeline-date">APR 12</div>
<div class="timetable-align">
<div class="timeline-event">DEMOS & JUDGING</div>
<div class="timeline-timetable">
<div class="timetable-event">
<span class="event-time">11:15 AM</span>
<span class="event-desc">Evaluation Round 1</span>
</div>
<div class="timetable-event">
<span class="event-time">01:00 PM</span>
<span class="event-desc">Lunch</span>
</div>
<div class="timetable-event">
<span class="event-time">03:30 PM</span>
<span class="event-desc">Final Evaluation Round</span>
</div>
</div>
</div>
</div>
<div class="timeline-item" data-aos>
<div class="timeline-dot"></div>
<div class="timeline-date">APR 12</div>
<div class="timetable-align">
<div class="timeline-event">CLOSING CEREMONY & PRIZES</div>
<div class="timeline-timetable">
<div class="timetable-event">
<span class="event-time">04:30 PM</span>
<span class="event-desc">Evening Snacks</span>
</div>
<div class="timetable-event">
<span class="event-time">05:30 PM</span>
<span class="event-desc">Prize Distribution & Closing Remarks</span>
</div></div>
</div>
</div>
</div>
</div>
Expand Down
149 changes: 148 additions & 1 deletion hackx/sections.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
initFooterCanvas();
// Core (one-time CSS transitions, no jank)
initScrollFadeIn();
initTimelineParallaxReveal();
initPrizeCounters();
// initScrollProgressBar(); // removed — was showing blue line at top
initAnnouncements();
Expand Down Expand Up @@ -396,6 +397,152 @@
}
}

// ===== TIMELINE PARALLAX REVEAL (timeline-only) =====
function initTimelineParallaxReveal() {
const timelineItems = Array.from(document.querySelectorAll('.timeline-item'));
if (timelineItems.length === 0) return;
const itemStates = new Map();
let rafId = null;

function clamp(value, min, max) {
return Math.min(Math.max(value, min), max);
}

function smoothstep(t) {
return t * t * (3 - 2 * t);
}

function setTimelineHeight(item, state) {
if (!state.timetable) return;
item.style.setProperty('--tt-height', `${state.timetable.scrollHeight}px`);
}

function initTimelineState() {
timelineItems.forEach((item) => {
item.classList.remove('timeline-open');
item.style.setProperty('--date-scale', '1');
item.style.setProperty('--date-glow', '0');
item.style.setProperty('--timeline-reveal', '0');

const timetable = item.querySelector('.timeline-timetable');
const events = Array.from(item.querySelectorAll('.timetable-event'));

events.forEach(eventEl => {
eventEl.classList.remove('is-visible');
eventEl.style.opacity = '0';
eventEl.style.transform = 'translateY(8px)';
});

const state = {
target: 0,
current: 0,
events,
timetable,
};

itemStates.set(item, state);
setTimelineHeight(item, state);
});
}

function updateTimelineHeights() {
timelineItems.forEach((item) => {
const state = itemStates.get(item);
if (!state) return;
setTimelineHeight(item, state);
});
}

function computeTargetsFromScroll() {
const vh = window.innerHeight || document.documentElement.clientHeight;
timelineItems.forEach(item => {
const state = itemStates.get(item);
if (!state) return;

const rect = item.getBoundingClientRect();
// Complete reveal by viewport midpoint (50% height)
const start = vh * 0.9;
const end = vh * 0.5;
const progress = clamp((start - rect.top) / Math.max(start - end, 1), 0, 1);
state.target = smoothstep(progress);
});
}

function applyRevealProgress(item, revealProgress) {
const state = itemStates.get(item);
if (!state) return;
const eventCount = state.events.length;

item.classList.toggle('timeline-open', revealProgress > 0.01);
item.style.setProperty('--date-scale', (1 + revealProgress * 0.06).toFixed(3));
item.style.setProperty('--date-glow', revealProgress.toFixed(3));
item.style.setProperty('--timeline-reveal', revealProgress.toFixed(3));

if (eventCount === 0) return;

state.events.forEach((eventEl, index) => {
// Slight overlap between items so the sequence feels continuous.
const stepSpan = 1 / (eventCount + 0.35);
const stepStart = index * stepSpan;
const localProgress = clamp((revealProgress - stepStart) / Math.max(stepSpan, 0.0001), 0, 1);

eventEl.style.opacity = localProgress.toFixed(3);
eventEl.style.transform = `translateY(${(1 - localProgress) * 8}px)`;
eventEl.classList.toggle('is-visible', localProgress > 0.6);
});
}

function startRafLoop() {
if (rafId !== null) return;

const tick = () => {
let hasActiveMotion = false;

timelineItems.forEach((item) => {
const state = itemStates.get(item);
if (!state) return;

const delta = state.target - state.current;
if (Math.abs(delta) > 0.0008) {
state.current += delta * 0.16;
hasActiveMotion = true;
} else {
state.current = state.target;
}

applyRevealProgress(item, state.current);
});

if (hasActiveMotion) {
rafId = requestAnimationFrame(tick);
} else {
rafId = null;
}
};

rafId = requestAnimationFrame(tick);
}

function updateFromScroll() {
computeTargetsFromScroll();
startRafLoop();
}

initTimelineState();
updateFromScroll();
window.addEventListener('scroll', updateFromScroll, { passive: true });
window.addEventListener('resize', () => {
updateTimelineHeights();
updateFromScroll();
});

// Ensure timeline positions are correct after fonts/layout settle.
setTimeout(() => {
updateTimelineHeights();
updateFromScroll();
}, 120);
}

// ===== PRIZE COUNTERS (easeOutExpo for satisfying deceleration) =====
function initPrizeCounters() {
const amounts = document.querySelectorAll('.prize-amount, .pool-amount');
Expand Down Expand Up @@ -1322,7 +1469,7 @@
`;
document.head.appendChild(style);

document.querySelectorAll('.readout-row, .prize-entry, .timeline-item').forEach(el => {
document.querySelectorAll('.readout-row, .prize-entry').forEach(el => {
el.classList.add('_line-trace-wrap');
if (el.style.position === '' || el.style.position === 'static') {
el.style.position = 'relative';
Expand Down
Loading