<script type="module" src="https://ajax.googleapis.com/ajax/libs/model-viewer/3.1.1/model-viewer.min.js"></script>
<header>
Demo for <a href="https://brm.us/scroll-driven-3d" target="_top">https://brm.us/scroll-driven-3d</a>
</header>
<model-viewer
alt="Nike Air Max 90"
src="https://assets.codepen.io/89905/nike_air_max_90.glb"
></model-viewer>
<footer>
<p>3D Model <a href="https://skfb.ly/ou8Yp" target="_top">“Nike Air Max 90”</a> by StudioAira! – <a href="http://creativecommons.org/licenses/by-nc/4.0/" target="_top">CC BY-NC 4.0</a>.</p>
</footer>
<div class="warning">
<p>⚠️ Your browser does not support Scroll-driven Animations. Please use Chrome 115 or newer.</p>
</div>
@keyframes foo {
to {
scale: 1;
}
}
model-viewer {
display: block;
width: 100%;
height: 95vh;
position: fixed;
animation: foo linear both;
animation-timeline: scroll(block root);
}
model-viewer::part(default-progress-bar) {
display: none;
}
header,
footer {
position: fixed;
left: 0;
right: 0;
text-align: center;
font-style: italic;
}
header {
top: 1em;
}
footer {
bottom: 0;
}
html {
height: 400vh;
}
body {
font-family: helvetica;
}
@layer warning {
.warning {
box-sizing: border-box;
padding: 1em;
margin: 1em 0;
border: 1px solid #ccc;
background: rgba(255 255 205 / 0.8);
position: fixed;
top: 40vh;
font-size: 2em;
left: 1em;
right: 1em;
max-width: 80ch;
margin: 0 auto;
z-index: 1000;
}
.warning > :first-child {
margin-top: 0;
}
.warning > :last-child {
margin-bottom: 0;
}
.warning a {
color: blue;
}
.warning--info {
border: 1px solid #123456;
background: rgb(205 230 255 / 0.8);
}
.warning--alarm {
border: 1px solid red;
background: #ff000010;
}
@supports (animation-timeline: view()) {
.warning:not([data-bug]) {
display: none;
}
}
@supports (animation-range: 0vh 90vh) {
.warning[data-bug="1427062"] {
display: none;
}
}
}
const trackAnimationProgress = (animation, cb, precision = 5) => {
let progress = 0;
const updateValue = () => {
if (animation && animation.currentTime) {
let newProgress = animation.effect.getComputedTiming().progress * 1;
if (animation.playState === "finished") newProgress = 1;
newProgress = Math.max(0.0, Math.min(1.0, newProgress)).toFixed(precision);
if (newProgress != progress) {
progress = newProgress;
cb(progress);
}
}
requestAnimationFrame(updateValue);
};
requestAnimationFrame(updateValue);
}
const model = document.querySelector("model-viewer");
trackAnimationProgress(model.getAnimations()[0], (progress) => {
model.orientation = `0deg 0deg ${progress * -360}deg`;
});
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.