Skip to content

Instantly share code, notes, and snippets.

@toabr
Created November 12, 2021 11:27
Show Gist options
  • Save toabr/acadbf2cfb24fb1ab25e770d1d630ad9 to your computer and use it in GitHub Desktop.
Save toabr/acadbf2cfb24fb1ab25e770d1d630ad9 to your computer and use it in GitHub Desktop.
CSS Cube Study
//- BUILDING BLOX -----------------------------
mixin box(className, attr)
.box(class=className data-name=className)&attributes(attributes)= attr
- const faces = ['front','back','left','right','top','bottom']
each face in faces
div(class='face face__' + face)
block
mixin scene(className)
.scene(class=className data-name=className)
block
//- SCENE ELEMENTS ----------------------------
.stage
+scene("base")
+box("parent")
+box("child")
const win = window
const root = document.documentElement
/*
* throttle events
*/
function throttle(fn, delay) {
let allowSample = true;
return function (e) {
if (allowSample) {
allowSample = false;
setTimeout(() => { allowSample = true; }, delay);
fn(e);
}
}
}
/*
* mouse move
*/
window.onmousemove = throttle(mouseMoveHandler, 100)
function mouseMoveHandler(e) {
const clientX = Math.round(e.clientX / (root.clientWidth / 100))/100
const clientY = Math.round(e.clientY / (root.clientHeight / 100))/100
root.style.setProperty("--client-x", clientX)
root.style.setProperty("--client-y", clientY)
}
/*
* Purely for debugging
*/
const {
dat: { GUI },
} = window
const CONTROLLER = new GUI()
const CONFIG = {
'zoom': 2,
'global-x': 70,
'global-y': 0,
'global-z': 30,
'parallax-x': 0,
'parallax-z': 0,
'face-opacity': 1,
'checker': true,
'labels': true,
'wireframe': true,
}
const UPDATE = () => {
Object.entries(CONFIG).forEach(([key, value]) => {
document.documentElement.style.setProperty(`--${key}`, value)
})
document.documentElement.setAttribute('checker', CONFIG.checker ? true : false)
document.documentElement.setAttribute('labels', CONFIG.labels ? true : false)
document.documentElement.setAttribute('wireframe', CONFIG.wireframe ? true : false)
}
const STAGE_FOLDER = CONTROLLER.addFolder('Stage')
STAGE_FOLDER.add(CONFIG, 'zoom', 0, 5, 0.1)
.name('Zoom')
.onChange(UPDATE)
STAGE_FOLDER.add(CONFIG, 'global-x', 0, 180, 1)
.name('Global X (deg)')
.onChange(UPDATE)
STAGE_FOLDER.add(CONFIG, 'global-y', 0, 180, 1)
.name('Global Y (deg)')
.onChange(UPDATE)
STAGE_FOLDER.add(CONFIG, 'global-z', 0, 180, 1)
.name('Global Z (deg)')
.onChange(UPDATE)
STAGE_FOLDER.add(CONFIG, 'parallax-x', 0, 180, 1)
.name('Parallax X')
.onChange(UPDATE)
STAGE_FOLDER.add(CONFIG, 'parallax-z', 0, 180, 1)
.name('Parallax Z')
.onChange(UPDATE)
STAGE_FOLDER.add(CONFIG, 'face-opacity', 0, 1, 0.1)
.name('Face Opacity')
.onChange(UPDATE)
STAGE_FOLDER.add(CONFIG, 'checker')
.name('Checker Texture')
.onChange(UPDATE)
STAGE_FOLDER.add(CONFIG, 'labels')
.name('Labels')
.onChange(UPDATE)
STAGE_FOLDER.add(CONFIG, 'wireframe')
.name('Wireframe')
.onChange(UPDATE)
UPDATE()
STAGE_FOLDER.open()
//CONTROLLER.close()
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.min.js"></script>
:root
--unit calc(var(--zoom, 1) * var(--factor, 1vmin))
*
margin 0
padding 0
box-sizing border-box
html, body
min-height 100%
display flex
align-items center
justify-content center
.stage
min-width 1px
min-height 1px
&, *, *::after, *::before
margin 0
padding 0
box-sizing border-box
transform-style preserve-3d
--distort-x calc(var(--client-y, 0.5) * var(--parallax-x) - var(--parallax-x) / 2)
--distort-z calc(var(--client-x, 0.5) * var(--parallax-z) - var(--parallax-z) / 2)
perspective calc(var(--perspective, 10000) * var(--unit))
transform \
rotateX(calc(var(--global-x, 60) * 1deg + var(--distort-x) * 1deg)) \
rotateY(calc(var(--global-y, 0) * 1deg)) \
rotateZ(calc(var(--global-z, 35) * 1deg + var(--distort-z) * 1deg)) \
.scene
--x 0
--y 0
--z 0
--width 25
--height 10 // box default
--depth 25
--rotate-x 0
--rotate-y 0
--rotate-z 0
width calc(var(--width, 25)*var(--unit))
height calc(var(--depth, 25)*var(--unit))
position absolute
top 50%
left 50%
transform-style preserve-3d
transform-origin 50% 50%
transform translate(-50%, -50%) \
translate3d( \
calc(var(--x, 0) * var(--unit)), \
calc(var(--y, 0) * var(--unit)), \
calc(var(--z, 0) * var(--unit))) \
rotateX(calc(var(--rotate-x, 0)*1deg)) \
rotateY(calc(var(--rotate-y, 0)*1deg)) \
rotateZ(calc(var(--rotate-z, 0)*1deg)) \
faceFront()
height calc(var(--height) * var(--unit))
width 100%
transform-origin 50% 50%
transform translate(-50%, -50%) \
rotateX(-90deg) \
translate3d(0, 0, calc((var(--depth) / 2) * var(--unit)))
faceBack()
height calc(var(--height) * var(--unit))
width 100%
transform-origin 50% 50%
transform translate(-50%, -50%) \
rotateX(-90deg) \
rotateY(180deg) \
translate3d(0, 0, calc((var(--depth) / 2) * var(--unit)))
faceRight()
height calc(var(--height) * var(--unit))
width calc(var(--depth) * var(--unit))
transform translate(-50%, -50%) \
rotateX(-90deg) \
rotateY(90deg) \
translate3d(0, 0, calc((var(--width) / 2) * var(--unit)))
faceLeft()
height calc(var(--height) * var(--unit))
width calc(var(--depth) * var(--unit))
transform translate(-50%, -50%) \
rotateX(-90deg) \
rotateY(-90deg) translate3d(0, 0, calc((var(--width) / 2) * var(--unit)))
faceTop()
height calc(var(--depth) * var(--unit))
width calc(var(--width) * var(--unit))
transform translate(-50%, -50%) \
translate3d(0, 0, calc((var(--height) / 2) * var(--unit)))
faceBottom()
height calc(var(--depth) * var(--unit))
width calc(var(--width) * var(--unit))
transform translate(-50%, -50%) \
translate3d(0, 0, calc((var(--height) / 2) * -1 * var(--unit))) \
rotateX(180deg)
buildBox()
--color-front var(--color-light, #f4e8d6)
--color-back var(--color-darker, #e0bd8b)
--color-left var(--color-base, #f1e1ca)
--color-right var(--color-base, #f1e1ca)
--color-top var(--color-dark, #ead1ae)
--color-bottom var(--color-darker, #e0bd8b)
.face__front
faceFront()
background-color var(--color-front)
.face__back
faceBack()
background-color var(--color-back)
.face__left
faceLeft()
background-color var(--color-left)
.face__right
faceRight()
background-color var(--color-right)
.face__top
faceTop()
background-color var(--color-top)
.face__bottom
faceBottom()
background-color var(--color-bottom)
[class^=face]
position absolute
top 50%
left 50%
.box
--x 0
--y 0
--z 0
--rotate-x 0
--rotate-y 0
--rotate-z 0
buildBox()
margin 0
padding 0
box-sizing border-box
transform-style preserve-3d
position absolute
width calc(var(--width, 10) * var(--unit))
height calc(var(--depth, 10) * var(--unit))
transform \
translate3d( \
calc(var(--x, 0) * var(--unit)), \
calc(var(--y, 0) * var(--unit)), \
calc(var(--z, 0) * var(--unit))) \
rotateX(calc(var(--rotate-x, 0) * 1deg)) \
rotateY(calc(var(--rotate-y, 0) * 1deg)) \
rotateZ(calc(var(--rotate-z, 0) * 1deg))
// ===============================================
// Helper
// ===============================================
// transparent box for positioning
.box.transparent > [class^=face]
background none
pointer-events none
coloring(colorBase = rgba(241, 225, 202, 1))
--color-base colorBase
--color-light lighten(colorBase, 23%)
--color-dark darken(colorBase, 8%)
--color-darker darken(colorBase, 18%)
z-start = calc(var(--height) / 2)
z-end = calc(var(--height) / -2)
// ===============================================
// DEBUG
// ===============================================
.box > [class^=face]
opacity var(--face-opacity)
[labels=true]
.dg.ac
z-index 99999
body
overflow scroll
.scene
background-color hsla(200, 80%, 50%, 0.5)
.box
background-color hsla(305, 80%, 50%, 0.5)
.scene::after,
.box::after
content attr(data-name)
position absolute
padding 1rem
font-weight bold
font-family monospace
color hsla(305, 80%, 100%, 0.8)
.box::after
top 50%
left 50%
transform translate(-50%, -50%)
.box [class^=face]
background-color transparent
background-image none
[wireframe=true]
[class^=face]
border 1px solid rgb(0, 0, 0)
.box .box [class^=face]
border-color rgb(0, 0, 255)
.box .box .box [class^=face]
border-color rgb(0, 255, 255)
[checker=true]
[class^=face]
background-image embedurl("https://us.v-cdn.net/5021068/uploads/editor/ha/7frj09nru4zu.png")
background-size calc(var(--unit)*8)
// ===============================================
// SCENE
// ===============================================
.parent
--width 15
--height 10
--depth 15
--x 5
--y 5
--z 5
.child
--width 5
--depth 5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment