-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscripts.js
More file actions
223 lines (205 loc) · 11.5 KB
/
scripts.js
File metadata and controls
223 lines (205 loc) · 11.5 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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
// Project modal data
const projectData = {
arcus: {
title: 'ARCUS — Roboracer Vienna 2026',
type: 'Autonomous vehicle · Ongoing',
description: 'ARCUS is an autonomous racing vehicle competing at Roboracer ICRA 2026 in Vienna. I implemented core localization and control algorithms including SLAM for real-time mapping, particle filtering for robust state estimation, and pure pursuit++ trajectory tracking. The full autonomous driving stack was developed using ROS2 on Linux, enabling real-time perception and decision-making at racing speeds.',
technologies: ['ROS2', 'SLAM', 'Particle Filter', 'Pure Pursuit++', 'Linux', 'C++', 'Autonomous Navigation'],
links: [
{ name: 'View on GitHub', url: 'https://github.com/robotique-udes/arcus' },
{ name: 'Team LinkedIn', url: 'https://www.linkedin.com/company/arcus-project/' }
]
},
sherbee: {
title: 'Sherbee',
type: 'Entrepreneurial project · Ongoing',
description: 'Sherbee is a startup developing audio-powered varroa mite detection technology for beekeepers. I contributed to product development, built the marketing website, developed strategic partnerships with beekeepers and agricultural organizations, and helped secure grants and external funding. This project combines embedded systems, signal processing, and business development.',
technologies: ['Web Development', 'Signal Processing', 'IoT', 'Embedded Systems', 'Business Strategy'],
links: [
{ name: 'Visit Website', url: 'https://sherbee.ca' },
{ name: 'Company LinkedIn', url: 'https://www.linkedin.com/company/sherbee/' }
]
},
ballbalancer: {
title: 'Ball balancing robot',
type: 'Mechatronics',
description: 'A complete electromechanical system designed and built from scratch. The project spans mechanical design (frame and linkage), PCB design with custom electronics, and real-time control software. I integrated a Raspberry Pi 5 with stepper motor drivers for precise actuation and implemented closed-loop visual control using OpenCV for real-time ball position detection and servo loop compensation.',
technologies: ['Raspberry Pi 5', 'Stepper Motors', 'OpenCV', 'PCB Design', 'Real-time Control', 'Python'],
links: [
{ name: 'View on GitHub', url: 'https://github.com/CharlesMcCabe/BallBalancer' },
{ name: 'Watch Demo', url: 'https://www.youtube.com/shorts/rVlpZmMtKw4' },
{ name: 'View CAD in Onshape', url: 'https://cad.onshape.com/documents/8632da1a62aee0745924fd5b/w/012cad01de5451e598a468e9/e/7d93e9c7a08a21e8eda356c5' }
]
},
vlogus: {
title: 'Vlogus',
type: 'Computer Vision · Web',
description: 'An intelligent cameraman robot with real-time face tracking and live video streaming capabilities. The system autonomously follows and tracks subjects during filming, enabling hands-free cinematic recording. Built with computer vision algorithms for robust face detection and tracking, combined with robotic servo control for smooth camera movement.',
technologies: ['Computer Vision', 'Face Detection/Tracking', 'Robotics', 'OpenCV', 'Real-time Processing', 'Python'],
links: [
{ name: 'View on GitHub', url: 'https://github.com/vlogUS-s4/VlogUS' },
{ name: 'Watch Demo', url: 'https://youtube.com/shorts/SqjVvZrrfgw' }
]
},
huski: {
title: 'Avalanche rescue robot',
type: 'Mobile robotics',
description: 'A proof-of-concept thermal detection robot designed for avalanche rescue operations. The system features tracked propulsion for terrain navigation and integrated thermal sensing for victim detection. Nearly all structural components were 3D-printed, demonstrating rapid prototyping for specialized robotics applications. I principally contributed to the mechanical design, notably the custom track system.',
technologies: ['Mobile Robotics', '3D Printing', 'Thermal Imaging', 'Tracked Locomotion', 'Embedded Systems'],
links: []
},
thumper: {
title: 'Dune Thumper replica',
type: 'Mechanical design',
description: 'A faithful recreation of the iconic Thumper vehicle from Dune, built with authentic mechanical systems and screen-accurate proportions. This was a fun project to bring a piece of sci-fi to life, combining my passion for design and cinema.',
technologies: ['Mechanical Design', 'Fabrication', 'Mechanical Systems', 'CAD'],
links: [
{ name: 'Watch Demo', url: 'https://youtube.com/shorts/60UvBixNILU' }
]
},
crc: {
title: 'CRC competition robot',
type: 'Competition',
description: 'A competitive robot designed and built under the tight constraints of the CRC competition: limited budget, small team, and strict timelines. I designed pretty much the whole mechanical system, including the elevator lift, the effector and the frame. The project was a great exercise in rapid prototyping, iterative design, and teamwork under pressure.',
technologies: ['Mechanical Design', 'CAD', 'Project Management', 'Rapid Prototyping'],
links: []
},
simulaction: {
title: 'Simulaction',
type: 'Web development',
description: 'A stock market simulation website built entirely from scratch with zero prior web development experience. This project was a deep dive into full-stack web development, covering frontend design, backend architecture, database management, and user interface design. It serves as a learning platform for students interested in financial markets and trading strategies.',
technologies: ['Web Development', 'Frontend', 'Backend', 'Database', 'JavaScript', 'Full-stack'],
links: []
},
bioterra: {
title: 'Bioterra',
type: 'Process engineering',
description: 'A seed-bomb production line demonstrating automated manufacturing of biodegradable seed bombs. The project showcases process engineering, automation design, and sustainable product development. It serves as a conceptual demonstration of germination technology and eco-friendly packaging materials. I worked on an automatic warehousing and dispensing system for the seed bombs, as well as the overall process flow design.',
technologies: ['Process Engineering', 'Automation', 'Manufacturing', 'Sustainability'],
links: []
},
rapidus: {
title: 'Rapidus — Robot in 3 days',
type: 'Competition · Sprint',
description: 'Built functional FRC competition robots in just 3 days as part of a rapid prototyping challenge. Beyond the engineering feat, we documented the entire process to create educational materials helping high-school teams replicate fast build workflows and discover new rapid development techniques. I principally worked on the design of the disk launcher.',
technologies: ['FRC', 'Rapid Prototyping', 'Documentation', 'Team Coordination', 'Problem-solving'],
links: [
{ name: 'Watch Reveal', url: 'https://youtu.be/5d347xy3TyQ' }
]
}
};
// Modal functionality
const modal = document.getElementById('project-modal');
const modalOverlay = modal.querySelector('.modal-overlay');
const modalClose = modal.querySelector('.modal-close');
const modalLinksContainer = modal.querySelector('.modal-links');
function openModal(projectId) {
const project = projectData[projectId];
if (!project) return;
// Populate modal content
modal.querySelector('.modal-title').textContent = project.title;
modal.querySelector('.modal-type').textContent = project.type;
modal.querySelector('.modal-description').textContent = project.description;
// Add technology tags
const techTagsContainer = modal.querySelector('.tech-tags');
techTagsContainer.innerHTML = '';
project.technologies.forEach(tech => {
const tag = document.createElement('span');
tag.className = 'tech-tag';
tag.textContent = tech;
techTagsContainer.appendChild(tag);
});
// Add links
modalLinksContainer.innerHTML = '';
project.links.forEach(link => {
const a = document.createElement('a');
a.className = 'modal-link';
a.href = link.url;
a.textContent = link.name;
a.target = '_blank';
a.rel = 'noopener noreferrer';
modalLinksContainer.appendChild(a);
});
modalLinksContainer.hidden = project.links.length === 0;
modal.classList.add('active');
modal.setAttribute('aria-hidden', 'false');
document.body.style.overflow = 'hidden';
}
function closeModal() {
modal.classList.remove('active');
modal.setAttribute('aria-hidden', 'true');
document.body.style.overflow = 'auto';
}
// Event listeners for project cards
document.querySelectorAll('[data-modal]').forEach(card => {
card.addEventListener('click', (e) => {
// Don't open modal if clicking on a link
if (e.target.tagName === 'A') return;
openModal(card.dataset.modal);
});
});
document.querySelectorAll('[data-page]').forEach(card => {
card.addEventListener('click', (e) => {
if (e.target.tagName === 'A') return;
const page = card.dataset.page;
if (page) {
window.location.href = page;
}
});
});
// Close modal listeners
modalClose.addEventListener('click', closeModal);
modalOverlay.addEventListener('click', closeModal);
// Close on Escape key
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && modal.classList.contains('active')) {
closeModal();
}
});
// Contact form
const contactForm = document.getElementById('contact-form');
const formStatus = document.getElementById('form-status');
if (contactForm && formStatus) {
contactForm.addEventListener('submit', async (event) => {
event.preventDefault();
const submitButton = contactForm.querySelector('.form-submit');
const endpoint = contactForm.getAttribute('action');
if (!endpoint) {
formStatus.textContent = 'Form endpoint is missing. Please try again later.';
formStatus.classList.remove('form-status--success');
formStatus.classList.add('form-status--error');
return;
}
if (submitButton) {
submitButton.disabled = true;
submitButton.textContent = 'Sending...';
}
formStatus.textContent = 'Sending your message...';
formStatus.classList.remove('form-status--success', 'form-status--error');
try {
const response = await fetch(endpoint, {
method: 'POST',
body: new FormData(contactForm),
headers: {
Accept: 'application/json'
}
});
if (response.ok) {
formStatus.textContent = 'Thanks, your message was sent successfully.';
formStatus.classList.add('form-status--success');
contactForm.reset();
} else {
formStatus.textContent = 'Sorry, your message could not be sent. Please try again.';
formStatus.classList.add('form-status--error');
}
} catch {
formStatus.textContent = 'Network error. Please check your connection and try again.';
formStatus.classList.add('form-status--error');
} finally {
if (submitButton) {
submitButton.disabled = false;
submitButton.textContent = 'Send message →';
}
}
});
}