Scene API

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.

Overview

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.

state.scene — World Space

World Space

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.

Coordinate conventions (screen mode)
Fold's content group sits at roughly world [0, 0.7, −0.35] (driven by originOffsetScreen).
World Y = 0 ≈ bottom of the first viewport — floor level.
In XR, 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);
getGroupScroll() — Scroll Space

Scroll Group

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.

Origin — top-left 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);
getGroupFixed() — Fixed Space

Fixed Group

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.

Origin — top-left of the viewport (0, 0, 0)
Same coordinate convention as the scroll group, but the group does not translate with scroll. Use 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.

At a Glance

world space — state.scene

Environment geometry, lighting, background models. Fixed in world coordinates. Not affected by scroll or XR origin.

scroll space — getGroupScroll()

Objects that live alongside page content. Origin = top-left of the page. Moves with scroll. Use getPixelSize() and getViewportSize() to align with HTML layout.

fixed space — getGroupFixed()

HUD / screen-anchored objects. Origin = top-left of the viewport. Never scrolls. Use getViewportSize() for edge positioning and reposition on resize.