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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
|
---
import Layout from "../layouts/Layout.astro";
import SocialNavbar from "../components/SocialNavbar.astro";
import Card from "../components/Card.astro";
---
<Layout title="Projects">
<main>
<div class="header-container">
<h1 class="text-4xl font-semibold text-center py-6">Projects</h1>
<p class="text-center mb-8">
Here are some of my projects. I love tinkering with stuff so for a more complete list, visit my <a class="font-bold hover:underline hover:text-blue-300 transition-colors" href="https://github.com/pinapelz">Github</a>
<br />
<a href="https://github.com/pulls/search?q=is%3Apr+is%3Amerged+author%3Apinapelz+-repo%3Apinapelz%2Fupptime+-repo%3Apinapelz%2Fpinapelz+-user%3Apinapelz+-org%3AAntAvionics" class="mt-6 inline-block hover:underline text-center font-bold text-2xl animate-pulse hover:text-blue-300 transition-colors">Open Source Contributions</a>
</p>
</div>
<ul role="list" class="project-grid">
<Card
href="https://github.com/pinapelz/Mirage"
title="Mirage"
body={`• Rhythm game score tracker that preserves scores across games - even niche ones
• No reliance on predefined seeds or chart metadata
• Import & track scores to keep a safe backup of your game progress
• Support for any rhythm game, even without official metadata
• Self-host for group tracking or use locally
• Multi-user system with customizable permissions
• Pre-loaded tracking for DANCERUSH, DANCE aROUND, Project DIVA, MUSIC DIVER, Nostalgia, and REFLEC BEAT`}
language="TypeScript"
languageColor="#3178c6"
year="2024"
image="/mirage.png"
imageAlt="Mirage score tracker interface screenshot"
tags={["React", "TypeScript", "Express", "Prisma ORM", "PostgreSQL"]}
/>
<Card
href="https://patchwork.moekyun.me"
title="Patchwork Archive"
body={`• Comprehensive archival system for YouTube videos at scale
• React-based frontend for managing requests and viewing archived content
• Python Flask backend API for authentication and database operations
• Distributed worker system for processing archival jobs
• Automatic metadata extraction and thumbnail preservation
• Efficient storage using S3-compatible backends
• Scalable architecture handling concurrent archival of thousands of videos`}
language="Javascript"
languageColor="#f1e05a"
year="2023"
image="/patchwork.png"
imageAlt="Screenshot of Patchwork Archive site"
tags={["React", "Python", "MySQL" , "S3 Storage", "TailwindCSS"]}
/>
<Card
href="https://github.com/pinapelz/tiny-time-tracker"
title="tiny-time-tracker"
body={`• Lightweight game time tracking application written in Rust
• Designed specifically for Windows systems
• Uses native process monitoring APIs instead of resource-intensive polling
• Event-based detection of when applications start and stop
• Clean web-based dashboard built with Askama templating
• Styled with Tailwind CSS for responsive design
• Detailed statistics about gaming habits and playtime`}
language="Rust"
languageColor="#dea584"
image="/ttt.png"
imagAlt="Tiny Time Tracker Web UI"
year="2025"
tags={["Rust", "Askama", "Tailwind", "Windows API", "SQLite"]}
/>
<Card
href="https://github.com/pinapelz/NijiTrack"
title="Nijitrack"
body={`• Data analytics platform for YouTube channel statistics
• Focus on VTuber and content creator metrics tracking
• Python backend for continuous data collection via YouTube API
• Tracks subscriber counts, view metrics, and other channel data
• Next.js frontend with interactive charts and historical analysis
• Responsive dashboard for comparing multiple channels
• Tools to identify growth trends and performance patterns`}
language="Python"
languageColor="#3572A5"
year="2023"
image="/phase-tracker.png"
tags={["Python", "Next.js", "Tailwind", "SSR", "Chart.js", "PostgreSQL", "YouTube API"]}
/>
<Card
href="https://github.com/pinapelz/brokenithm-evolved-ios-umi"
title="brokenithm-evolved-ios-umi"
body={`• Low-level bridge application for iOS rhythm game controllers
• Interfaces with the Brokenithm protocol for game input
• Direct integration with chuniio hardware input systems
• Translates UMIGURI LED lighting signals for iOS compatibility
• Real-time input translation with minimal latency
• Accurate transmission of touch inputs to the game system
• Custom protocol implementations for input capture and LED synchronization
• Enables arcade-style gaming experiences using mobile devices`}
language="Python"
image="/brokenithm.png"
imageAlt="Brokenithm-SwiftUI bridged via USB MUX into UMIGURI"
languageColor="#3572A5"
year="2025"
tags={["Python", "C#"]}
/>
<Card
href="https://github.com/pinapelz/JHolodex"
title="JHolodex"
body={`• Object-oriented Java wrapper library for the Holodex API
• Provides easy access to VTuber and content creator data
• Built with Retrofit2 for efficient HTTP operations
• Clean, intuitive interface for querying channel information
• Access to video metadata and live stream data
• Extensive documentation and comprehensive unit tests
• Published on Maven Central for easy integration
• Follows modern Java development practices and API design patterns`}
language="Java"
languageColor="#b07219"
image="/jholodex.png"
imageAlt="JHolodex Central Repository"
year="2023"
tags={["Java", "Retrofit2", "Maven Central", "REST API"]}
/>
<Card
href="https://github.com/pinapelz/573-updates"
title="573-UPDATES"
body={`• Modular web scraping and news aggregation system for arcade gaming
• Python-based scraper monitoring multiple news sources
• Tracks game updates, patch notes, and community announcements
• Automatic parsing and standardization to JSON format
• React single-page application built with TypeScript
• Intuitive, filterable interface for browsing aggregated news
• Extensible architecture for adding new data sources
• Automated deployment pipelines for content updates`}
language="Typescript"
languageColor="#3178c6"
year="2025"
image="/573.png"
imageAlt="573-UPDATES site screenshot"
tags={["React", "TypeScript", "Python", "Web Scraping"]}
/>
<Card
href="https://github.com/pinapelz/ffxiv-chronowatcher"
title="ffxiv-chronowatcher"
body={`• Precision-engineered Rust library for FFXIV calculations
• Accurate implementation of Eorzean Time system
• Weather forecasting for all game zones with perfect accuracy
• Complex time conversion algorithms and weather generation systems
• Comprehensive unit testing for reliability
• Extensive documentation with practical examples
• Published on crates.io for easy integration
• Valuable for developers building FFXIV-related tools`}
language="Rust"
languageColor="#dea584"
year="2024"
image="/chronowatcher.png"
imageAlt="Crates.io FFXIV-Chronowatcher"
tags={["Rust", "Crates.io"]}
/>
<Card
href="https://blog.pinapelz.com"
title="Personal Blog"
body={`• Modern, performance-focused personal blog built with Astro
• Platform for technical insights and project updates
• MDX integration combining Markdown with React components
• Rich content with embedded demos and interactive elements
• Clean, responsive design with accessibility compliance
• Excellent SEO optimization and fast loading times
• Content spanning from technical tutorials to industry observations
• Project breakdowns and software development experiences`}
language="Astro"
image="/blog.png"
imageAlt="Personal Blog Site Screenshot"
languageColor="#ff5a03"
year="2023"
tags={["Astro", "MDX", "React"]}
/>
<Card
href="https://github.com/pinapelz/ytmp3AutoTag"
title="ytID3AutoTag"
body={`• Java Swing desktop application for YouTube to MP3 conversion
• Automatic ID3 metadata tagging from video information
• Intelligent analysis of video titles and descriptions
• Auto-population of artist names, song titles, and album info
• User-friendly GUI designed for ease of use
• Batch processing capabilities for multiple downloads
• High audio quality preservation during conversion
• Streamlined workflow for building organized music libraries`}
language="Java"
languageColor="#b07219"
image="yt.png"
imageAlt="ytId3AutoTag Swing Metadata Editing GUI"
year="2022"
tags={["Java", "Swing"]}
/>
<Card
href="https://github.com/pinapelz/yet-another-lavaplayer-bot"
title="Yet Another Lavaplayer Bot"
body={`• Feature-rich, self-hosted Discord music bot
• Built with Java Discord API (JDA) and Lavaplayer
• Multi-source playback: YouTube, SoundCloud, Bandcamp, etc.
• Advanced queue management and playlist support
• Audio filtering and sound customization features
• Comprehensive command handling system
• User permission controls and moderation features
• High-quality audio streaming for Discord servers`}
language="Java"
languageColor="#b07219"
image="/lavaplayer.png"
imageAlt="Example usage of Discord bot. Able to search + play songs on YouTube"
year="2022"
tags={["Java", "JDA", "Discord Bot", "Lavaplayer", "Audio Streaming", "Async Programming"]}
/>
<Card
href="https://github.com/pinapelz/moekyun-me-link-shortener"
title="Moekyun Link Shortener"
body={`• Self-hosted URL shortening service built with Flask
• Designed for easy deployment on serverless platforms
• Clean, minimalist interface with intuitive controls
• Custom short URL generation and management
• PostgreSQL for reliable data persistence
• Redis caching for frequently accessed URLs
• Fast response times even under heavy load
• 1-click deployment through Vercel for easy setup`}
language="Python"
languageColor="#3572A5"
year="2023"
image="/link.png"
imageAlt="Moekyun Link Shortener Screenshot"
tags={["Python", "Flask", "PostgreSQL", "Redis"]}
/>
<Card
href="https://github.com/pinapelz/ffxiv-malmstone"
title="Malmstone Calculator"
body={`• Specialized FFXIV Dalamud plugin for PvP progression tracking
• Real-time goal-setting functionality within the game interface
• Built with ImGui for seamless UI integration
• Hooks into game data to fetch necessary information
• Calculates matches needed to reach player-defined goals
• Customizable target tracking for different rewards
• Match history analysis and performance metrics
• Time-to-completion estimates based on win rate probabilities`}
language="C#"
languageColor="#178600"
year="2023"
image="/malmstone.png"
imageAlt="FFXIV Malmstone Plugin Screenshot"
tags={["C#", "ImGui"]}
/>
</ul>
<div class="text-center my-12">
<a href="https://knowledge.pinapelz.com/personal/tools" class="inline-block hover:underline text-2xl animate-pulse transition-all hover:text-blue-300">and also a few smaller tools...</a>
</div>
</main>
<SocialNavbar />
<!-- Image Modal -->
<div id="imageModal" class="modal">
<span class="close-modal">×</span>
<img class="modal-content" id="modalImage">
<div id="modalCaption"></div>
</div>
<style>
main {
margin: auto;
padding: 2rem 1.5rem;
max-width: 1300px;
color: white;
font-size: 18px;
line-height: 1.6;
}
a {
color: white;
transition: all 0.2s ease;
}
.header-container {
margin-bottom: 2.5rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
padding-bottom: 1rem;
}
.project-grid {
display: grid;
grid-template-columns: repeat(1, 1fr);
gap: 2.5rem;
padding: 0;
list-style: none;
margin-bottom: 2rem;
}
/* Bullet point styling */
.bullet-style {
position: relative;
padding-left: 1.25rem;
margin-bottom: 0.5rem;
line-height: 1.5;
}
.bullet-style::before {
content: "•";
position: absolute;
left: 0;
color: rgb(139, 92, 246);
font-weight: bold;
}
@media (min-width: 768px) {
.project-grid {
grid-template-columns: repeat(2, 1fr);
gap: 2rem 2.5rem;
}
}
@media (min-width: 1200px) {
.project-grid {
grid-template-columns: repeat(2, 1fr);
gap: 3rem;
}
}
/* Modal Styles */
.modal {
display: none;
position: fixed;
z-index: 1500;
padding-top: 50px;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.9);
opacity: 0;
transition: opacity 0.3s ease;
}
.modal-visible {
opacity: 1;
display: block;
}
.modal-content {
margin: auto;
display: block;
max-width: 90%;
max-height: 80vh;
opacity: 0;
transition: opacity 0.3s ease;
}
.modal-content-visible {
opacity: 1;
}
.close-modal {
position: absolute;
top: 15px;
right: 35px;
color: #f1f1f1;
font-size: 40px;
font-weight: bold;
transition: 0.3s;
cursor: pointer;
z-index: 1001;
}
.close-modal:hover,
.close-modal:focus {
color: #bbb;
text-decoration: none;
cursor: pointer;
}
#modalCaption {
margin: auto;
display: block;
width: 80%;
max-width: 700px;
text-align: center;
color: #ccc;
padding: 10px 0;
height: 150px;
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Get all project images
const projectImages = document.querySelectorAll('.image-container');
const modal = document.getElementById('imageModal');
const modalImg = document.getElementById('modalImage');
const modalCaption = document.getElementById('modalCaption');
const closeBtn = document.querySelector('.close-modal');
// Add click event to each project image
projectImages.forEach(imgContainer => {
imgContainer.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
const img = this.querySelector('img');
modal.style.display = "block";
setTimeout(() => {
modal.classList.add('modal-visible');
}, 10);
modalImg.src = img.src;
modalImg.alt = img.alt;
setTimeout(() => {
modalImg.classList.add('modal-content-visible');
}, 50);
modalCaption.textContent = img.alt;
return false;
});
});
// Close modal when clicking the X
closeBtn.addEventListener('click', closeModal);
// Close modal when clicking outside the image
modal.addEventListener('click', function(event) {
if (event.target === modal) {
closeModal();
}
});
// Close modal with Escape key
document.addEventListener('keydown', function(event) {
if (event.key === 'Escape' && modal.style.display === 'block') {
closeModal();
}
});
function closeModal() {
modal.classList.remove('modal-visible');
modalImg.classList.remove('modal-content-visible');
setTimeout(() => {
modal.style.display = "none";
}, 300);
}
});
</script>
</Layout>
|