Loading video...

Video Failed to Load

Go Home

COBE v2: reliably use any DOM elements as markers & arcs. CSS transition, animation, filter, interactivity, ...all just work. High perf, zero deps, still ~5KB. Coming soon.

225,256 views • 6 months ago •via X (Twitter)

37 Comments

Shu's profile picture
Shu6 months ago

It creatively uses CSS-native APIs, position-anchor and CSS variable. Here's how you style a label without any JS: Your marker automatically follows the anchored position on the 3D space. Use the `--cobe-visible-` prefixed variable to toggle between visible/invisible styles.

Shu's profile picture
Shu6 months ago

2 years ago I was working on the separated marker/arc layers. But I stopped there because there’s no great APIs to anchor DOM nodes reliably and declaratively. I really don’t want JS to be involved here like exposing {x,y,z}[] and have positioning a userland thing. It’s definitely going to have perf and frame-syncing issues in different frameworks. And users need to handle all the DOM layering and position: relative/fixed things. So I waited until the declarative CSS anchor positioning API gets wider adopted. It feels great!

Shu's profile picture
Shu6 months ago

And the conditional CSS trick. You can define the fallback value: .marker { opacity: 1; opacity: var(--cobe-visible-marker, 0); transition: opacity .3s ease; } And COBE will unset the variable when the marker is invisible (behind the globe) so final opacity fallbacks to 0. If visible, the variable is set to “invalid” and the CSS is equivalent to: .marker { opacity: 1; opacity: invalid; transition: opacity .3s ease; } So it shows as 1. Transitions all work. You can use this variable to toggle any CSS properties too including blur in the demo video.

Gonzalo Cordova's profile picture
Gonzalo Cordova6 months ago

clean! I posted my first design yesterday and just got humbled

Manu Arora's profile picture
Manu Arora6 months ago

youre the best

Kevin Okinedo's profile picture
Kevin Okinedo6 months ago

This is gorgeous, currently using v1 on and will be upgrading once available. Awesome work!

stonechat's profile picture
stonechat6 months ago

is there a marker limit?

Igor bedesqui's profile picture
Igor bedesqui6 months ago

@1weiho whaaaaaat, so cool

Andrew Gadzik ▲'s profile picture
Andrew Gadzik ▲6 months ago

@samko_cx We should chat 😂

Rajat's profile picture
Rajat6 months ago

im pretty sure AI can't recreate this kind of DX

Pablo Stanley's profile picture
Pablo Stanley6 months ago

DARK MAGIC

Asad Synt's profile picture
Asad Synt6 months ago

need it

rege's profile picture
rege6 months ago

This is soooo good! 🤏😎 🤏🕶️ 😲

Christo Ribeiro's profile picture
Christo Ribeiro6 months ago

This is beautiful 🤩

dom's profile picture
dom6 months ago

I ended up using this for a side project tool - very cool stuff. Thanks for sharing!

Jp 🦝's profile picture
Jp 🦝6 months ago

Literally started using it yesterday for a project—if you have an alpha or beta, I’m happy to give it a try 🙏

Evil Rabbit's profile picture
Evil Rabbit6 months ago

🤍

Michael Houghton 🐺's profile picture
Michael Houghton 🐺6 months ago

Man I need this on our maps these marker styles are dope and ffffaaast

Matt's profile picture
Matt6 months ago

this is so f beautiful bro ❤️🥰

Atif Saleem's profile picture
Atif Saleem6 months ago

It looks great and I got few ideas to adopt from it. I saw something similar at @Replit Agent 4 launch where @amasad prompted the agent to build.

Aleksej Petricig's profile picture
Aleksej Petricig6 months ago

That's the coolest animation and UI that I've ever seen! 🤩 Love it!

klöss's profile picture
klöss6 months ago

ohhhh I love this

Dan ⚡️'s profile picture
Dan ⚡️6 months ago

so pretty i can't stop watching this

Saïd Aitmbarek's profile picture
Saïd Aitmbarek6 months ago

looks insanely cool :)

Tino Fileccia's profile picture
Tino Fileccia6 months ago

What makes this better than the Three.JS CSS3DRenderer?

Arghya Das's profile picture
Arghya Das6 months ago

thank you, i need it

Fred Moon 🚀's profile picture
Fred Moon 🚀6 months ago

im in the deep for exactly this. can't wait for the release!

Nucleus☕️'s profile picture
Nucleus☕️6 months ago

very niceee

Armin's profile picture
Armin6 months ago

Sweet, I’m gonna use this. It’d be good to be able to tag lat and long as well, switch between spherical and flat views, and somehow integrate AI elements into it.

