Sorry, there's nothing at this address.
+
+
+ A PhD student at KU Leuven with a passion for game development and software independence.
+
+ Currently I'm working on:
+
+
+ RollAbility
+ 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 build 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 or Watch the video.
+
+
+ Alcove
+ Alcove is a 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 on both android phones as on embedded linux devices.
+
Read more about Alcove.
+
However in the past I also worked on:
+ +
+
+ Godot Addons
+ I published two small addons to the godot asset library.
+
One addon called Godot Visual Studio Debugger which allows you to dynammicaly run the current scene open in the Godot editor directly in Visual Studio Debugger.
+
The second addons called Godot Test Scenes extends the Godot editor with an additional run mode, this mode runs a associated test scene to the currently open one in the editor.
+
They are both open source:
+
Godot Test Scenes and Godot Visual Studio Debugger
+
+
+ Kingfisher
+ The project Kingfisher is a game build by PossilbyPixels that rises awareness about Autism. It is a storybased 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 neigborhood generator. This tool allowed us to draw streets in the editor which then were automaticly filled with procedural generated houses and gardens. You can see a demo in this video.
+
You can wishlist the game on Steam!
+
+
+ Ludum Dare
+ Between 2019 and 2024, I participated regulary into 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 where they are still availble for play. In the future I want to migrate them to this website.
+
I want to especially highlight Cobor goes farming and Windy the Indy
+
+
+ Masterthesis: Planet Tool
+ 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.
+
+
+ Masterproject: Wizard Gloves
+ 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 or you can find the game and paper here
+
Under construction...
- \ No newline at end of file + diff --git a/Shared/Footer.razor b/Shared/Footer.razor new file mode 100644 index 0000000..785ecf0 --- /dev/null +++ b/Shared/Footer.razor @@ -0,0 +1,8 @@ +© @currentYear - douwco.be
+Made and hosted in EU
+Under construction...
- \ No newline at end of file + diff --git a/wwwroot/includes/home.html b/Shared/HomeSection.razor similarity index 86% rename from wwwroot/includes/home.html rename to Shared/HomeSection.razor index eb4c996..df6e1ca 100644 --- a/wwwroot/includes/home.html +++ b/Shared/HomeSection.razor @@ -1,7 +1,7 @@
+
- Welcome to the Douwco website.
+ Welcome to the Douwco website.
Ever wondered what machine the website you are visiting is run on? Well this time you know, just look to the image.
- This small homeserver hosts several open-source services like Nextcloud, Gitea, Overleaf community and ofcourse this
- website.
+ This small homeserver hosts several open-source services like Nextcloud, Gitea, Overleaf community and of course this
+ website.
Here I showcase my portfolio and all the games I've created over the years. If you are
a family member you can also find the different services in the Douwco Apps tab.
+
0}function Nr(e){return e<-1}Ur&&(Tr=new globalThis.FinalizationRegistry(Hr));const Or=Symbol.for("wasm js_owned_gc_handle"),Cr=Symbol.for("wasm cs_owned_js_handle"),Dr=Symbol.for("wasm do_not_force_dispose");function Fr(e){return Br(e)?Er[e]:Rr(e)?xr[0-e]:null}function Pr(e){if(hr(),e[Cr])return e[Cr];const t=Ir.length?Ir.pop():Ar++;return Er[t]=e,Object.isExtensible(e)&&("function"==typeof e&&Object.prototype.hasOwnProperty.call(e,"prototype")||(e[Cr]=t)),t}function Mr(e){let t;Br(e)?(t=Er[e],Er[e]=void 0,Ir.push(e)):Rr(e)&&(t=xr[0-e],xr[0-e]=void 0),null==t&&mt(!1,"ObjectDisposedException"),void 0!==t[Cr]&&(t[Cr]=void 0)}function zr(e,t){hr(),e[Or]=t,Ur&&Tr.register(e,t,e);const n=yr(e);jr.set(t,n)}function Vr(e,t,r){var o;hr(),e&&(t=e[Or],e[Or]=u,Ur&&Tr.unregister(e)),t!==u&&jr.delete(t)&&!r&<.is_runtime_running()&&!Gr&&function(e){e||mt(!1,"Must be valid gc_handle"),lt.assert_runtime_running();const t=Ke.stackSave();try{const t=$n(3),r=Ln(t,2);Wn(r,14),Kn(r,e),n&&!Nr(e)&&bn.isUI||kn(yn.ReleaseJSOwnedObjectByGCHandle,t)}finally{lt.is_runtime_running()&&Ke.stackRestore(t)}}(t),Nr(t)&&(o=t,$r.push(o))}function Wr(e){const t=e[Or];if(t==u)throw new Error("Assert failed: ObjectDisposedException");return t}function Hr(e){lt.is_runtime_running()&&Vr(null,e)}function qr(e){if(!e)return null;const t=jr.get(e);return t?t.deref():null}let Gr=!1;function Jr(e,t){let n=!1,r=!1;Gr=!0;let o=0,s=0,a=0,i=0;const c=[...jr.keys()];for(const e of c){const r=jr.get(e),o=r&&r.deref();if(Ur&&o&&Tr.unregister(o),o){const s="boolean"==typeof o[Dr]&&o[Dr];if(t&&We(`Proxy of C# ${typeof o} with GCHandle ${e} was still alive. ${s?"keeping":"disposing"}.`),s)n=!0;else{const t=lt.getPromiseController(o);t&&t.reject(new Error("WebWorker which is origin of the Task is being terminated.")),"function"==typeof o.dispose&&o.dispose(),o[Or]===e&&(o[Or]=u),!br&&r&&r.dispose(),a++}}}n||(jr.clear(),Ur&&(Tr=new globalThis.FinalizationRegistry(Hr)));const l=(e,n)=>{const o=n[e],s=o&&"boolean"==typeof o[Dr]&&o[Dr];if(s||(n[e]=void 0),o)if(t&&We(`Proxy of JS ${typeof o} with JSHandle ${e} was still alive. ${s?"keeping":"disposing"}.`),s)r=!0;else{const t=lt.getPromiseController(o);t&&t.reject(new Error("WebWorker which is origin of the Task is being terminated.")),"function"==typeof o.dispose&&o.dispose(),o[Cr]===e&&(o[Cr]=void 0),i++}};for(let e=0;e 0}function Nr(e){return e<-1}Ur&&(Tr=new globalThis.FinalizationRegistry(Hr));const Or=Symbol.for("wasm js_owned_gc_handle"),Cr=Symbol.for("wasm cs_owned_js_handle"),Dr=Symbol.for("wasm do_not_force_dispose");function Fr(e){return Br(e)?Er[e]:Rr(e)?xr[0-e]:null}function Pr(e){if(hr(),e[Cr])return e[Cr];const t=Ir.length?Ir.pop():Ar++;return Er[t]=e,Object.isExtensible(e)&&("function"==typeof e&&Object.prototype.hasOwnProperty.call(e,"prototype")||(e[Cr]=t)),t}function Mr(e){let t;Br(e)?(t=Er[e],Er[e]=void 0,Ir.push(e)):Rr(e)&&(t=xr[0-e],xr[0-e]=void 0),null==t&&mt(!1,"ObjectDisposedException"),void 0!==t[Cr]&&(t[Cr]=void 0)}function zr(e,t){hr(),e[Or]=t,Ur&&Tr.register(e,t,e);const n=yr(e);jr.set(t,n)}function Vr(e,t,r){var o;hr(),e&&(t=e[Or],e[Or]=u,Ur&&Tr.unregister(e)),t!==u&&jr.delete(t)&&!r&<.is_runtime_running()&&!Gr&&function(e){e||mt(!1,"Must be valid gc_handle"),lt.assert_runtime_running();const t=Ke.stackSave();try{const t=$n(3),r=Ln(t,2);Wn(r,14),Kn(r,e),n&&!Nr(e)&&bn.isUI||kn(yn.ReleaseJSOwnedObjectByGCHandle,t)}finally{lt.is_runtime_running()&&Ke.stackRestore(t)}}(t),Nr(t)&&(o=t,$r.push(o))}function Wr(e){const t=e[Or];if(t==u)throw new Error("Assert failed: ObjectDisposedException");return t}function Hr(e){lt.is_runtime_running()&&Vr(null,e)}function qr(e){if(!e)return null;const t=jr.get(e);return t?t.deref():null}let Gr=!1;function Jr(e,t){let n=!1,r=!1;Gr=!0;let o=0,s=0,a=0,i=0;const c=[...jr.keys()];for(const e of c){const r=jr.get(e),o=r&&r.deref();if(Ur&&o&&Tr.unregister(o),o){const s="boolean"==typeof o[Dr]&&o[Dr];if(t&&We(`Proxy of C# ${typeof o} with GCHandle ${e} was still alive. ${s?"keeping":"disposing"}.`),s)n=!0;else{const t=lt.getPromiseController(o);t&&t.reject(new Error("WebWorker which is origin of the Task is being terminated.")),"function"==typeof o.dispose&&o.dispose(),o[Or]===e&&(o[Or]=u),!br&&r&&r.dispose(),a++}}}n||(jr.clear(),Ur&&(Tr=new globalThis.FinalizationRegistry(Hr)));const l=(e,n)=>{const o=n[e],s=o&&"boolean"==typeof o[Dr]&&o[Dr];if(s||(n[e]=void 0),o)if(t&&We(`Proxy of JS ${typeof o} with JSHandle ${e} was still alive. ${s?"keeping":"disposing"}.`),s)r=!0;else{const t=lt.getPromiseController(o);t&&t.reject(new Error("WebWorker which is origin of the Task is being terminated.")),"function"==typeof o.dispose&&o.dispose(),o[Cr]===e&&(o[Cr]=void 0),i++}};for(let e=0;e
- A PhD student at KU Leuven with a passion for game development and software independence.
-
- RollAbility
- Alcove However in the past I also worked on:
- Godot Addons
- Kingfisher
- Ludum Dare
- Masterthesis: Planet Tool
- Masterproject: Wizard Gloves Made and hosted in 🇪🇺{e&&"AbortError"!==e&&"AbortError"!==e.name&&ze("http muted: "+e)}))}function No(e){try{e.isAborted||(e.streamWriter&&(Bo(e.streamWriter.abort()),e.isAborted=!0),e.streamReader&&(Bo(e.streamReader.cancel()),e.isAborted=!0)),e.isAborted||e.abortController.signal.aborted||e.abortController.abort("AbortError")}catch(e){}}function Oo(e,t,n){n>0||mt(!1,"expected bufferLength > 0");const r=new Span(t,n,0).slice();return Qr((async()=>{e.streamWriter||mt(!1,"expected streamWriter"),e.responsePromise||mt(!1,"expected fetch promise");try{await e.streamWriter.ready,await e.streamWriter.write(r)}catch(e){throw new Error("BrowserHttpWriteStream.Rejected")}}))}function Co(e){return e||mt(!1,"expected controller"),Qr((async()=>{e.streamWriter||mt(!1,"expected streamWriter"),e.responsePromise||mt(!1,"expected fetch promise");try{await e.streamWriter.ready,await e.streamWriter.close()}catch(e){throw new Error("BrowserHttpWriteStream.Rejected")}}))}function Do(e,t,n,r,o,s){const a=new TransformStream;return e.streamWriter=a.writable.getWriter(),Bo(e.streamWriter.closed),Bo(e.streamWriter.ready),Po(e,t,n,r,o,s,a.readable)}function Fo(e,t,n,r,o,s,a,i){return Po(e,t,n,r,o,s,new Span(a,i,0).slice())}function Po(e,t,n,r,o,s,a){jo(),hr(),t&&"string"==typeof t||mt(!1,"expected url string"),n&&r&&Array.isArray(n)&&Array.isArray(r)&&n.length===r.length||mt(!1,"expected headerNames and headerValues arrays"),o&&s&&Array.isArray(o)&&Array.isArray(s)&&o.length===s.length||mt(!1,"expected headerNames and headerValues arrays");const i=new Headers;for(let e=0;edocument.baseURI,getLocationHref:()=>location.href,scrollToElement:Se};function Le(e,t,n=!1){const r=Ce(e);!t.forceLoad&&Ee(r)?Fe(r,!1,t.replaceHistoryEntry,t.historyEntryState,n):function(e,t){if(location.href===e){const t=e+"?";history.replaceState(null,"",t),location.replace(e)}else t?location.replace(e):location.href=e}(e,t.replaceHistoryEntry)}async function Fe(e,t,n,r=void 0,o=!1){if(Pe(),function(e,t){const n=new URL(e),r=new URL(t);return n.origin===r.origin&&n.pathname===r.pathname&&n.search===r.search&&""!==r.hash}(location.href,e))return xe(e,n,r),void function(e){const t=e.indexOf("#");t!==e.length-1&&Se(e.substring(t+1))}(e);const i=Je();(o||!i?.hasLocationChangingEventListeners||await Be(e,r,t,i))&&(function(e,t){const n=new URL(e),r=new URL(t);return n.protocol===r.protocol&&n.host===r.host&&n.port===r.port&&n.pathname===r.pathname}(e,location.href)||(ye=!0),xe(e,n,r),await He(t))}function xe(e,t,n=void 0){t?history.replaceState({userState:n,_index:Re},"",e):(Re++,history.pushState({userState:n,_index:Re},"",e))}function Me(e){return new Promise((t=>{const n=_e;_e=()=>{_e=n,t()},history.go(e)}))}function Pe(){Oe&&(Oe(!1),Oe=null)}function Be(e,t,n,r){return new Promise((o=>{Pe(),ke++,Oe=o,r.locationChanging(ke,e,t,n)}))}async function He(e,t){const n=location.href;await Promise.all(Array.from(De,(async([t,r])=>{A(t)&&await r.locationChanged(n,history.state?.userState,e)})))}async function je(e){_e&&(Ie(),1)&&await _e(e),Re=history.state?._index??0}function Je(){const e=Ae();if(void 0!==e)return De.get(e)}const ze={focus:function(e,t){if(e instanceof HTMLElement)e.focus({preventScroll:t});else{if(!(e instanceof SVGElement))throw new Error("Unable to focus an invalid element.");if(!e.hasAttribute("tabindex"))throw new Error("Unable to focus an SVG element that does not have a tabindex.");e.focus({preventScroll:t})}},focusBySelector:function(e){const t=document.querySelector(e);t&&(t.hasAttribute("tabindex")||(t.tabIndex=-1),t.focus({preventScroll:!0}))}},$e={init:function(e,t,n,r=50){const o=Ue(t);(o||document.documentElement).style.overflowAnchor="none";const i=document.createRange();f(n.parentElement)&&(t.style.display="table-row",n.style.display="table-row");const s=new IntersectionObserver((function(r){r.forEach((r=>{if(!r.isIntersecting)return;i.setStartAfter(t),i.setEndBefore(n);const o=i.getBoundingClientRect().height,s=r.rootBounds?.height;r.target===t?e.invokeMethodAsync("OnSpacerBeforeVisible",r.intersectionRect.top-r.boundingClientRect.top,o,s):r.target===n&&n.offsetHeight>0&&e.invokeMethodAsync("OnSpacerAfterVisible",r.boundingClientRect.bottom-r.intersectionRect.bottom,o,s)}))}),{root:o,rootMargin:`${r}px`});s.observe(t),s.observe(n);const a=d(t),c=d(n),{observersByDotNetObjectId:l,id:u}=Ve(e);function d(e){const t={attributes:!0},n=new MutationObserver(((n,r)=>{f(e.parentElement)&&(r.disconnect(),e.style.display="table-row",r.observe(e,t)),s.unobserve(e),s.observe(e)}));return n.observe(e,t),n}function f(e){return null!==e&&(e instanceof HTMLTableElement&&""===e.style.display||"table"===e.style.display||e instanceof HTMLTableSectionElement&&""===e.style.display||"table-row-group"===e.style.display)}l[u]={intersectionObserver:s,mutationObserverBefore:a,mutationObserverAfter:c}},dispose:function(e){const{observersByDotNetObjectId:t,id:n}=Ve(e),r=t[n];r&&(r.intersectionObserver.disconnect(),r.mutationObserverBefore.disconnect(),r.mutationObserverAfter.disconnect(),e.dispose(),delete t[n])}},We=Symbol();function Ue(e){return e&&e!==document.body&&e!==document.documentElement?"visible"!==getComputedStyle(e).overflowY?e:Ue(e.parentElement):null}function Ve(e){const t=e._callDispatcher,n=e._id;return t[We]??={},{observersByDotNetObjectId:t[We],id:n}}const Ke={getAndRemoveExistingTitle:function(){const e=document.head?document.head.getElementsByTagName("title"):[];if(0===e.length)return null;let t=null;for(let n=e.length-1;n>=0;n--){const r=e[n],o=r.previousSibling;o instanceof Comment&&null!==W(o)||(null===t&&(t=r.textContent),r.parentNode?.removeChild(r))}return t}},Ge={init:function(e,t){t._blazorInputFileNextFileId=0,t.addEventListener("click",(function(){t.value=""})),t.addEventListener("change",(function(){t._blazorFilesById={};const n=Array.prototype.map.call(t.files,(function(e){const n={id:++t._blazorInputFileNextFileId,lastModified:new Date(e.lastModified).toISOString(),name:e.name,size:e.size,contentType:e.type,readPromise:void 0,arrayBuffer:void 0,blob:e};return t._blazorFilesById[n.id]=n,n}));e.invokeMethodAsync("NotifyChange",n)}))},toImageFile:async function(e,t,n,r,o){const i=Xe(e,t),s=await new Promise((function(e){const t=new Image;t.onload=function(){URL.revokeObjectURL(t.src),e(t)},t.onerror=function(){t.onerror=null,URL.revokeObjectURL(t.src)},t.src=URL.createObjectURL(i.blob)})),a=await new Promise((function(e){const t=Math.min(1,r/s.width),i=Math.min(1,o/s.height),a=Math.min(t,i),c=document.createElement("canvas");c.width=Math.round(s.width*a),c.height=Math.round(s.height*a),c.getContext("2d")?.drawImage(s,0,0,c.width,c.height),c.toBlob(e,n)})),c={id:++e._blazorInputFileNextFileId,lastModified:i.lastModified,name:i.name,size:a?.size||0,contentType:n,blob:a||i.blob};return e._blazorFilesById[c.id]=c,c},readFileData:async function(e,t){return Xe(e,t).blob}};function Xe(e,t){const n=e._blazorFilesById[t];if(!n)throw new Error(`There is no file with ID ${t}. The file list may have changed. See https://aka.ms/aspnet/blazor-input-file-multiple-selections.`);return n}const Ye=new Set,qe={enableNavigationPrompt:function(e){0===Ye.size&&window.addEventListener("beforeunload",Ze),Ye.add(e)},disableNavigationPrompt:function(e){Ye.delete(e),0===Ye.size&&window.removeEventListener("beforeunload",Ze)}};function Ze(e){e.preventDefault(),e.returnValue=!0}const Qe=new Map,et={navigateTo:function(e,t,n=!1){Le(e,t instanceof Object?t:{forceLoad:t,replaceHistoryEntry:n})},registerCustomEventType:function(e,t){if(!t)throw new Error("The options parameter is required.");if(i.has(e))throw new Error(`The event '${e}' is already registered.`);if(t.browserEventName){const n=s.get(t.browserEventName);n?n.push(e):s.set(t.browserEventName,[e]),a.forEach((n=>n(e,t.browserEventName)))}i.set(e,t)},rootComponents:v,runtime:{},_internal:{navigationManager:Te,domWrapper:ze,Virtualize:$e,PageTitle:Ke,InputFile:Ge,NavigationLock:qe,getJSDataStreamChunk:async function(e,t,n){return e instanceof Blob?await async function(e,t,n){const r=e.slice(t,t+n),o=await r.arrayBuffer();return new Uint8Array(o)}(e,t,n):function(e,t,n){return new Uint8Array(e.buffer,e.byteOffset+t,n)}(e,t,n)},attachWebRendererInterop:function(t,n,r,o){if(S.has(t))throw new Error(`Interop methods are already registered for renderer ${t}`);S.set(t,n),r&&o&&Object.keys(r).length>0&&function(t,n,r){if(p)throw new Error("Dynamic root components have already been enabled.");p=t,g=n;for(const[t,o]of Object.entries(r)){const r=e.findJSFunction(t,0);for(const e of o)r(e,n[e])}}(R(t),r,o),I.get(t)?.[0]?.(),function(e){for(const t of C)t(e)}(t)}}};window.Blazor=et;const tt=navigator,nt=tt.userAgentData&&tt.userAgentData.brands,rt=nt&&nt.length>0?nt.some((e=>"Google Chrome"===e.brand||"Microsoft Edge"===e.brand||"Chromium"===e.brand)):window.chrome,ot=tt.userAgentData?.platform??navigator.platform;function it(e){return 0!==e.debugLevel&&(rt||navigator.userAgent.includes("Firefox"))}let st=!1;function at(){const e=document.querySelector("#blazor-error-ui");e&&(e.style.display="block"),st||(st=!0,document.querySelectorAll("#blazor-error-ui .reload").forEach((e=>{e.onclick=function(e){location.reload(),e.preventDefault()}})),document.querySelectorAll("#blazor-error-ui .dismiss").forEach((e=>{e.onclick=function(e){const t=document.querySelector("#blazor-error-ui");t&&(t.style.display="none"),e.preventDefault()}})))}var ct,lt;!function(e){e[e.Default=0]="Default",e[e.Server=1]="Server",e[e.WebAssembly=2]="WebAssembly",e[e.WebView=3]="WebView"}(ct||(ct={})),function(e){e[e.Trace=0]="Trace",e[e.Debug=1]="Debug",e[e.Information=2]="Information",e[e.Warning=3]="Warning",e[e.Error=4]="Error",e[e.Critical=5]="Critical",e[e.None=6]="None"}(lt||(lt={}));class ut{constructor(e=!0,t,n,r=0){this.singleRuntime=e,this.logger=t,this.webRendererId=r,this.afterStartedCallbacks=[],n&&this.afterStartedCallbacks.push(...n)}async importInitializersAsync(e,t){await Promise.all(e.map((e=>async function(e,n){let r;var o;n.moduleExports||(o=n.name,r=new URL(o,document.baseURI).toString(),n.moduleExports=await import(r));const i=n.moduleExports;if(void 0!==i){if(e.singleRuntime){const{beforeStart:n,afterStarted:r,beforeWebAssemblyStart:o,afterWebAssemblyStarted:a,beforeServerStart:c,afterServerStarted:l}=i;let u=n;e.webRendererId===ct.Server&&c&&(u=c),e.webRendererId===ct.WebAssembly&&o&&(u=o);let d=r;return e.webRendererId===ct.Server&&l&&(d=l),e.webRendererId===ct.WebAssembly&&a&&(d=a),s(e,u,d,t)}return function(e,t,n){const o=n[0],{beforeStart:i,afterStarted:a,beforeWebStart:c,afterWebStarted:l,beforeWebAssemblyStart:u,afterWebAssemblyStarted:d,beforeServerStart:f,afterServerStarted:m}=t,h=!(c||l||u||d||f||m||!i&&!a),p=h&&o.enableClassicInitializers;if(h&&!o.enableClassicInitializers)e.logger?.log(lt.Warning,`Initializer '${r}' will be ignored because multiple runtimes are available. Use 'before(Web|WebAssembly|Server)Start' and 'after(Web|WebAssembly|Server)Started' instead.`);else if(p)return s(e,i,a,n);if(function(e){e.webAssembly?e.webAssembly.initializers||(e.webAssembly.initializers={beforeStart:[],afterStarted:[]}):e.webAssembly={initializers:{beforeStart:[],afterStarted:[]}},e.circuit?e.circuit.initializers||(e.circuit.initializers={beforeStart:[],afterStarted:[]}):e.circuit={initializers:{beforeStart:[],afterStarted:[]}}}(o),u&&o.webAssembly.initializers.beforeStart.push(u),d&&o.webAssembly.initializers.afterStarted.push(d),f&&o.circuit.initializers.beforeStart.push(f),m&&o.circuit.initializers.afterStarted.push(m),l&&e.afterStartedCallbacks.push(l),c)return c(o)}(e,i,t)}function s(e,t,n,r){if(n&&e.afterStartedCallbacks.push(n),t)return t(...r)}}(this,e))))}async invokeAfterStartedCallbacks(e){const t=(n=this.webRendererId,I.get(n)?.[1]);var n;t&&await t,await Promise.all(this.afterStartedCallbacks.map((t=>t(e))))}}let dt,ft,mt,ht,pt=null;const gt={load:function(e,t){return async function(e,t){const{dotnet:n}=await async function(e){if("undefined"==typeof WebAssembly||!WebAssembly.validate)throw new Error("This browser does not support WebAssembly.");if(e.loadBootResource){const t="dotnetjs",n=e.loadBootResource(t,"dotnet.js","_framework/dotnet.js","","js-module-dotnet");if("string"==typeof n){const e=new URL(n,document.baseURI).toString();return await import(e)}if(n)throw new Error(`For a ${t} resource, custom loaders must supply a URI string.`)}return await import("./dotnet.js")}(e),r=function(e,t){const n={maxParallelDownloads:1e6,enableDownloadRetry:!1};e.environment&&(n.applicationEnvironment=e.environment);const r={...window.Module||{},onConfigLoaded:async n=>{n.environmentVariables||(n.environmentVariables={}),"sharded"===n.globalizationMode&&(n.environmentVariables.__BLAZOR_SHARDED_ICU="1"),et._internal.getApplicationEnvironment=()=>n.applicationEnvironment,t?.(n),ht=await async function(e,t){if(e.initializers)return await Promise.all(e.initializers.beforeStart.map((t=>t(e)))),new ut(!1,void 0,e.initializers.afterStarted,ct.WebAssembly);{const n=[e,t.resources?.extensions??{}],r=new ut(!0,void 0,void 0,ct.WebAssembly),o=t?.resources?.libraryInitializers;let i;return i=o?"length"in o?o:Object.keys(o).map((e=>({name:e}))):[],await r.importInitializersAsync(i,n),r}}(e,n)},onDownloadResourceProgress:bt,config:n,out:yt,err:wt};return r}(e,t);e.applicationCulture&&n.withApplicationCulture(e.applicationCulture),e.environment&&n.withApplicationEnvironment(e.environment),e.loadBootResource&&n.withResourceLoader(e.loadBootResource),n.withModuleConfig(r),e.configureRuntime&&e.configureRuntime(n),mt=await n.create()}(e,t)},start:function(){return async function(){if(!mt)throw new Error("The runtime must be loaded it gets configured.");const{setModuleImports:t,INTERNAL:n,getConfig:r,invokeLibraryInitializers:o}=mt;ft=n,function(e){const t=ot.match(/^Mac/i)?"Cmd":"Alt";it(e)&&console.info(`Debugging hotkey: Shift+${t}+D (when application has focus)`),document.addEventListener("keydown",(t=>{t.shiftKey&&(t.metaKey||t.altKey)&&"KeyD"===t.code&&(it(e)?navigator.userAgent.includes("Firefox")?async function(){const e=await fetch(`_framework/debug?url=${encodeURIComponent(location.href)}&isFirefox=true`);200!==e.status&&console.warn(await e.text())}():rt?function(){const e=document.createElement("a");e.href=`_framework/debug?url=${encodeURIComponent(location.href)}`,e.target="_blank",e.rel="noopener noreferrer",e.click()}():console.error("Currently, only Microsoft Edge (80+), Google Chrome, or Chromium, are supported for debugging."):console.error("Cannot start debugging, because the application was not compiled with debugging enabled."))}))}(r()),et.runtime=mt,et._internal.dotNetCriticalError=wt,t("blazor-internal",{Blazor:{_internal:et._internal}});const i=await mt.getAssemblyExports("Microsoft.AspNetCore.Components.WebAssembly");return Object.assign(et._internal,{dotNetExports:{...i.Microsoft.AspNetCore.Components.WebAssembly.Services.DefaultWebAssemblyJSRuntime}}),dt=e.attachDispatcher({beginInvokeDotNetFromJS:(e,t,n,r,o)=>{if(Et(),!r&&!t)throw new Error("Either assemblyName or dotNetObjectId must have a non null value.");const i=r?r.toString():t;et._internal.dotNetExports.BeginInvokeDotNet(e?e.toString():null,i,n,o)},endInvokeJSFromDotNet:(e,t,n)=>{et._internal.dotNetExports.EndInvokeJS(n)},sendByteArray:(e,t)=>{et._internal.dotNetExports.ReceiveByteArrayFromJS(e,t)},invokeDotNetFromJS:(e,t,n,r)=>(Et(),et._internal.dotNetExports.InvokeDotNet(e||null,t,n??0,r))}),{invokeLibraryInitializers:o}}()},callEntryPoint:async function(){try{await mt.runMain(mt.getConfig().mainAssemblyName,[])}catch(e){console.error(e),at()}},getArrayEntryPtr:function(e,t,n){const r=function(e){return e+12}(e)+4+t*n;return r},getObjectFieldsBaseAddress:function(e){return e+8},readInt16Field:function(e,t){return mt.getHeapI16(e+(t||0))},readInt32Field:function(e,t){return mt.getHeapI32(e+(t||0))},readUint64Field:function(e,t){return mt.getHeapU52(e+(t||0))},readObjectField:function(e,t){return mt.getHeapU32(e+(t||0))},readStringField:function(e,t,n){const r=mt.getHeapU32(e+(t||0));if(0===r)return null;if(n){const e=ft.monoObjectAsBoolOrNullUnsafe(r);if("boolean"==typeof e)return e?"":null}return ft.monoStringToStringUnsafe(r)},readStructField:function(e,t){return e+(t||0)},beginHeapLock:function(){return Et(),pt=St.create(),pt},invokeWhenHeapUnlocked:function(e){pt?pt.enqueuePostReleaseAction(e):e()}};function bt(e,t){const n=e/t*100;document.documentElement.style.setProperty("--blazor-load-percentage",`${n}%`),document.documentElement.style.setProperty("--blazor-load-percentage-text",`"${Math.floor(n)}%"`)}const vt=["DEBUGGING ENABLED"],yt=e=>vt.indexOf(e)<0&&console.log(e),wt=e=>{console.error(e||"(null)"),at()};function Et(){if(pt)throw new Error("Assertion failed - heap is currently locked")}class St{enqueuePostReleaseAction(e){this.postReleaseActions||(this.postReleaseActions=[]),this.postReleaseActions.push(e)}release(){if(pt!==this)throw new Error("Trying to release a lock which isn't current");for(ft.mono_wasm_gc_unlock(),pt=null;this.postReleaseActions?.length;)this.postReleaseActions.shift()(),Et()}static create(){return ft.mono_wasm_gc_lock(),new St}}class Ct{constructor(e){this.batchAddress=e,this.arrayRangeReader=It,this.arrayBuilderSegmentReader=At,this.diffReader=Nt,this.editReader=Rt,this.frameReader=kt}updatedComponents(){return t.readStructField(this.batchAddress,0)}referenceFrames(){return t.readStructField(this.batchAddress,It.structLength)}disposedComponentIds(){return t.readStructField(this.batchAddress,2*It.structLength)}disposedEventHandlerIds(){return t.readStructField(this.batchAddress,3*It.structLength)}updatedComponentsEntry(e,t){return Dt(e,t,Nt.structLength)}referenceFramesEntry(e,t){return Dt(e,t,kt.structLength)}disposedComponentIdsEntry(e,n){const r=Dt(e,n,4);return t.readInt32Field(r)}disposedEventHandlerIdsEntry(e,n){const r=Dt(e,n,8);return t.readUint64Field(r)}}const It={structLength:8,values:e=>t.readObjectField(e,0),count:e=>t.readInt32Field(e,4)},At={structLength:12,values:e=>{const n=t.readObjectField(e,0),r=t.getObjectFieldsBaseAddress(n);return t.readObjectField(r,0)},offset:e=>t.readInt32Field(e,4),count:e=>t.readInt32Field(e,8)},Nt={structLength:4+At.structLength,componentId:e=>t.readInt32Field(e,0),edits:e=>t.readStructField(e,4),editsEntry:(e,t)=>Dt(e,t,Rt.structLength)},Rt={structLength:20,editType:e=>t.readInt32Field(e,0),siblingIndex:e=>t.readInt32Field(e,4),newTreeIndex:e=>t.readInt32Field(e,8),moveToSiblingIndex:e=>t.readInt32Field(e,8),removedAttributeName:e=>t.readStringField(e,16)},kt={structLength:36,frameType:e=>t.readInt16Field(e,4),subtreeLength:e=>t.readInt32Field(e,8),elementReferenceCaptureId:e=>t.readStringField(e,16),componentId:e=>t.readInt32Field(e,12),elementName:e=>t.readStringField(e,16),textContent:e=>t.readStringField(e,16),markupContent:e=>t.readStringField(e,16),attributeName:e=>t.readStringField(e,16),attributeValue:e=>t.readStringField(e,24,!0),attributeEventHandlerId:e=>t.readUint64Field(e,8)};function Dt(e,n,r){return t.getArrayEntryPtr(e,n,r)}const _t=/^\s*Blazor-WebAssembly-Component-State:(?{await dt.invokeDotNetStaticMethodAsync("Microsoft.AspNetCore.Components.WebAssembly","NotifyLocationChanged",e,t,n)}),(async(e,t,n,r)=>{const o=await dt.invokeDotNetStaticMethodAsync("Microsoft.AspNetCore.Components.WebAssembly","NotifyLocationChangingAsync",t,n,r);et._internal.navigationManager.endLocationChanging(e,o)}));const a=new Ut(e);et._internal.registeredComponents={getRegisteredComponentsCount:()=>a.getCount(),getAssembly:e=>a.getAssembly(e),getTypeName:e=>a.getTypeName(e),getParameterDefinitions:e=>a.getParameterDefinitions(e)||"",getParameterValues:e=>a.getParameterValues(e)||""},et._internal.getPersistedState=()=>Tt(document,_t)||"",et._internal.getInitialComponentsUpdate=()=>Vt,et._internal.updateRootComponents=(e,t)=>{et._internal.dotNetExports?.UpdateRootComponentsCore(e,t)},et._internal.endUpdateRootComponents=t=>e.onAfterUpdateRootComponents?.(t),et._internal.attachRootComponentToElement=(e,t,n)=>{const r=a.resolveRegisteredElement(e);r?we(n,r,t,!1):function(e,t,n){const r="::before";let o=!1;if(e.endsWith("::after"))e=e.slice(0,-7),o=!0;else if(e.endsWith(r))throw new Error(`The '${r}' selector is not supported.`);const i=function(e){const t=h.get(e);if(t)return h.delete(e),t}(e)||document.querySelector(e);if(!i)throw new Error(`Could not find any element matching selector '${e}'.`);we(n,H(i,!0),t,o)}(e,t,n)};try{await i,await s.start()}catch(e){throw new Error(`Failed to start platform. Reason: ${e}`)}s.callEntryPoint(),ht.invokeAfterStartedCallbacks(et),r()}function Zt(e){return Pt??=(async()=>{await Gt;const t=Mt??{};t.environment||(t.environment=e?.environmentName??void 0);const n=Mt?.configureRuntime;t.configureRuntime=t=>{n?.(t),e?.environmentVariables&&t.withEnvironmentVariables(e.environmentVariables)},await gt.load(t,Ht)})(),Pt}function Qt(e,t,n,r,o,i){return 0!==o?(dt.beginInvokeJSFromDotNet(o,e,r,n,t,i),null):dt.invokeJSFromDotNet(e,r,n,t,i)}function en(e,t,n){dt.endInvokeDotNetFromJS(e,t,n)}function tn(e,t,n,r){!function(e,t,n,r,o){let i=Qe.get(t);if(!i){const n=new ReadableStream({start(e){Qe.set(t,e),i=e}});e.supplyDotNetStream(t,n)}o?(i.error(o),Qe.delete(t)):0===r?(i.close(),Qe.delete(t)):i.enqueue(n.length===r?n:n.subarray(0,r))}(dt,e,t,n,r)}function nn(e,t){dt.receiveByteArray(e,t)}class rn{constructor(e){this.initialComponents=e}resolveRootComponent(e){return this.initialComponents[e]}}class on{constructor(){this._eventListeners=new Map}static create(e){const t=new on;return e.addEventListener=t.addEventListener.bind(t),e.removeEventListener=t.removeEventListener.bind(t),t}addEventListener(e,t){let n=this._eventListeners.get(e);n||(n=new Set,this._eventListeners.set(e,n)),n.add(t)}removeEventListener(e,t){this._eventListeners.get(e)?.delete(t)}dispatchEvent(e,t){const n=this._eventListeners.get(e);if(!n)return;const r={...t,type:e};for(const e of n)e(r)}}let sn=!1;async function an(e){if(sn)throw new Error("Blazor has already started.");sn=!0,Xt(Promise.resolve(e||{})),on.create(et);const t=Lt(document,"webassembly"),n=function(){const e=Tt(document,Ot,"options");if(e)return JSON.parse(e)}(),r=new rn(t);await Yt(r,n)}et.start=an,window.DotNet=e,document&&document.currentScript&&"false"!==document.currentScript.getAttribute("autostart")&&an().catch(wt)}();
diff --git a/bin/Debug/net10.0/wwwroot/_framework/blazor.webassembly.js.gz b/bin/Debug/net10.0/wwwroot/_framework/blazor.webassembly.js.gz
new file mode 100644
index 0000000..b41e131
Binary files /dev/null and b/bin/Debug/net10.0/wwwroot/_framework/blazor.webassembly.js.gz differ
diff --git a/bin/Debug/net10.0/wwwroot/_framework/dotnet.js b/bin/Debug/net10.0/wwwroot/_framework/dotnet.js
new file mode 100644
index 0000000..8a0ffca
--- /dev/null
+++ b/bin/Debug/net10.0/wwwroot/_framework/dotnet.js
@@ -0,0 +1,1310 @@
+//! Licensed to the .NET Foundation under one or more agreements.
+//! The .NET Foundation licenses this file to you under the MIT license.
+
+var e=!1;const t=async()=>WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,4,1,96,0,0,3,2,1,0,10,8,1,6,0,6,64,25,11,11])),o=async()=>WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,5,1,96,0,1,123,3,2,1,0,10,15,1,13,0,65,1,253,15,65,2,253,15,253,128,2,11])),n=async()=>WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,5,1,96,0,1,123,3,2,1,0,10,10,1,8,0,65,0,253,15,253,98,11])),r=Symbol.for("wasm promise_control");function i(e,t){let o=null;const n=new Promise((function(n,r){o={isDone:!1,promise:null,resolve:t=>{o.isDone||(o.isDone=!0,n(t),e&&e())},reject:e=>{o.isDone||(o.isDone=!0,r(e),t&&t())}}}));o.promise=n;const i=n;return i[r]=o,{promise:i,promise_control:o}}function s(e){return e[r]}function a(e){e&&function(e){return void 0!==e[r]}(e)||Be(!1,"Promise is not controllable")}const l="__mono_message__",c=["debug","log","trace","warn","info","error"],d="MONO_WASM: ";let u,f,m,g,p,h;function w(e){g=e}function b(e){if(Pe.diagnosticTracing){const t="function"==typeof e?e():e;console.debug(d+t)}}function y(e,...t){console.info(d+e,...t)}function v(e,...t){console.info(e,...t)}function E(e,...t){console.warn(d+e,...t)}function _(e,...t){if(t&&t.length>0&&t[0]&&"object"==typeof t[0]){if(t[0].silent)return;if(t[0].toString)return void console.error(d+e,t[0].toString())}console.error(d+e,...t)}function x(e,t,o){return function(...n){try{let r=n[0];if(void 0===r)r="undefined";else if(null===r)r="null";else if("function"==typeof r)r=r.toString();else if("string"!=typeof r)try{r=JSON.stringify(r)}catch(e){r=r.toString()}t(o?JSON.stringify({method:e,payload:r,arguments:n.slice(1)}):[e+r,...n.slice(1)])}catch(e){m.error(`proxyConsole failed: ${e}`)}}}function j(e,t,o){f=t,g=e,m={...t};const n=`${o}/console`.replace("https://","wss://").replace("http://","ws://");u=new WebSocket(n),u.addEventListener("error",A),u.addEventListener("close",S),function(){for(const e of c)f[e]=x(`console.${e}`,T,!0)}()}function R(e){let t=30;const o=()=>{u?0==u.bufferedAmount||0==t?(e&&v(e),function(){for(const e of c)f[e]=x(`console.${e}`,m.log,!1)}(),u.removeEventListener("error",A),u.removeEventListener("close",S),u.close(1e3,e),u=void 0):(t--,globalThis.setTimeout(o,100)):e&&m&&m.log(e)};o()}function T(e){u&&u.readyState===WebSocket.OPEN?u.send(e):m.log(e)}function A(e){m.error(`[${g}] proxy console websocket error: ${e}`,e)}function S(e){m.debug(`[${g}] proxy console websocket closed: ${e}`,e)}function D(){Pe.preferredIcuAsset=O(Pe.config);let e="invariant"==Pe.config.globalizationMode;if(!e)if(Pe.preferredIcuAsset)Pe.diagnosticTracing&&b("ICU data archive(s) available, disabling invariant mode");else{if("custom"===Pe.config.globalizationMode||"all"===Pe.config.globalizationMode||"sharded"===Pe.config.globalizationMode){const e="invariant globalization mode is inactive and no ICU data archives are available";throw _(`ERROR: ${e}`),new Error(e)}Pe.diagnosticTracing&&b("ICU data archive(s) not available, using invariant globalization mode"),e=!0,Pe.preferredIcuAsset=null}const t="DOTNET_SYSTEM_GLOBALIZATION_INVARIANT",o=Pe.config.environmentVariables;if(void 0===o[t]&&e&&(o[t]="1"),void 0===o.TZ)try{const e=Intl.DateTimeFormat().resolvedOptions().timeZone||null;e&&(o.TZ=e)}catch(e){y("failed to detect timezone, will fallback to UTC")}}function O(e){var t;if((null===(t=e.resources)||void 0===t?void 0:t.icu)&&"invariant"!=e.globalizationMode){const t=e.applicationCulture||(ke?globalThis.navigator&&globalThis.navigator.languages&&globalThis.navigator.languages[0]:Intl.DateTimeFormat().resolvedOptions().locale),o=e.resources.icu;let n=null;if("custom"===e.globalizationMode){if(o.length>=1)return o[0].name}else t&&"all"!==e.globalizationMode?"sharded"===e.globalizationMode&&(n=function(e){const t=e.split("-")[0];return"en"===t||["fr","fr-FR","it","it-IT","de","de-DE","es","es-ES"].includes(e)?"icudt_EFIGS.dat":["zh","ko","ja"].includes(t)?"icudt_CJK.dat":"icudt_no_CJK.dat"}(t)):n="icudt.dat";if(n)for(let e=0;e{e&&"AbortError"!==e&&"AbortError"!==e.name&&ze("http muted: "+e)}))}function No(e){try{e.isAborted||(e.streamWriter&&(Bo(e.streamWriter.abort()),e.isAborted=!0),e.streamReader&&(Bo(e.streamReader.cancel()),e.isAborted=!0)),e.isAborted||e.abortController.signal.aborted||e.abortController.abort("AbortError")}catch(e){}}function Oo(e,t,n){n>0||mt(!1,"expected bufferLength > 0");const r=new Span(t,n,0).slice();return Qr((async()=>{e.streamWriter||mt(!1,"expected streamWriter"),e.responsePromise||mt(!1,"expected fetch promise");try{await e.streamWriter.ready,await e.streamWriter.write(r)}catch(e){throw new Error("BrowserHttpWriteStream.Rejected")}}))}function Co(e){return e||mt(!1,"expected controller"),Qr((async()=>{e.streamWriter||mt(!1,"expected streamWriter"),e.responsePromise||mt(!1,"expected fetch promise");try{await e.streamWriter.ready,await e.streamWriter.close()}catch(e){throw new Error("BrowserHttpWriteStream.Rejected")}}))}function Do(e,t,n,r,o,s){const a=new TransformStream;return e.streamWriter=a.writable.getWriter(),Bo(e.streamWriter.closed),Bo(e.streamWriter.ready),Po(e,t,n,r,o,s,a.readable)}function Fo(e,t,n,r,o,s,a,i){return Po(e,t,n,r,o,s,new Span(a,i,0).slice())}function Po(e,t,n,r,o,s,a){jo(),hr(),t&&"string"==typeof t||mt(!1,"expected url string"),n&&r&&Array.isArray(n)&&Array.isArray(r)&&n.length===r.length||mt(!1,"expected headerNames and headerValues arrays"),o&&s&&Array.isArray(o)&&Array.isArray(s)&&o.length===s.length||mt(!1,"expected headerNames and headerValues arrays");const i=new Headers;for(let e=0;e
- Hi, I'm Douwe
-
- Currently I'm working on:
-
-
- 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 build 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 or Watch the video.
-
-
- Alcove is a 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 on both android phones as on embedded linux devices.
-
Read more about Alcove.
-
-
- I published two small addons to the godot asset library.
-
One addon called Godot Visual Studio Debugger which allows you to dynammicaly run the current scene open in the Godot editor directly in Visual Studio Debugger.
-
The second addons called Godot Test Scenes extends the Godot editor with an additional run mode, this mode runs a associated test scene to the currently open one in the editor.
-
They are both open source:
-
Godot Test Scenes and Godot Visual Studio Debugger
-
-
- The project Kingfisher is a game build by PossilbyPixels that rises awareness about Autism. It is a storybased 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 neigborhood generator. This tool allowed us to draw streets in the editor which then were automaticly filled with procedural generated houses and gardens. You can see a demo in this video.
-
You can wishlist the game on Steam!
-
-
- Between 2019 and 2024, I participated regulary into 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 where they are still availble for play. In the future I want to migrate them to this website.
-
I want to especially highlight Cobor goes farming and Windy the Indy
-
-
- 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.
-
-
- 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 or you can find the game and paper here
-