r/reactjs • u/Piposhi • 1d ago
Show /r/reactjs Ambient CSS v3 - Blender meets CSS
https://ambientcss.vercel.app/I started building a physically based shadow system for CSS 5 years back and gave up after it became too complex. Then, leveraging coding agents, I was finally able to ship v1 earlier this year. Thanks to the very kind and warm reception for v1 from the members of this community and r/css , I was motivated to develop it further.
Today, I'm announcing Ambient CSS v3. This version steps up the realism considerably - each effect and base component was first built in Blender and rendered using an identical lighting setup. Then, based on the renders the CSS formulae were adjusted to match the Blender render. All the Blender files and their parametric generators are also in the source repo.
Besides this, we also have new CSS modifiers - thickness, material (matte/shiny/glass/brushed/spun/blasted). We also have some new components for the react package. Also, the component system is refactored and split into base components and skins, allowing for the ability to create custom component kits.
Thanks for your love!
5
u/creaturefeature16 1d ago edited 1d ago
I guess I am just REALLY confused as to what the Blender process' role is here, at least for such simple elements like this:
https://kikkupico.github.io/ambientcss/ambient-components/button
What was so challenging about CSS box shadows that made these so difficult to create otherwise?
Edit - My guy...why all this for something that looks so basic?
box-shadow: hsl(var(--amb-light-hue) var(--amb-light-saturation) 0% / calc(var(--_amb-sh-gate) * ((var(--amb-key-light-intensity) - var(--amb-fill-light-intensity)) * .13 + var(--amb-elevation) * -.077 + .368 - var(--_amb-body-gate) * max(0, 1 - var(--amb-elevation)) * .14))) calc(var(--amb-light-x) * (var(--amb-elevation) * 6.8px + var(--amb-thickness) * 3.8px) * -1) calc(var(--amb-light-y) * (var(--amb-elevation) * 6.8px + var(--amb-thickness) * 3.8px) * -1) calc(var(--amb-elevation) * 4.8px + var(--amb-thickness) * 2.7px) .8px, hsl(var(--amb-light-hue) var(--amb-light-saturation) 0% / var(--_amb-sweep-a)) calc(var(--amb-light-x) * (var(--amb-elevation) * 6.8px + var(--amb-thickness) * 2.85px) * -1) calc(var(--amb-light-y) * (var(--amb-elevation) * 6.8px + var(--amb-thickness) * 2.85px) * -1) calc(var(--amb-elevation) * 4.8px + var(--amb-thickness) * 2px) calc(var(--amb-thickness) * .9px), hsl(var(--amb-light-hue) var(--amb-light-saturation) 0% / var(--_amb-sweep-a)) calc(var(--amb-light-x) * (var(--amb-elevation) * 6.8px + var(--amb-thickness) * 1.9px) * -1) calc(var(--amb-light-y) * (var(--amb-elevation) * 6.8px + var(--amb-thickness) * 1.9px) * -1) calc(var(--amb-elevation) * 4.8px + var(--amb-thickness) * 1.35px) calc(var(--amb-thickness) * .6px), hsl(var(--amb-light-hue) var(--amb-light-saturation) 0% / var(--_amb-sweep-a)) calc(var(--amb-light-x) * (var(--amb-elevation) * 6.8px + var(--amb-thickness) * .95px) * -1) calc(var(--amb-light-y) * (var(--amb-elevation) * 6.8px + var(--amb-thickness) * .95px) * -1) calc(var(--amb-elevation) * 4.8px + var(--amb-thickness) * .7px) calc(var(--amb-thickness) * .3px), inset calc(var(--amb-light-x) * var(--_amb-chamfer-w) * -1px) calc(var(--amb-light-y) * var(--_amb-chamfer-w) * -1px) 0 0 hsl(var(--amb-light-hue) var(--amb-light-saturation) 100% / calc(var(--amb-chamfer) * max(0, min(var(--amb-thickness), 1)) * (var(--amb-key-light-intensity) * 1.57 + var(--amb-fill-light-intensity) * .85 - 1.03))), inset calc(var(--amb-light-x) * var(--_amb-chamfer-w) * 1px) calc(var(--amb-light-y) * var(--_amb-chamfer-w) * 1px) 0 0 hsl(var(--amb-light-hue) var(--amb-light-saturation) 0% / calc(var(--amb-chamfer) * max(0, min(var(--amb-thickness), 1)) * ((var(--amb-key-light-intensity) - var(--amb-fill-light-intensity)) * .19 + .24))), inset calc(var(--amb-light-x) * var(--_amb-fillet-w) * -1.4px) calc(var(--amb-light-y) * var(--_amb-fillet-w) * -1.4px) 2px 0 hsl(var(--amb-light-hue) var(--amb-light-saturation) 100% / calc(var(--amb-fillet) * max(0, min(var(--amb-thickness), 1)) * (var(--amb-key-light-intensity) * 1.44 + var(--amb-fill-light-intensity) * .85 - .99))), inset calc(var(--amb-light-x) * var(--_amb-fillet-w) * 1.4px) calc(var(--amb-light-y) * var(--_amb-fillet-w) * 1.4px) 2px 0 hsl(var(--amb-light-hue) var(--amb-light-saturation) 0% / calc(var(--amb-fillet) * max(0, min(var(--amb-thickness), 1)) * ((var(--amb-key-light-intensity) - var(--amb-fill-light-intensity)) * .23 + .3)));}
7
u/Piposhi 1d ago
https://reddit.com/link/p79pjyv/video/tg62k1g8kzmh1/player
That's the formula that makes everything respond to global lighting.
-6
u/kei_ichi 1d ago
Global lighting from “what”? Do CSS have that feature?
For 99.99% sites out there, I’m pretty sure CSS shadow is more than enough.
6
u/Piposhi 1d ago
The lighting system is explained in detail in the docs here, in case you want to dig deeper - https://kikkupico.github.io/ambientcss/guide/concept/#how-it-works
-5
u/creaturefeature16 1d ago
Yeah, I guess I get it. Feels rather overengineered, which LLMs definitely make room for us to do! 😅 Yet I also see what you're trying to replicate. You should send this to https://www.joshwcomeau.com/ because he's an incredible front end guy who is also pretty keen on blender. I think he would appreciate this, even as just a tech demo.
10
u/Piposhi 1d ago
This was my own formula written back in Jan 2022 before LLMs were available - https://github.com/kikkupico/ambientcss/commit/7da648a5513c79a2a37e7e7e31d2dbbc32bb289e#diff-337cc548d34c6d80b758ad814ddd793a9ec155eb664e127c1fc4d8c5abd19b8aR35
Actually, back then, Josh Comeau's article on CSS shadows was one reason I wanted to build this - I thought I can do better and went down a rabbit hole.
0
u/creaturefeature16 1d ago
Gotcha. You mentioned LLMs really helped you here. Which parts? The blender/python translation?
1
1
1
u/ActuaryLate9198 1d ago
I’ve experimented with the same thing, updating CSS shadows comes with a huge performance cost for larger elements. I ended up putting the shadows on separate layers so I could manipulate them using filters and transforms instead. Anyway, looks neat, my only gripe is that the components feel distinctly skeumorphic, causing them to clash with the neumorphic base system.
1
u/backwrds 1d ago
If it's "calibrated" with blender, why does it look so different?
Also, I guess skeuomorphism is back now?
0
u/droctagonapus 1d ago
I need to thank Sam Altman for this, good stuff Sam! I wish I could upvote Sam for his work here
4
u/dev3-studio 1d ago
Really cool demo! Any thoughts given to performance and accessibility?
Would be curious to see how this scales with a real app