Onze diensten

Brand_Identity

Het fundament voor autoriteit — een merk dat domineert, niet decoreert.vanaf €2.500

Brand Identity

Een scherp merk is geen decoratie, het is je grootste concurrentievoordeel. We leggen een fundament dat direct professioneel oogt en consistent blijft over elk kanaal.

Wat we doen:

We bepalen je positionering ten opzichte van de concurrentie, ontwerpen een complete visuele identiteit — een nieuw logo, kleurenpalet en typografie — en vatten alles samen in een praktisch merkhandboek.

Het resultaat is een professionele uitstraling die vanaf de eerste indruk vertrouwen wekt.

✓Scherpe positionering — Onderscheid bepalen van de concurrentie.
✓High-end visuals — Compleet nieuw logo, kleurenpalet en typografie.
✓Brand guide — Praktisch handboek voor merkconsistentie.
✓Directe impact — Professionele uitstraling die vertrouwen wekt.
Brand Identity 1
Brand Identity 2

Laten we samenwerken

Neem contact op om je project te bespreken — we bouwen merken die domineren, niet decoreren.

Studio

Naam

E-mailadres

Telefoonnummer

Budget

Bedankt — we reageren binnen één werkdag.

Er ging iets mis. Probeer het opnieuw.

(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); } }); })();