Tekst op een draaiende cilinder New
A sentence wraps around a cylinder that turns slowly on its axis, like a barber pole: the front is crisp, the back shows through mirrored. Drag or swipe to spin it, arrow keys turn it step by step, with a pause button. For the hero of a hairdresser or barber, a rotating offer or a brand name in a header.
Barbier Yusuf in Tilburg: knippen, baard trimmen en scheren
Loop binnen zonder afspraak, dinsdag tot en met zaterdag.
How to use it
- Paste the HTML where the text animations should appear.
- Add the CSS to your stylesheet. All classes are prefixed, so nothing clashes with your own styles.
- Add the JavaScript and call init() with the element that contains the HTML.
<!-- Tekst op een draaiende cilinder · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie -->
<div class="jouw-container">
<div class="t7c">
<h3 class="t7c__sr">Barbier Yusuf in Tilburg: knippen, baard trimmen en scheren</h3>
<div class="t7c__scene" tabindex="0" aria-label="Draaiende tekst, pijltjes links en rechts draaien de cilinder"><div class="t7c__drum" aria-hidden="true"></div><div class="t7c__ring" aria-hidden="true" data-text="knippen · baard trimmen · scheren · Barbier Yusuf · Tilburg · "></div></div>
<div class="t7c__foot"><p class="t7c__p">Loop binnen zonder afspraak, dinsdag tot en met zaterdag.</p><button class="t7c__btn" type="button" aria-pressed="false">Pauze</button></div>
</div>
</div>/* Tekst op een draaiende cilinder · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie */
.t7c{position:absolute;inset:0;display:flex;flex-direction:column;justify-content:center;gap:14px;padding:12px 18px;container-type:size;font-family:'Switzer',sans-serif;box-sizing:border-box}
.t7c__sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;margin:0}
.t7c__scene{position:relative;height:46cqh;perspective:900px;display:flex;align-items:center;justify-content:center;cursor:grab;touch-action:pan-y;border-radius:4px;outline:none}
.t7c__scene:focus-visible{outline:2px solid #F5480F;outline-offset:2px}
.t7c__drum{position:absolute;top:50%;left:50%;height:64%;transform:translate(-50%,-50%);border-radius:4px;background:linear-gradient(90deg,#d9d6d1 0%,#f7f6f4 34%,#ffffff 46%,#ebe9e5 70%,#c9c5bf 100%)}
.t7c__ring{position:relative;width:0;height:0;transform-style:preserve-3d}
.t7c__ch{position:absolute;left:0;top:0;font-weight:800;line-height:1;color:#0a0a0a;white-space:pre;backface-visibility:visible}
.t7c__ch.is-dot{color:#F5480F}
.t7c__foot{display:flex;align-items:center;justify-content:space-between;gap:12px}
.t7c__p{margin:0;font-size:clamp(12px,3.2cqi,14px);line-height:1.4;color:#3a3a3a}
.t7c__btn{flex:none;min-height:30px;min-width:64px;padding:6px 10px;border:1px solid #0a0a0a;border-radius:4px;background:#fff;color:#0a0a0a;font:600 13px/1.2 'Switzer',sans-serif;cursor:pointer;transition:background-color .16s,color .16s}
.t7c__btn:hover{background:#0a0a0a;color:#fff}
.t7c__btn:focus-visible{outline:2px solid #F5480F;outline-offset:2px}// Tekst op een draaiende cilinder · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie
// root = het element waarin de HTML staat
function init(root){
var w=root.querySelector('.t7c'),scene=w.querySelector('.t7c__scene'),ring=w.querySelector('.t7c__ring'),drum=w.querySelector('.t7c__drum'),btn=w.querySelector('.t7c__btn'),txt=ring.dataset.text;
var C=txt.split('').map(function(ch){var s=document.createElement('span');s.className='t7c__ch'+(ch==='·'?' is-dot':'');s.textContent=ch;ring.appendChild(s);return {el:s,ang:0,wd:0};});
var R=100,rot=0,vel=0,auto=-14,run=true,vis=true,raf=0,last=0,drag=null,reduce=matchMedia('(prefers-reduced-motion: reduce)').matches;
function layout(){var W=scene.clientWidth,Hh=scene.clientHeight;R=Math.min(W*.36,190);var fs=40;C.forEach(function(c){c.el.style.transform='none';c.el.style.fontSize=fs+'px';});var tot=0;C.forEach(function(c){c.wd=c.el.getBoundingClientRect().width||fs*.5;tot+=c.wd;});
var scale=(2*Math.PI*R)/tot;fs=Math.max(12,Math.min(Hh*.42,fs*scale));C.forEach(function(c){c.el.style.fontSize=fs.toFixed(1)+'px';});tot=0;C.forEach(function(c){c.wd=c.el.getBoundingClientRect().width||fs*.5;tot+=c.wd;});
var acc=0;C.forEach(function(c){var mid=acc+c.wd/2;c.ang=mid/tot*360;acc+=c.wd;c.el.style.marginLeft=(-c.wd/2).toFixed(1)+'px';c.el.style.marginTop=(-fs/2).toFixed(1)+'px';c.el.style.transform='rotateY('+c.ang.toFixed(2)+'deg) translateZ('+R.toFixed(1)+'px)';});
drum.style.width=(2*R).toFixed(0)+'px';drum.style.height=(fs*1.5).toFixed(0)+'px';draw();}
function draw(){ring.style.transform='rotateY('+rot.toFixed(2)+'deg)';C.forEach(function(c){var a=(c.ang+rot)*Math.PI/180,f=Math.cos(a);c.el.style.opacity=(f>0?.2+.8*f*f:.05+.05*(1+f)).toFixed(3);});}
function loop(now){raf=0;var dt=last?Math.min(.05,(now-last)/1000):.016;last=now;if(!drag){vel+=((run?auto:0)-vel)*.03;rot+=vel*dt;}draw();if(w.isConnected&&vis&&(run||Math.abs(vel)>.5||drag))raf=requestAnimationFrame(loop);}
function start(){if(!raf&&vis){last=0;raf=requestAnimationFrame(loop);}}
scene.addEventListener('pointerdown',function(e){drag={x:e.clientX,t:performance.now(),id:e.pointerId};try{scene.setPointerCapture(e.pointerId);}catch(_){}scene.style.cursor='grabbing';start();});
scene.addEventListener('pointermove',function(e){if(!drag||drag.id!==e.pointerId)return;var dx=e.clientX-drag.x,now=performance.now(),dd=dx/R*57.3;rot+=dd;vel=dd/Math.max(.008,(now-drag.t)/1000);vel=Math.max(-600,Math.min(600,vel));drag.x=e.clientX;drag.t=now;draw();});
function end(){if(!drag)return;drag=null;scene.style.cursor='';if(reduce)vel=0;start();}
scene.addEventListener('pointerup',end);scene.addEventListener('pointercancel',end);
scene.addEventListener('keydown',function(e){if(e.key!=='ArrowLeft'&&e.key!=='ArrowRight')return;e.preventDefault();rot+=e.key==='ArrowLeft'?-20:20;draw();});
btn.addEventListener('click',function(){run=!run;btn.setAttribute('aria-pressed',String(!run));btn.textContent=run?'Pauze':'Draaien';if(run)start();});
if(reduce){run=false;btn.setAttribute('aria-pressed','true');btn.textContent='Draaien';}
rot=-8;layout();if('ResizeObserver' in window)new ResizeObserver(layout).observe(scene);if(document.fonts&&document.fonts.ready)document.fonts.ready.then(layout);
if('IntersectionObserver' in window)new IntersectionObserver(function(en){vis=en[0].isIntersecting;if(vis&&run)start();}).observe(w);else start();
}
init(document.querySelector('.jouw-container'));
More text animations
Seen something you like?
Add it to your selection and send it over. We build your site around it, in your brand.
Get in touch →