Repository navigation
Expand file tree
/
Copy pathindex.js
More file actions
145 lines (131 loc) · 7.04 KB
/
Copy pathindex.js
File metadata and controls
145 lines (131 loc) · 7.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/* ---------- view router (tabs) ---------- */
const navlinks = document.getElementById('navlinks');
const views = document.querySelectorAll('.view');
const validViews = new Set(['home','schedule','speakers','sponsors','cfp','venue']);
function showView(id, push){
if(!validViews.has(id)) id = 'home';
views.forEach(v => {
const on = v.id === 'view-' + id;
v.classList.toggle('active', on);
v.style.display = on ? 'block' : 'none';
});
document.querySelectorAll('.navlinks a[data-view]').forEach(a =>
a.classList.toggle('current', a.dataset.view === id));
window.scrollTo(0, 0);
navlinks.classList.remove('open');
if(push !== false && location.hash !== '#' + id) history.pushState(null, '', '#' + id);
}
document.querySelectorAll('[data-view]').forEach(el => {
el.addEventListener('click', e => { e.preventDefault(); showView(el.dataset.view); });
});
window.addEventListener('popstate', () => showView((location.hash || '#home').slice(1), false));
/* ---------- mobile menu ---------- */
document.getElementById('burger').addEventListener('click', () => navlinks.classList.toggle('open'));
/* ---------- speakers (real data) ---------- */
const speakers = [
{n:'Cristian Planas', img:'speakers/cristian-planas.png', r:'Principal Engineer', c:'Combinaut', t:'Dead Cucumbers & Frozen Capybaras: Building the Safety Net for Agentic Development'},
{n:'Dhruva Sagar (DS)', img:'speakers/dhruva-sagar.jpg', r:'Senior Consultant', c:'Tarka Labs', t:'The Ceiling: Why Ruby 4.0 Needed a Second Compiler'},
{n:'Shanmugha Priya P R', img:'speakers/shanmugha-priya.jpg', r:'Senior Software Engineer', c:'Rently Software Development Pvt Ltd', t:'Rethinking Ruby Query Optimization: From ORM Traps to AI Analysis'},
{n:'Vishwajeetsingh Desurkar', img:'speakers/vishwajeetsingh-desurkar.jpg', r:'Senior Software Engineer', c:'Josh Software Pvt Ltd', t:'No Way Home: Threads, Fibers and Ractors Against One Training Loop'},
{n:'Akshay Birajdar', img:'speakers/akshay-birajdar.jpg', r:'Senior Software Engineer', c:'Zendesk', t:'Small Things, Big Impact: Scaling Ruby Apps with the Right Primitives'},
{n:'Ratnadeep Deshmane', img:'speakers/ratnadeep-deshmane.jpg', r:'CTO', c:'Betacraft', t:'The Pursuit of Quality: Chase Better Code with AI, and the Speed Follows'},
{n:'Sourabh Bharale', img:'speakers/sourabh-bharale.jpeg', r:'Senior Software Engineer', c:'MoxiWorks Solutions Pvt Ltd', t:"Your API Is Already an Agent's Tool"}
];
speakers.sort((a, b) => a.n.localeCompare(b.n));
document.getElementById('spkGrid').innerHTML = speakers.map(s => `
<article class="spk">
${s.kb ? '<span class="kb">Keynote</span>' : ''}
<div class="spk-photo"><img src="${s.img}" alt="${s.n}" loading="lazy"></div>
<div class="spk-body">
<div class="spk-name">${s.n}</div>
<div class="spk-role">${s.r}</div>
<div class="spk-co">${s.c}</div>
<div class="spk-talk">${s.t}</div>
</div>
</article>`).join('');
/* ---------- countdown to 21 Nov 2026, 9:00 AM IST ---------- */
const target = new Date('2026-11-21T09:00:00+05:30').getTime();
const el = {d:'cd-days',h:'cd-hrs',m:'cd-min',s:'cd-sec'};
const pad = n => String(n).padStart(2,'0');
function tick(){
let diff = Math.max(0, target - Date.now());
const d = Math.floor(diff/864e5); diff -= d*864e5;
const h = Math.floor(diff/36e5); diff -= h*36e5;
const m = Math.floor(diff/6e4); diff -= m*6e4;
const s = Math.floor(diff/1e3);
document.getElementById(el.d).textContent = d;
document.getElementById(el.h).textContent = pad(h);
document.getElementById(el.m).textContent = pad(m);
document.getElementById(el.s).textContent = pad(s);
}
tick(); setInterval(tick, 1000);
/* ---------- nav shadow on scroll ---------- */
const topbar = document.querySelector('.topbar');
addEventListener('scroll', () => {
topbar.style.boxShadow = scrollY > 20 ? '0 10px 30px -20px rgba(94,10,32,.45)' : 'none';
});
/* ---------- mini-game: Gem Catch ---------- */
(function(){
const stage = document.getElementById('gameStage');
if(!stage) return;
const scoreEl = document.getElementById('gScore');
const timeEl = document.getElementById('gTime');
const overlay = document.getElementById('gOverlay');
const RUBY = '<svg viewBox="0 0 32 28"><path d="M8 2h16l6 8-14 16L2 10z" fill="#E0115F"/><path d="M8 2l8 8 8-8M2 10h28M16 10v16" stroke="#F2D58C" stroke-width="1.4" fill="none"/></svg>';
let running=false, score=0, timeLeft=10, items=[], lastT=0, spawnAcc=0, secAcc=0, raf=0, best=0;
function spawn(){
const w = stage.clientWidth;
const isBomb = Math.random() < 0.22;
const el = document.createElement('div');
el.className = isBomb ? 'bomb' : 'gem';
el.innerHTML = isBomb ? '💣' : RUBY;
el.style.left = Math.max(0, Math.random()*(w-46)) + 'px';
el.style.transform = 'translateY(-50px)';
const it = { el, y:-50, vy: 85 + Math.random()*65 + (10-timeLeft)*5, alive:true };
el.addEventListener('pointerdown', ev => {
ev.preventDefault();
if(!running || !it.alive) return;
it.alive = false;
if(isBomb){ score = Math.max(0, score-2); el.className='bomb boom'; }
else { score += 1; el.className='gem pop'; }
scoreEl.textContent = score;
setTimeout(()=>el.remove(), 220);
}, {passive:false});
stage.appendChild(el);
items.push(it);
}
function loop(t){
if(!running) return;
if(!lastT) lastT = t;
const dt = Math.min(0.05, (t-lastT)/1000); lastT = t;
spawnAcc += dt; secAcc += dt;
const spawnEvery = Math.max(0.30, 0.58 - (10-timeLeft)*0.028);
if(spawnAcc >= spawnEvery){ spawnAcc = 0; spawn(); }
if(secAcc >= 1){ secAcc -= 1; timeLeft -= 1; timeEl.textContent = Math.max(0, timeLeft); if(timeLeft <= 0){ endGame(); return; } }
const h = stage.clientHeight;
for(const it of items){ if(!it.alive) continue; it.y += it.vy*dt; it.el.style.transform = 'translateY('+it.y+'px)'; if(it.y > h){ it.alive=false; it.el.remove(); } }
items = items.filter(it => it.alive);
raf = requestAnimationFrame(loop);
}
function clearItems(){ items.forEach(it => it.el.remove()); items = []; }
function startGame(){
clearItems(); score=0; timeLeft=10; lastT=0; spawnAcc=0; secAcc=0; running=true;
scoreEl.textContent='0'; timeEl.textContent='10';
overlay.classList.add('hide');
raf = requestAnimationFrame(loop);
}
function endGame(){
running=false; cancelAnimationFrame(raf); clearItems(); timeEl.textContent='0';
const isBest = score > best && score > 0;
if(score > best) best = score;
overlay.classList.remove('hide');
overlay.innerHTML =
`<h3>Time's up!</h3><div class="big-score">${score}</div>`
+ `<p>${score===0 ? 'No rubies this time — give it another go!' : (isBest ? '🎉 New personal best!' : 'Nice catching! Best this session: ' + best + '.')}</p>`
+ `<button class="btn btn-gold" id="gAgain">Play Again</button>`;
document.getElementById('gAgain').addEventListener('click', startGame);
}
document.getElementById('gStart').addEventListener('click', startGame);
})();
/* ---------- initial route ---------- */
showView((location.hash || '#home').slice(1), false);