Add custom Three.js objects to any of three named placement groups — world space, scroll space, or fixed space — each with its own coordinate system and scroll behaviour.
When Fold.page initialises it exposes three groups through its
JavaScript API. You access them in the onReady callback
and add ordinary Three.js objects to whichever group fits.
Fold.init({
foldpage: true,
onReady: function () {
var THREE = Fold.getThree();
var state = Fold.getThreeState(); // { scene, camera, renderer, … }
var scrollGrp = Fold.getGroupScroll(); // moves with page scroll
var fixedGrp = Fold.getGroupFixed(); // stays anchored to viewport
var px = Fold.getPixelSize(); // 1 CSS px → world units
var vp = Fold.getViewportSize();// { width, height } in world units
}
});
Fold.getPixelSize(n) converts CSS pixel values to
Three.js world units using the same global scale factor the rest of
Fold uses (pixelSizeDefault = 0.0007). Call it with no
argument to get the raw scale factor, or pass a number to convert it
directly: Fold.getPixelSize(40) → 40 * 0.0007.
Objects added to state.scene live in raw Three.js world
coordinates. They are never repositioned by Fold's scroll or XR
origin systems, making them ideal for environment geometry, floor
planes, and ambient lighting that should feel permanently anchored in
the physical world.
world [0, 0.7, −0.35]
(driven by originOffsetScreen).Y = 0 ≈ bottom of the first viewport — floor level.Y = 0 = the physical floor where the user stands.
In this demo a fading grid and a pink cone are placed in world space. Scroll the page — they stay exactly where they are.
var state = Fold.getThreeState();
// Fading grid floor
var grid = new THREE.GridHelper(40, 40);
state.scene.add(grid);
// Cone pinned at a fixed world position
var cone = new THREE.Mesh(
new THREE.ConeGeometry(Fold.getPixelSize(14), Fold.getPixelSize(28), 32),
new THREE.MeshStandardMaterial({ color: 'hotpink' })
);
cone.position.set(0, 0.7, -0.2);
state.scene.add(cone);
Objects added to Fold.getGroupScroll() share the same
space as the rendered HTML content. The group translates with the page
scroll, so positions are expressed relative to the top-left corner
of the page.
0, 0, 0)x → rightward (positive = right)y → upward (negate CSS px: 40 px down = y = −40 * px)z → toward the viewer (positive = closer)
Use Fold.getViewportSize() to get viewport dimensions in
world units for centre, right-edge, or bottom-edge alignment, and
re-call it on resize to keep objects correctly placed as
the window changes.
var scrollGroup = Fold.getGroupScroll();
var px = Fold.getPixelSize();
// 40 px right, 40 px down from the page origin
var box = new THREE.Mesh(
new THREE.BoxGeometry(
Fold.getPixelSize(40), Fold.getPixelSize(40), Fold.getPixelSize(40)
),
new THREE.MeshStandardMaterial({ color: 'lightgreen' })
);
box.position.set(40 * px, -40 * px, 0);
scrollGroup.add(box);
// Horizontally centred, 160 px from the top — re-positions on resize
var sphere = new THREE.Mesh(
new THREE.SphereGeometry(Fold.getPixelSize(28), 32, 32),
new THREE.MeshStandardMaterial({ color: 'cyan' })
);
scrollGroup.add(sphere);
function positionCentered() {
var vp = Fold.getViewportSize();
sphere.position.set(
vp.width / 2,
-(160 * Fold.getPixelSize()),
0.05
);
}
positionCentered();
window.addEventListener('resize', positionCentered);
Objects added to Fold.getGroupFixed() stay anchored to
the viewport regardless of scroll position. Use it for HUD
elements, badges, navigation overlays, and any object that should
track the screen edge.
0, 0, 0)Fold.getViewportSize() for
bottom and right edge positioning.
var fixedGroup = Fold.getGroupFixed();
// Bottom-right corner — 100 px from each edge
var badge = new THREE.Mesh(
new THREE.TorusGeometry(
Fold.getPixelSize(30), Fold.getPixelSize(10), 16, 60
),
new THREE.MeshStandardMaterial({ color: 'orange' })
);
fixedGroup.add(badge);
function positionBadge() {
var vp = Fold.getViewportSize();
var margin = 100 * Fold.getPixelSize();
badge.position.set(vp.width - margin, -(vp.height - margin), 0.05);
}
positionBadge();
window.addEventListener('resize', positionBadge);
In this demo an orange torus ring appears in the bottom-right corner. No matter how far you scroll, it stays in exactly the same screen position.
Environment geometry, lighting, background models. Fixed in world coordinates. Not affected by scroll or XR origin.
Objects that live alongside page content. Origin = top-left of the page. Moves with scroll. Use getPixelSize() and getViewportSize() to align with HTML layout.
HUD / screen-anchored objects. Origin = top-left of the viewport. Never scrolls. Use getViewportSize() for edge positioning and reposition on resize.