diff --git a/public/assets/css/douwco.css b/public/assets/css/douwco.css index 541e05a..1f06b0c 100644 --- a/public/assets/css/douwco.css +++ b/public/assets/css/douwco.css @@ -23,6 +23,10 @@ --blue-clr: #47bcdf; --green-clr: #6ede9a; --white-clr: #ffffff; + --card-border-radius: 25px; + --dark-green: #1a3d2e; + --dark-teal: #2c5f5f; + --orange-clr: #f39c12; } body { diff --git a/public/assets/css/style.css b/public/assets/css/style.css index 2e19977..d67d35d 100644 --- a/public/assets/css/style.css +++ b/public/assets/css/style.css @@ -72,6 +72,17 @@ footer > div > p { .scroll_section { min-height: 100vh; scroll-snap-align: start; + display: flex; + flex-direction: column; + align-items: center; +} + +.scroll_section > h1 { + color: var(--white-clr); + font-size: 48px; + margin: 20px 0; + text-align: center; + width: 100%; } /* ===== Navigationbar ===== */ @@ -191,6 +202,574 @@ footer > div > p { float: left; } +/* New project card styling - rectangular with image on top */ +.project-card-new { + background-color: var(--background-accent-clr); + border-radius: var(--card-border-radius, 25px); + overflow: hidden; + margin: 10px; + max-width: 400px; + min-width: 300px; + box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3); + display: flex; + flex-direction: column; + transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); + cursor: pointer; + position: relative; +} + +.project-card-new.expanded { + z-index: 10; + transform: scale(1.02); + box-shadow: 0 12px 35px rgba(0, 0, 0, 0.5); +} + +.project-card-new .toggle-icon { + position: absolute; + top: 10px; + right: 10px; + width: 30px; + height: 30px; + border-radius: 50%; + background-color: var(--green-clr); + color: var(--background-clr); + font-size: 20px; + font-weight: bold; + z-index: 20; + cursor: pointer; + transition: transform 0.2s ease; +} + +.project-card-new .toggle-icon:hover { + transform: scale(1.1); +} + +.project-card-image-container { + position: relative; + width: 100%; + height: 200px; + overflow: hidden; + transition: height 0.4s cubic-bezier(0.4, 0, 0.2, 1); +} + +.project-card-new.expanded .project-card-image-container { + height: 150px; +} + +.project-card-image { + width: 100%; + height: 100%; + object-fit: cover; + background-color: #888; /* Plain grey as fallback */ +} + +.project-card-title-container { + position: relative; + margin-top: -50px; /* Overlap with image */ + padding: 10px 20px; + z-index: 1; +} + +.project-card-title-background { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: var(--background-accent-clr); + border-radius: var(--card-border-radius, 25px); + opacity: 0.95; +} + +.project-card-title { + position: relative; + font-weight: bold; + font-size: 20px; + color: var(--green-clr); + margin: 0; + z-index: 1; +} + +.project-card-content { + padding: 0 20px; + color: var(--text-color); + max-height: 0; + overflow: hidden; + transition: max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1), padding-top 0.4s cubic-bezier(0.4, 0, 0.2, 1), padding-bottom 0.4s cubic-bezier(0.4, 0, 0.2, 1); +} + +.project-card-new.expanded .project-card-content { + max-height: 1000px; + padding: 20px; +} + +.project-card-short-desc { + padding: 10px 20px 20px; + color: var(--text-color); + line-height: 1.6; + transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); +} + +.project-card-new.expanded .project-card-short-desc { + display: none; +} + +.project-card-content p { + margin: 0; + line-height: 1.6; +} + +/* About Me grid layout */ +.about-me-projects-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); + gap: 20px; + width: 100%; + max-width: 1200px; + margin: 20px auto; +} + +/* ===== Apps Section - Full Width Dashboard Carousel ===== */ + +.apps-container { + width: 100%; + max-width: 1600px; + margin: 0 auto; + padding: 20px; + display: flex; + flex-direction: column; + gap: 30px; +} + +.carousel-container-full { + position: relative; + width: 100%; + padding: 40px 60px; + box-sizing: border-box; +} + +.carousel-track-full { + display: flex; + justify-content: center; + align-items: center; + gap: 20px; + width: 100%; +} + +.carousel-item-full { + display: flex; + flex-direction: column; + align-items: center; + cursor: pointer; + transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1); + z-index: 1; + min-width: 120px; +} + +.carousel-item-full[data-selected="true"] { + z-index: 5; +} + +.service-icon-large { + width: 100px; + height: 100px; + border-radius: 50%; + background-color: var(--icon-bg, #888); + display: flex; + align-items: center; + justify-content: center; + color: var(--white-clr); + font-weight: bold; + font-size: 40px; + transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1); + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3); +} + +.carousel-item-full[data-selected="true"] .service-icon-large { + width: 150px; + height: 150px; + font-size: 60px; + box-shadow: 0 8px 25px rgba(0, 0, 0, 0.5); +} + +.carousel-item-full:nth-child(1):not([data-selected="true"]) .service-icon-large, +.carousel-item-full:nth-child(5):not([data-selected="true"]) .service-icon-large { + width: 80px; + height: 80px; + font-size: 32px; + opacity: 0.7; +} + +.carousel-item-full:nth-child(2):not([data-selected="true"]):not(:nth-child(4)) .service-icon-large, +.carousel-item-full:nth-child(4):not([data-selected="true"]):not(:nth-child(2)) .service-icon-large { + width: 90px; + height: 90px; + font-size: 36px; + opacity: 0.85; +} + +.service-label-large { + color: var(--white-clr); + font-size: 22px; + margin-top: 15px; + opacity: 0.8; + transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1); + text-align: center; +} + +.carousel-item-full[data-selected="true"] .service-label-large { + opacity: 1; + font-size: 28px; + font-weight: bold; +} + +.carousel-item-full:nth-child(1):not([data-selected="true"]) .service-label-large, +.carousel-item-full:nth-child(5):not([data-selected="true"]) .service-label-large { + opacity: 0.5; +} + +.carousel-nav-full { + position: absolute; + top: 50%; + transform: translateY(-50%); + background: rgba(255, 255, 255, 0.15); + border: none; + color: var(--white-clr); + font-size: 48px; + width: 50px; + height: 50px; + border-radius: 50%; + cursor: pointer; + transition: all 0.3s ease; + z-index: 10; +} + +.carousel-nav-full:hover { + background: rgba(255, 255, 255, 0.25); + transform: translateY(-50%) scale(1.1); +} + +.carousel-nav-full.prev { + left: 20px; +} + +.carousel-nav-full.next { + right: 20px; +} + +/* Service detail area - full width */ +.service-detail-full { + width: 100%; + background-color: var(--dark-green, #1a3d2e); + border-radius: var(--card-border-radius, 25px); + padding: 40px; + box-sizing: border-box; + display: flex; + flex-direction: column; + gap: 30px; +} + +.service-screenshot-full { + width: 100%; + height: 400px; + border-radius: 15px; + overflow: hidden; + background-color: #2a2a2a; + transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1); +} + +.service-screenshot-full img { + width: 100%; + height: 100%; + object-fit: cover; + opacity: 0; + transition: opacity 0.6s cubic-bezier(0.4, 0, 0.2, 1); +} + +.service-screenshot-full img.active { + opacity: 1; +} + +.service-info-full { + display: flex; + flex-direction: column; + align-items: center; + gap: 20px; + text-align: center; +} + +.service-title { + color: var(--green-clr); + font-size: 42px; + margin: 0; + opacity: 0; + transition: opacity 0.6s cubic-bezier(0.4, 0, 0.2, 1) 0.1s; +} + +.service-title.active { + opacity: 1; +} + +.service-description-full { + color: var(--white-clr); + font-size: 24px; + line-height: 1.6; + max-width: 800px; + opacity: 0; + transition: opacity 0.6s cubic-bezier(0.4, 0, 0.2, 1) 0.2s; +} + +.service-description-full.active { + opacity: 1; +} + +.service-description-full p { + margin: 0; +} + +/* Go to App Button */ +.go-to-app-button { + display: inline-block; + background-color: var(--green-clr); + color: var(--background-clr); + padding: 18px 40px; + font-size: 28px; + font-weight: bold; + text-decoration: none; + border-radius: 15px; + border: none; + cursor: pointer; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3); + margin-top: 20px; + opacity: 0; + transition: opacity 0.6s cubic-bezier(0.4, 0, 0.2, 1) 0.3s; +} + +.go-to-app-button:hover { + transform: translateY(-2px); + box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4); +} + +.go-to-app-button.active { + opacity: 1; +} + +/* ===== Games Section ===== */ + +.games-container { + width: 100%; + max-width: 1600px; + margin: 0 auto; + padding: 20px; +} + +.games-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: 30px; + width: 100%; +} + +.game-card { + background-color: var(--dark-teal, #2c5f5f); + border-radius: var(--card-border-radius, 25px); + overflow: hidden; + cursor: pointer; + transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); + position: relative; + display: flex; + flex-direction: column; +} + +.game-card:hover { + transform: translateY(-5px); + box-shadow: 0 12px 30px rgba(0, 0, 0, 0.4); +} + +.game-card-image { + width: 100%; + height: 200px; + overflow: hidden; + background-color: #888; +} + +.game-card-image img { + width: 100%; + height: 100%; + object-fit: cover; + background-color: #888; +} + +.game-card-content { + padding: 20px; + display: flex; + flex-direction: column; + gap: 10px; +} + +.game-card-title { + color: var(--white-clr); + font-size: 24px; + font-weight: bold; + margin: 0; +} + +.game-card-description { + color: var(--white-clr); + font-size: 18px; + opacity: 0.8; + margin: 0; + line-height: 1.5; +} + +.game-year-badge { + display: inline-block; + background-color: var(--orange-clr, #f39c12); + color: var(--background-clr); + padding: 5px 12px; + border-radius: 20px; + font-size: 14px; + font-weight: bold; + align-self: flex-start; +} + +.game-card-expanded { + display: none; + padding: 20px; + background-color: rgba(0, 0, 0, 0.2); + flex: 1; +} + +.game-card.expanded .game-card-expanded { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +.game-card.expanded .game-card-content { + display: none; +} + +.game-card.expanded .game-card-image { + height: 250px; +} + +.game-card-full-description { + color: var(--white-clr); + font-size: 20px; + line-height: 1.6; + text-align: center; + max-width: 80%; + margin-bottom: 20px; +} + +.play-button { + display: inline-block; + background-color: var(--green-clr); + color: var(--background-clr); + padding: 15px 35px; + font-size: 24px; + font-weight: bold; + text-decoration: none; + border-radius: 15px; + border: none; + cursor: pointer; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.4); +} + +.play-button:hover { + transform: scale(1.05); + box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4); +} + +/* Responsive design for carousel */ +@media (max-width: 1024px) { + .apps-container { + padding: 15px; + } + + .carousel-container-full { + padding: 30px 40px; + } + + .carousel-track-full { + gap: 15px; + } + + .service-icon-large { + width: 80px; + height: 80px; + font-size: 32px; + } + + .carousel-item-full[data-selected="true"] .service-icon-large { + width: 120px; + height: 120px; + font-size: 48px; + } + + .carousel-item-full:nth-child(1):not([data-selected="true"]) .service-icon-large, + .carousel-item-full:nth-child(5):not([data-selected="true"]) .service-icon-large { + width: 60px; + height: 60px; + font-size: 24px; + } + + .carousel-item-full:nth-child(2):not([data-selected="true"]):not(:nth-child(4)) .service-icon-large, + .carousel-item-full:nth-child(4):not([data-selected="true"]):not(:nth-child(2)) .service-icon-large { + width: 70px; + height: 70px; + font-size: 28px; + } + + .service-screenshot-full { + height: 300px; + } + + .service-title { + font-size: 36px; + } + + .service-description-full { + font-size: 20px; + } + + .service-label-large { + font-size: 18px; + } + + .carousel-item-full[data-selected="true"] .service-label-large { + font-size: 24px; + } + + .go-to-app-button { + font-size: 24px; + padding: 15px 35px; + } +} + +/* Currently working on and However in the past sections */ +.about-me-section { + width: 100%; + margin-bottom: 40px; +} + +.about-me-section h2 { + font-size: 28px; + color: var(--white-clr); + margin-bottom: 20px; + border-bottom: 2px solid var(--green-clr); + padding-bottom: 10px; +} + +.about-me-section h2 .green-text { + color: var(--green-clr); + font-weight: bold; +} + /* ===== Images ===== */ .icon { diff --git a/public/assets/img/games/ludum47_placeholder.png b/public/assets/img/games/ludum47_placeholder.png new file mode 100644 index 0000000..669fade Binary files /dev/null and b/public/assets/img/games/ludum47_placeholder.png differ diff --git a/public/assets/img/games/ludum48_placeholder.png b/public/assets/img/games/ludum48_placeholder.png new file mode 100644 index 0000000..7ddb957 Binary files /dev/null and b/public/assets/img/games/ludum48_placeholder.png differ diff --git a/public/assets/img/games/ludum49_placeholder.png b/public/assets/img/games/ludum49_placeholder.png new file mode 100644 index 0000000..a0c33bb Binary files /dev/null and b/public/assets/img/games/ludum49_placeholder.png differ diff --git a/public/assets/img/games/ludum50_placeholder.png b/public/assets/img/games/ludum50_placeholder.png new file mode 100644 index 0000000..281434e Binary files /dev/null and b/public/assets/img/games/ludum50_placeholder.png differ diff --git a/public/assets/img/games/ludum51_placeholder.png b/public/assets/img/games/ludum51_placeholder.png new file mode 100644 index 0000000..480bdea Binary files /dev/null and b/public/assets/img/games/ludum51_placeholder.png differ diff --git a/public/assets/img/games/windy_placeholder.png b/public/assets/img/games/windy_placeholder.png new file mode 100644 index 0000000..3760734 Binary files /dev/null and b/public/assets/img/games/windy_placeholder.png differ diff --git a/public/assets/js/index.js b/public/assets/js/index.js index 2515b3c..b7c79da 100644 --- a/public/assets/js/index.js +++ b/public/assets/js/index.js @@ -2,6 +2,9 @@ document.addEventListener('DOMContentLoaded', () => { setupNavigationHighlight(); setupNavigationClicks(); setupCopyright(); + setupProjectCards(); + setupAppsCarousel(); + setupGameCards(); }); function setupNavigationHighlight() { @@ -43,3 +46,218 @@ function setupNavigationClicks() { function setupCopyright() { document.getElementById('copyright').textContent = `© ${new Date().getFullYear()} - douwco.be`; } + +function setupProjectCards() { + const projectCards = document.querySelectorAll('.project-card-new'); + + projectCards.forEach(card => { + const shortDesc = card.querySelector('.project-card-short-desc'); + const fullContent = card.querySelector('.project-card-content'); + const toggleIcon = card.querySelector('.toggle-icon'); + + if (!shortDesc || !fullContent || !toggleIcon) return; + + const toggleCard = (event) => { + if (event.target.tagName === 'A') { + return; + } + + const isExpanded = card.classList.contains('expanded'); + + if (isExpanded) { + card.classList.remove('expanded'); + toggleIcon.textContent = '+'; + } else { + card.classList.add('expanded'); + toggleIcon.textContent = '−'; + } + + event.stopPropagation(); + }; + + card.addEventListener('click', toggleCard); + toggleIcon.addEventListener('click', toggleCard); + }); +} + +function setupAppsCarousel() { + const carousel = document.getElementById('apps-carousel'); + const carouselContainer = carousel ? carousel.closest('.carousel-container-full') : null; + const items = document.querySelectorAll('#apps-carousel .carousel-item-full'); + const prevBtn = carouselContainer ? carouselContainer.querySelector('.carousel-nav-full.prev') : null; + const nextBtn = carouselContainer ? carouselContainer.querySelector('.carousel-nav-full.next') : null; + const screenshotImg = document.getElementById('apps-screenshot-img'); + const description = document.getElementById('apps-description'); + const title = document.getElementById('apps-title'); + const goToAppBtn = document.getElementById('apps-link'); + + if (!carousel || items.length === 0) return; + + const services = [ + { + name: 'Gitea', + screenshot: '/assets/img/gitea_screenshot.png', + description: 'Self-hosted Git service with a simple and lightweight interface.', + url: 'https://gitea.douwco.be' + }, + { + name: 'Nextcloud', + screenshot: '/assets/img/nextcloud_screenshot.png', + description: 'Private file hosting and collaboration platform with powerful features.', + url: 'https://nextcloud.douwco.be' + }, + { + name: 'Penpot', + screenshot: '/assets/img/penpot_screenshot.png', + description: 'Open-source design and prototyping platform for teams.', + url: 'https://penpot.douwco.be' + }, + { + name: 'Beszel', + screenshot: '/assets/img/beszel_screenshot.png', + description: 'Custom service management and monitoring dashboard.', + url: 'https://beszel.douwco.be' + }, + { + name: 'Wattif', + screenshot: '/assets/img/wattif_screenshot.png', + description: 'Energy monitoring and analysis tool for smart homes.', + url: 'https://wattif.douwco.be' + } + ]; + + let currentIndex = 0; + let isAnimating = false; + + function updateCarousel() { + if (isAnimating) return; + isAnimating = true; + + items.forEach((item, index) => { + const isSelected = index === currentIndex; + item.setAttribute('data-selected', isSelected.toString()); + }); + + const service = services[currentIndex]; + + if (description) description.classList.remove('active'); + if (screenshotImg) screenshotImg.classList.remove('active'); + if (title) title.classList.remove('active'); + if (goToAppBtn) goToAppBtn.classList.remove('active'); + + setTimeout(() => { + if (screenshotImg) { + screenshotImg.src = service.screenshot; + } + if (title) { + title.textContent = service.name; + } + if (description) { + description.innerHTML = `
${service.description}
`; + } + if (goToAppBtn) { + goToAppBtn.href = service.url; + } + + setTimeout(() => { + if (description) description.classList.add('active'); + if (screenshotImg) screenshotImg.classList.add('active'); + if (title) title.classList.add('active'); + if (goToAppBtn) goToAppBtn.classList.add('active'); + isAnimating = false; + }, 50); + }, 300); + } + + function rotateCarousel(direction) { + if (isAnimating) return; + + currentIndex = (currentIndex + direction + items.length) % items.length; + updateCarousel(); + } + + if (prevBtn) { + prevBtn.addEventListener('click', () => rotateCarousel(-1)); + } + + if (nextBtn) { + nextBtn.addEventListener('click', () => rotateCarousel(1)); + } + + items.forEach((item, index) => { + item.addEventListener('click', () => { + if (isAnimating) return; + currentIndex = index; + updateCarousel(); + }); + }); + + let touchStartX = 0; + let touchEndX = 0; + + if (carousel) { + carousel.addEventListener('touchstart', (e) => { + touchStartX = e.changedTouches[0].screenX; + }, { passive: true }); + + carousel.addEventListener('touchend', (e) => { + touchEndX = e.changedTouches[0].screenX; + handleSwipe(); + }, { passive: true }); + } + + function handleSwipe() { + if (isAnimating) return; + + const swipeThreshold = 50; + const diff = touchStartX - touchEndX; + + if (Math.abs(diff) > swipeThreshold) { + if (diff > 0) { + rotateCarousel(1); + } else { + rotateCarousel(-1); + } + } + } + + if (carousel) { + carousel.addEventListener('wheel', (e) => { + if (isAnimating) return; + e.preventDefault(); + if (e.deltaY > 0) { + rotateCarousel(1); + } else { + rotateCarousel(-1); + } + }, { passive: false }); + } + + updateCarousel(); +} + +function setupGameCards() { + const gameCards = document.querySelectorAll('.game-card'); + + gameCards.forEach(card => { + card.addEventListener('click', (event) => { + const isExpanded = card.classList.contains('expanded'); + + if (isExpanded) { + card.classList.remove('expanded'); + } else { + gameCards.forEach(c => c.classList.remove('expanded')); + card.classList.add('expanded'); + } + + event.stopPropagation(); + }); + + const playButton = card.querySelector('.play-button'); + if (playButton) { + playButton.addEventListener('click', (event) => { + event.stopPropagation(); + }); + } + }); +} diff --git a/public/index.html b/public/index.html index 421f795..b18ea84 100644 --- a/public/index.html +++ b/public/index.html @@ -10,6 +10,24 @@ +
A PhD student at KU Leuven with a passion for game development and software independence.
-
- Currently I'm working on:
However in the past I also worked on:
-
+ Therapeutic exergame for wheelchair training with clinical protocol integration.
+For my PhD research at KU Leuven, I'm developing RollAbility, a therapeutic exergame that bridges player autonomy with clinical guidelines to enhance wheelchair training. Developed in collaboration with therapists, RollAbility is a game built onto a clinical protocol and controlled by an actual powered wheelchair. The game connects to the RollAbility App which allows therapists to control the training session in real-time. [[Read the paper|https://dl.acm.org/doi/abs/10.1145/3748621]] or [[watch the video|https://www.youtube.com/watch?v=8y9XFdSN_04]].
+
+ Interreg project building a lung cancer detection device with cross-platform UI.
+Alcove is an interreg project between Flemish, Walloon and French universities and hospitals that aims to build a device that detects lung cancer through a breath test. My role is to create a user interface for the device. This UI has to work both on android phones and on embedded linux devices. [[Read more about Alcove|https://alcove.crosss3.eu/nl/]].
+
+ Visual Studio Debugger and Test Scenes addons for the Godot engine.
+I published two small addons to the godot asset library. One addon called [[Godot Visual Studio Debugger|https://godotengine.org/asset-library/asset/3505]] which allows you to dynamically run the current scene open in the Godot editor directly in Visual Studio Debugger. The second addon called [[Godot Test Scenes|https://godotengine.org/asset-library/asset/3420]] extends the Godot editor with an additional run mode, this mode runs an associated test scene to the currently open one in the editor. They are both open source: [[Godot Test Scenes|https://github.com/DouweRavers/godot_test_scene]] and [[Godot Visual Studio Debugger|https://github.com/DouweRavers/godot_visualstudio_debugger/tree/main]].
+
+ Story-based action/puzzle game raising awareness about Autism.
+The project [[Kingfisher|https://kingfisher-game.com/]] is a game built by PossilbyPixels that raises awareness about Autism. It is a story-based action / puzzle game for PC and mobile. My role in the project was to build minigames that occur throughout the story and also to develop tools to help development. One of the tools I made for this project was a suburban neighborhood generator. This tool allowed us to draw streets in the editor which then were automatically filled with procedurally generated houses and gardens. You can see a demo in [[this video|/assets/vid/procedural_streets.mp4]]. You can wishlist the game on [[Steam|https://store.steampowered.com/app/4197280/Kingfisher_An_Autism_Tale/]]!
+
+ Game jam participation with 48-hour deadlines and no external resources.
+Between 2019 and 2024, I participated regularly in the Ludum Dare event. This event was all about creating games under tight deadlines of 48 hours and with no external resources such as audio or 3D art. After each event I published my game on [[Itch.io|https://coffeeplanet.itch.io/]] where they are still available for play. In the future I want to migrate them to this website. I want to especially highlight [[Cobor goes farming|https://coffeeplanet.itch.io/ludum-dare-51]] and [[Windy the Indie|https://coffeeplanet.itch.io/windy-the-indie]].
+
+ Procedural planet terrain generation with GPU compute shaders.
+For my Masterthesis at Group T KU Leuven I made a tool for Unity that creates a procedural planet terrain. The main challenge of this project was to optimize the algorithm to work as fast as possible. For this I leveraged GPU compute shaders to process large chunks of data at once. You can find the tool and my thesis paper [[here|https://github.com/DouweRavers/ThesisProject-ThePlanetEngine/tree/main]].
+
+ Gesture-based interaction with wearable hardware for virtual environments.
+In another project during my masters we explored gesture-based interactions in virtual environments. For this project we developed a prototype using Unity and custom wearable hardware to enable magic-like hand gestures for interfacing with a story game. See the game [[here|/assets/vid/wizard_gloves.mp4]] or you can find the game and paper [[here|https://github.com/DouweRavers/MasterProject-WizardsGlovesAdventure/tree/main]].
+- Under construction... -
+
+ - Under construction... -
+
+ A farming game made in 48 hours.
+ 2022 +
+ A puzzle platformer game.
+ 2022 +
+ A top-down adventure game.
+ 2021 +
+ A minimalist arcade shooter.
+ 2021 +
+ A story-driven puzzle game.
+ 2020 +
+ A platformer about indie development.
+ 2024 +