Wrennly's profile picture
Wrennly6 months ago

dom elements as compute targets is wild. did you find the dom update overhead dominates over the gpu work for 1m particles, or did you de...

DeafBuild's profile picture
DeafBuild6 months ago

😍

Siddharth Borderwala's profile picture
Siddharth Borderwala6 months ago

The demo video is so cool! You cooked with COBE 🔥

Harshal's profile picture
Harshal6 months ago

looks awesome!

Tonino Catapano (tonnoz)'s profile picture
Tonino Catapano (tonnoz)6 months ago

great work thank you!

Antonio Bonet's profile picture
Antonio Bonet6 months ago

Will it be possible to have this feature de​coupled in case we want to use it like on 2D maps or so?

Doug Lance's profile picture
Doug Lance6 months ago

do you need beta testers? 👀

seekvision's profile picture
seekvision6 months ago

nice

Related Videos

CSS in 2024 🤯 You can create a range slider with updating value tooltip and color changing track without using any JavaScript 🤯 ::-webkit-slider-thumb{ view-timeline: --thumb inline; } Scroll animation on the slider thumb that animates a number between the "min" and "max" of the range 😅 @​property --value { syntax: ' '; } @​keyframes sync { to { --value: 100; }} Tie that up to the contain animation-range ⚡️ .control { animation: sync both linear reverse; animation-timeline: --thumb; animation-range: contain; } Hoist the view timeline so the tooltip can use the value too! :root { timeline-scope: --thumb; } Then use it in the counter which goes in the tooltip 😇 .tooltip { counter-reset: val var(--value); } .tooltip::after { content: counter(val); } Then the accent color is based on the value too 🎨 [type=range] { accent-color: hsl(var(--value) 90% 65%); } The magic from the quoted post is using anchor positioning on the range thumb to position that tooltip 👏 Never thought of that when working on the spec for this API. This API lets you tether elements to other elements. Using the pseudo is a clever move! ::-webkit-slider-thumb { anchor-name: --thumb; } .tooltip { position: absolute; anchor-default: --thumb; left: anchor(50%); bottom: calc(anchor(top) + 25%); } The last piece is the little bounce transition... OK. I used a line or two of JavaScript for that 🙏😬 const updateDelta = ({ movementX }) => { document​.documentElement​.style.setProperty('--delta-x', movementX) } document.body.addEventListener('pointermove', updateDelta) But only so you can pass the movement delta to CSS and then reset the position with linear() to get that bouncy transition 😎 .hint { rotate: calc(clamp(-60, var(--delta-x) * -1, 60) * 1deg); transition: rotate 1s linear( 0, 0.2178 2.1%, 1.1144 8.49%, ... ); } Should probably do a video on this one. Lots of little tricks to break down with it for sure! 💯 As always, any questions, let me know! Also, this one only works in Chrome Canary with the Experimental Web Platform Features flag enabled ✅ This one almost feels like rocket science ha 🚀 CodePen.IO link below! 👇

jhey ʕ•ᴥ•ʔ

251,867 views • 2 years ago

CSS variables are live and they are POWERFUL. Now Live on Product Hunt 🚀 ➡️ Create a design system "So you can stay consistent and build much quicker." Define global styles like colors, gradients, sizes, and box shadows. ➡️ Use your variables everywhere "So you never have to manually enter a border color again." You're not limited to just sizes, colors, and font families. Use variables in gradients, box shadows, transforms, and more! ➡️ Start with libraries like Open Props, expertly crafted CSS variables "So you can use a tried and true system, and so we can standardize our Projects." Because there are no abstractions, you can use existing CSS variable libraries like Open Props, an expertly crafted library of CSS variables, and the recommended starting point in Webstudio. ➡️ Create complex micro-interactions "So when you hover a link, you can change any children's styles." CSS variables go beyond reusability! You can define variables anywhere in the navigator, such as on a link, and modify the variables on hover. Then, you can use those variables on the children to create complex micro-interactions! ➡️ Design and build simultaneously "So when deciding that perfect border color, you can arrow through all your options." Experimenting on the canvas just got a whole lot better. Now, you can arrow through your variables and see them rendered on the canvas to see which works best. ➡️ Change variable by breakpoint "So you can make the variables look great, no matter the screen size." CSS variables in Webstudio use the same UI as the rest of your styles, enabling breakpoints to work the same way. ✨ Building with design systems gives a HUGE boost in speed, consistency, and maintainability.

Webstudio

15,497 views • 1 year ago

