Virtuele tour · Productie

Armoedefonds

Een virtuele tour door de loods — radicaal transparant.

Armoedefonds
Jaar · 2026Diensten · Concept · Videoproductie · Virtuele tour
De uitdaging

Het Armoedefonds wilde donateurs en partners meenemen achter de schermen, zonder gelikte marketing die onecht voelt. Geen reclame, maar radicale transparantie.

Onze aanpak

Eerlijke regie

Een rondleiding zonder script of acteurs — puur de dagelijkse werkelijkheid.

Productie

Hoogwaardige beeld- en geluidskwaliteit.

Narratief

Gestructureerd tot een verhaal dat impact uitlegt en raakt.

Permanent

strategisch asset

Vertrouwen

transparantie voor donateurs

Herbruikbaar

voor site, presentaties & funding

Armoedefonds 1
Armoedefonds 2
Armoedefonds 3

Maak van jouw verhaal de Final Frame

(function(){ var nav=document.getElementById('on-nav'); if(nav) window.addEventListener('scroll',function(){nav.classList.toggle('scrolled',window.scrollY>40)},{passive:true}); if(window.self!==window.top){ document.querySelectorAll('.on-rv').forEach(function(el){el.classList.add('in')}); var builderNav=document.getElementById('on-nav'); if(builderNav){builderNav.style.position='relative';builderNav.style.top='auto';builderNav.style.left='auto';builderNav.style.right='auto'} document.querySelectorAll('.on-page').forEach(function(el){el.style.paddingTop='0'}); }else{ var io=new IntersectionObserver(function(entries){ entries.forEach(function(e){ if(!e.isIntersecting) return; e.target.classList.remove('on-will'); e.target.classList.add('in'); io.unobserve(e.target); }); },{threshold:.08}); // Perf: only HIDE (.on-will) elements below the fold — above-the-fold content // stays painted so it can't delay LCP waiting on JS. var vhR=window.innerHeight||document.documentElement.clientHeight||800; document.querySelectorAll('.on-rv').forEach(function(el){ var r=el.getBoundingClientRect(); if(r.top-40){el.classList.add('in');} else{el.classList.add('on-will');io.observe(el);} }); } // Build the mobile drawer + overlay LAZILY on first open (post-hydration) // instead of at HTML-parse time — appending to before React hydrates // the /s/ render path caused a hydration mismatch (React #418). The guard // makes this idempotent if the block is injected/executed twice. function onEnsureMobDrawer(){ if(document.getElementById('on-mob-drawer')) return; var over=document.createElement('div'); over.className='on-mob-overlay';over.id='on-mob-over'; var drw=document.createElement('nav'); drw.id='on-mob-drawer'; drw.innerHTML=[['Home','/'],['Werk','/work'],['Diensten','/services'],['Prijzen','/pricing'],['Studio','/studio'],['Contact','/contact']].map(function(p){ return ''+p[0]+''; }).join(''); document.body.appendChild(over);document.body.appendChild(drw); } window.onMenu=function(){ onEnsureMobDrawer(); var btn=document.getElementById('on-mob-btn'); var drw=document.getElementById('on-mob-drawer'); var ov=document.getElementById('on-mob-over'); if(!drw||!ov) return; var opening=!drw.classList.contains('open'); drw.classList.toggle('open',opening); ov.classList.toggle('open',opening); if(btn) btn.classList.toggle('open',opening); document.body.style.overflow=opening?'hidden':''; }; // Countup — HTML carries the FINAL value (renderer parity + no-JS safe); // the live site animates from 0 up to it. Skipped in the builder iframe. if(window.self===window.top&&typeof IntersectionObserver!=='undefined'){ var cio=new IntersectionObserver(function(entries){ entries.forEach(function(en){ if(!en.isIntersecting) return; cio.unobserve(en.target); var el=en.target,fin=el.getAttribute('data-on-count')||el.textContent; var num=parseInt(fin,10)||0,t0=null; function step(ts){ if(!t0)t0=ts; var p=Math.min(1,(ts-t0)/1000);p=1-Math.pow(1-p,3); el.textContent=String(Math.round(num*p)); if(p<1)requestAnimationFrame(step);else el.textContent=fin; } requestAnimationFrame(step); }); },{threshold:.4}); document.querySelectorAll('[data-on-count]').forEach(function(el){cio.observe(el)}); } // Work filter tabs — hide via display none on the wrapper (never opacity) function onFilter(cat){ document.querySelectorAll('[data-on-cat]').forEach(function(w){ w.style.display=(cat==='all'||w.getAttribute('data-on-cat')===cat)?'':'none'; }); } // Delegated clicks — inline onclick attrs are stripped on canvas conversion document.addEventListener('click',function(e){ if(!e.target||!e.target.closest) return; var el; el=e.target.closest('#on-mob-btn'); if(el){onMenu();return;} el=e.target.closest('#on-mob-over'); if(el){onMenu();return;} el=e.target.closest('[data-on-tab]');if(el){ document.querySelectorAll('[data-on-tab]').forEach(function(t){t.classList.remove('act')}); el.classList.add('act'); onFilter(el.getAttribute('data-on-tab')); return; } }); // Self-hosted background videos: force muted (SSR can drop the attribute) and // call play() — Safari reliably autoplays muted HTML5 video this way. function ffPlay(v){ try{ v.muted=true; v.setAttribute('muted',''); var p=v.play(); if(p&&p.catch)p.catch(function(){}); }catch(e){} } document.querySelectorAll('video[autoplay]').forEach(function(v){ ffPlay(v); v.addEventListener('canplay',function(){ffPlay(v)},{once:true}); if('IntersectionObserver' in window){ new IntersectionObserver(function(es){es.forEach(function(e){if(e.isIntersecting)ffPlay(e.target)})},{threshold:.1}).observe(v); } }); })();(function(){ var nav=document.getElementById('on-nav'); if(nav) window.addEventListener('scroll',function(){nav.classList.toggle('scrolled',window.scrollY>40)},{passive:true}); if(window.self!==window.top){ document.querySelectorAll('.on-rv').forEach(function(el){el.classList.add('in')}); var builderNav=document.getElementById('on-nav'); if(builderNav){builderNav.style.position='relative';builderNav.style.top='auto';builderNav.style.left='auto';builderNav.style.right='auto'} document.querySelectorAll('.on-page').forEach(function(el){el.style.paddingTop='0'}); }else{ document.querySelectorAll('.on-rv').forEach(function(el){el.classList.add('on-will')}); var io=new IntersectionObserver(function(entries){ entries.forEach(function(e){ if(!e.isIntersecting) return; e.target.classList.remove('on-will'); e.target.classList.add('in'); io.unobserve(e.target); }); },{threshold:.08}); document.querySelectorAll('.on-rv').forEach(function(el){io.observe(el)}); } (function(){ var over=document.createElement('div'); over.className='on-mob-overlay';over.id='on-mob-over'; var drw=document.createElement('nav'); drw.id='on-mob-drawer'; drw.innerHTML=[['Home','/'],['Werk','/work'],['Diensten','/services'],['Prijzen','/pricing'],['Studio','/studio'],['Contact','/contact']].map(function(p){ return ''+p[0]+''; }).join(''); document.body.appendChild(over);document.body.appendChild(drw); })(); window.onMenu=function(){ var btn=document.getElementById('on-mob-btn'); var drw=document.getElementById('on-mob-drawer'); var ov=document.getElementById('on-mob-over'); if(!drw||!ov) return; var opening=!drw.classList.contains('open'); drw.classList.toggle('open',opening); ov.classList.toggle('open',opening); if(btn) btn.classList.toggle('open',opening); document.body.style.overflow=opening?'hidden':''; }; // Countup — HTML carries the FINAL value (renderer parity + no-JS safe); // the live site animates from 0 up to it. Skipped in the builder iframe. if(window.self===window.top&&typeof IntersectionObserver!=='undefined'){ var cio=new IntersectionObserver(function(entries){ entries.forEach(function(en){ if(!en.isIntersecting) return; cio.unobserve(en.target); var el=en.target,fin=el.getAttribute('data-on-count')||el.textContent; var num=parseInt(fin,10)||0,t0=null; function step(ts){ if(!t0)t0=ts; var p=Math.min(1,(ts-t0)/1000);p=1-Math.pow(1-p,3); el.textContent=String(Math.round(num*p)); if(p<1)requestAnimationFrame(step);else el.textContent=fin; } requestAnimationFrame(step); }); },{threshold:.4}); document.querySelectorAll('[data-on-count]').forEach(function(el){cio.observe(el)}); } // Work filter tabs — hide via display none on the wrapper (never opacity) function onFilter(cat){ document.querySelectorAll('[data-on-cat]').forEach(function(w){ w.style.display=(cat==='all'||w.getAttribute('data-on-cat')===cat)?'':'none'; }); } // Delegated clicks — inline onclick attrs are stripped on canvas conversion document.addEventListener('click',function(e){ if(!e.target||!e.target.closest) return; var el; el=e.target.closest('#on-mob-btn'); if(el){onMenu();return;} el=e.target.closest('#on-mob-over'); if(el){onMenu();return;} el=e.target.closest('[data-on-tab]');if(el){ document.querySelectorAll('[data-on-tab]').forEach(function(t){t.classList.remove('act')}); el.classList.add('act'); onFilter(el.getAttribute('data-on-tab')); return; } }); // Repaired 2026-08-09. The handler that stood here cancelled the native submit, revealed // the #on-contact-done panel and fired the 'lead' conversion — while sending nothing at // all. The strict lead-v1 contract now owns this submit: form[data-sp-form] is bound by // the _FORM runtime, which POSTs to /api/adaptive/forms/submit and reveals // [data-sp-success] only once the server has answered ok. We record the conversion at // that point and not before. 'sp:submit-success' is dispatched without bubbles, so this // listens in the CAPTURE phase, which reaches document for any event. document.addEventListener('sp:submit-success',function(e){ var form=e.target; if(!form||form.id!=='on-contact-form') return; if(window.noetis&&window.noetis.track) window.noetis.track('lead'); },true); // Self-hosted background videos: force muted (SSR can drop the attribute) and // call play() — Safari reliably autoplays muted HTML5 video this way. function ffPlay(v){ try{ v.muted=true; v.setAttribute('muted',''); var p=v.play(); if(p&&p.catch)p.catch(function(){}); }catch(e){} } document.querySelectorAll('video[autoplay]').forEach(function(v){ ffPlay(v); v.addEventListener('canplay',function(){ffPlay(v)},{once:true}); if('IntersectionObserver' in window){ new IntersectionObserver(function(es){es.forEach(function(e){if(e.isIntersecting)ffPlay(e.target)})},{threshold:.1}).observe(v); } }); })();