Add 3d Viewport component
Implement a Viewport component and associated update script that allows rendering 3d content inside it. This is based on the implementation used at Furnavia for their 2025 website.
This commit is contained in:
parent
c8527f17f7
commit
49a329ac43
4 changed files with 47 additions and 0 deletions
|
@ -10,6 +10,7 @@ export default function BasePage(props: BaseProps) {
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>{props.title}</title>
|
<title>{props.title}</title>
|
||||||
<link rel="stylesheet" href="/style.css" />
|
<link rel="stylesheet" href="/style.css" />
|
||||||
|
<script type="module" defer="" src="viewport.js" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header class="header">
|
<header class="header">
|
||||||
|
|
12
src/components/Viewport.tsx
Normal file
12
src/components/Viewport.tsx
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
/**
|
||||||
|
3d Viewport
|
||||||
|
*/
|
||||||
|
export default function Viewport(
|
||||||
|
props: {
|
||||||
|
children: unknown,
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
return <div class="viewport in3d">
|
||||||
|
{ props.children }
|
||||||
|
</div>
|
||||||
|
}
|
|
@ -64,6 +64,19 @@ ol, ul {
|
||||||
padding-inline-start: 1.25em;
|
padding-inline-start: 1.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 3d viewport */
|
||||||
|
.in3d {
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
}
|
||||||
|
.viewport {
|
||||||
|
pointer-events: none;
|
||||||
|
perspective: 300vmax;
|
||||||
|
perspective-origin: 50% var(--y-offset);
|
||||||
|
}
|
||||||
|
.viewport * {
|
||||||
|
pointer-events: initial;
|
||||||
|
}
|
||||||
|
|
||||||
/* Base Page Layout */
|
/* Base Page Layout */
|
||||||
body {
|
body {
|
||||||
max-width: 50rem;
|
max-width: 50rem;
|
||||||
|
|
21
web/viewport.js
Normal file
21
web/viewport.js
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
function setViewportOffset(viewport) {
|
||||||
|
// Calculate the distance from the top of the element to the center of the screen.
|
||||||
|
// This is an accurate rendering, but we might want to change it for artistic effects.
|
||||||
|
const windowHeight = window.innerHeight;
|
||||||
|
const rect = viewport.getBoundingClientRect();
|
||||||
|
if (rect.top > windowHeight || rect.bottom < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const yOffset = windowHeight / 2 - rect.top;
|
||||||
|
viewport.style.setProperty('--y-offset', yOffset+"px");
|
||||||
|
}
|
||||||
|
|
||||||
|
const viewports = document.querySelectorAll(".viewport");
|
||||||
|
function updateViewports() {
|
||||||
|
for (const viewport of viewports) {
|
||||||
|
setViewportOffset(viewport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
window.addEventListener("scroll", updateViewports, { passive: true });
|
||||||
|
window.addEventListener("resize", updateViewports, { passive: true });
|
||||||
|
updateViewports();
|
Loading…
Add table
Add a link
Reference in a new issue