CSS Tip! ✨ You can create these parallax effects and image cross-fades with scroll-driven animations 🤙 img { animation: fade; animation-timeline: view(); mix-blend-mode: plus-lighter } img:last-of-type { animation-direction: reverse; } @​keyframes fade { to { opacity: 0; }} This one's fun! 😁 The trick with the cross-fading image is to make use of one animation that runs at the same time on two images inside a container. You use the same animation, animation-timeline, and animation-range. But, you use animation-direction: reverse on one of the images so they go in the opposite direction 🫶 The use of mix-blend-mode: plus-lighter; produces a better cross-fade result 💯 A viewTimeline (view()) works because you know that both images are the same height. The range you can use is img { animation-timeline: view(); animation-range: cover 45% cover 55%; } That means when the image has covered 45% of the scrollport (In this case, the window), start the animation. And finish when it has covered 55% 🎬 How about the slight parallax? This is a trick with calc(). You know the top of the small image and the big image line up. And you can do this by absolutely placing the caption outside of the small image. The trick is to translate the small image by a distance so it lines up with the bottom of the big image. You can do that like this :root { --catch-up: calc( var(--big-height) - var(--small-height) ); } @​keyframes move { to { translate: 0 var(--catch-up); }} Then drive that animation with a scroll-driven animation using the container of both images as the driver 🤙 /* section contains both images */ section { view-timeline: --container; } .img-fader { animation: catch-up both linear; animation-timeline: --container; animation-range: 50vh calc(100vh + (var(--big-height) * 0.25)); } That's it! Scroll-driven image cross-fading and parallax effects without any JavaScript. This demo will work in all browsers as there is some JavaScript in place where the API isn't supported 🤙 To do that, it uses GSAP ScrollTrigger 🏆 As always, any questions, requests, etc. hit me up! 🤙 CodePen.IO link below 👇

jhey ʕ•ᴥ•ʔ

242,205 views • 2 years ago

CSS Tip! 🤯 You can create a CSS-only version of this balance slider using a scroll animation on the underlying input[type=range] 🚀 ::-webkit-slider-thumb { view-timeline: --thumb inline; } Scroll animation driven by the slider thumb animates a number between the "min" and "max" of the range 😅 @​property --value { inherits: true; initial-value: 0; syntax: ' '; } @​keyframes sync { to { --value: 100; }} Tie that up to the contain animation-range ⚡️ .control { animation: sync both linear reverse; animation-timeline: --thumb; animation-range: contain; } Hoist the view timeline so all the parts of the control can use it! .control { timeline-scope: --thumb; } Use that value in a counter which is used for the labels. Create a low and a high for each side 😇 .control__label { counter-reset: low var(--value) high calc(100 - var(--value)); } .control__label::before { content: "COFFEE " counter(low) "%"; } .control__label::after { content: counter(high) "% MILK"; } That's the magic of updating the label values ✨ For the big track, it's a fake track. You can make use of the same --value property and do some calc() to work out the width of each part. .control__track::before { width: calc(var(--value) * 1% - 0.5rem); background: var(--coffee); border-radius: 4px; transition: width 0.1s; } The width leaves a little gap for the indicator piece 🤙 The color calculation for --coffee isn't too wild but again you can use the same --value .control__track { --coffee: hsl(24 74% calc( 24% + (30% * ((100 - var(--value, 0)) / 100)) / 1 ) / 0.4); } Now for the last piece. Making the track change height. You could set up another custom property and animate its value using the --thumb timeline too 🔥 @​property --shift { initial-value: 0; inherits: true; syntax: ' '; } @​keyframes shift { 0%, 31%, 61%, 100% { --shift: 0; } 32%, 60% { --shift: 1; } } Then use that --shift to update the translation of the label and height of the track 🤓 .label { transform: translateY(calc(var(--shift) * 50%)); transition: transform var(--speed) var(--timing); } Cool part here is that you can use the control to work out the @​keyframes percentages 😅 Oh. And the timing for that little bounce? Use the linear() function 😎 :root { --timing: linear( 0, 0.5007 7.21%, 0.7803 12.29%, 0.8883 14.93%, 0.9724 17.63%, 1.0343 20.44%, 1.0754 23.44%, 1.0898 25.22%, 1.0984 27.11%, 1.1014 29.15%, 1.0989 31.4%, 1.0854 35.23%, 1.0196 48.86%, 1.0043 54.06%, 0.9956 59.6%, 0.9925 68.11%, 1 ); } Should probably do a video on this one. Lots of little custom property tricks for sure! 💯 It's not too far off the range slider with the tooltip that came up previously As always, any questions, let me know! Also, this one only works in Chrome currently ✅🥲 This one's a bit rocket science ha 🚀 CodePen.IO link below! 👇

jhey ʕ•ᴥ•ʔ

377,871 views • 2 years ago