Skip to content

Image Capabilities ​

Fold.page renders images, SVGs, and 3D models as first-class elements in the 3D scene. Standard <img> tags become textured planes with full CSS sizing and opacity support. SVGs can be rasterized as flat textures or converted into extrudable 3D mesh geometry. GLB and GLTF models are auto-scaled to fit any element and composed with the same transform and position pipeline as every other element on the page.


Index ​

  • Basic Image Rendering — Standard <img> elements rendered as flat textured planes with CSS sizing and opacity.
  • Depth Repetition — Stack multiple copies of an image along the Z axis. Without box-shadow, the whole stack pushes forward toward the camera; with box-shadow, each layer is styled individually and recedes/directs per layer.
  • SVG Images — Texture or geometry rendering for .svg sources and inline <svg> tags.
    • Texture Mode — SVG rasterized to a flat texture; supports gradients, filters, and masks.
    • Geometry Mode — SVG paths converted to 3D mesh geometry with optional extrusion.
    • Inline <svg> Elements — Per-shape depth control for layered 3D compositions in plain markup.
  • Lit Materials — Make images and SVGs respond to scene lighting with PBR material presets.
  • 3D Models (GLB / GLTF) — Load and auto-scale GLB models at any element's position.
    • Auto-scaling — Longest axis scaled to CSS width; data-foldpage-scale applies on top.
    • Draco Compression — Draco-compressed GLBs handled automatically via a shared decoder.
    • Transforms — data-foldpage-scale and CSS transform attributes apply.
    • CSS Position — Static, absolute, fixed, and sticky position routing works the same as all other elements.
    • Loading — Models load in the background without blocking the scene.

Basic Image Rendering ​

By default, <img> elements inside the .foldpage wrapper are rendered as flat textured planes:

  • Size and position follow the image's CSS layout (width, height, object-fit, positioning).
  • Transparent PNGs work; nearly transparent pixels (alpha below 0.1) are cut out.
  • CSS opacity is applied.
  • Both sides are visible by default, following the global backside setting.

No configuration needed.

Back-Face Rendering ​

By default images are double-sided, so they're visible when rotated to face away from the viewer. To make a specific image single-sided, add data-foldpage-backface="false":

html
<img src="logo.png"
     data-foldpage-depth="7"
     data-foldpage-backface="false">

This is useful when images form the faces of a 3D composition (e.g. a CSS-positioned cube using rotateY transforms) — suppressing the back face prevents the inside surface from bleeding through when the element rotates. The attribute applies to the image's primary plane and all its depth-repetition copies.

Scope: Currently applies to <img> elements. The global default is set by Fold.init({ backside }). See Data Attribute API → backface for the full attribute reference.


Depth Repetition ​

data-foldpage-depth creates stacked depth copies of an image along the Z axis. Whether the stack recedes behind the image or the whole stack pushes forward toward the camera depends on whether the image has a CSS box-shadow.

Required attributes:

AttributeDescription
data-foldpage-depthTotal depth of the stack in CSS pixels. Determines how many copies are made.
data-foldpage-depth-intervalZ-spacing between each copy (CSS px). Default: 2.

Layer count formula: layers = round(depth / interval), clamped to a maximum of 20 layers.

Default (no box-shadow): forward push ​

With no box-shadow, depth copies use default styling (white tint, base opacity) and the entire stack — including the primary image — is pushed forward toward the camera by the full clamped stack depth (layers × interval). The image bulges out of the page rather than sinking into it.

html
<!-- depth 9 / interval 2 = round(4.5) = 5 depth copies.
     Primary image + all 5 copies shift forward 10px (5 × 2) toward the camera. -->
<img src="card.png"
     data-foldpage-depth="9"
     data-foldpage-depth-interval="2">

With box-shadow: styled, receding layers ​

Adding a box-shadow opts into per-layer styling and disables the forward push — depth behaves exactly as before, with each shadow layer becoming a separate 3D mesh offset behind (or, with inset, in front of) the primary image.

html
<!-- depth 9 / interval 2 = 5 depth copies, styled and receding — no forward push -->
<img src="card.png"
     data-foldpage-depth="9"
     data-foldpage-depth-interval="2"
     style="box-shadow:
       0 2px 4px rgba(0, 0, 200, 0.5),
       0 4px 8px rgba(100, 0, 200, 0.4),
       0 6px 12px rgba(200, 0, 255, 0.3),
       0 8px 16px rgba(255, 0, 200, 0.2);">

Shadow → 3D layer mapping:

Shadow property3D effect
offset-x / offset-yMesh XY offset
colorTint applied to the layer mesh
spread-radiusMesh scale (positive = larger shadow copy)
blur-radiusInfluences layer opacity
insetReverses direction (inset = layer in front rather than behind)

Layer assignment: Each box-shadow layer styles one depth copy in order. If there are more depth copies than shadow layers, all remaining copies share the styling of the last shadow. This means you can define a general "background echo" with a single shadow and use a larger data-foldpage-depth to get many copies of it.

html
<!-- 10 copies, all styled by the single box-shadow -->
<img src="logo.png"
     data-foldpage-depth="15"
     data-foldpage-depth-interval="1.5"
     style="box-shadow: 0 0 8px rgba(100, 0, 255, 0.3);">

Text has the same forward-push behavior. A text element with no visible background and no CSS text-shadow treats data-foldpage-depth / data-foldpage-depth-interval the same way images do in the no-box-shadow case — synthesizing shadow-style layers (50% opacity, inheriting the text color) and pushing the whole stack forward. See CSS Properties → Text Shadows.


SVG Images ​

<img> elements with .svg sources, and inline <svg> tags within the wrapper, are automatically routed through the SVG pipeline. Two modes are available, and the default depends on how the SVG is placed:

SVG placementDefault mode
<img src="….svg">Texture
Inline <svg>Geometry — or texture when the SVG uses texture-only features (<linearGradient>, <radialGradient>, <filter>, <clipPath>, <mask>, <text>/<tspan>, <image>, <foreignObject>, SMIL or CSS animation) and has no data-foldpage-depth

Set data-foldpage-svg-mode="texture" or "geo" to choose the mode explicitly.

Texture Mode ​

The SVG is rendered to an offscreen canvas and used as a flat texture. This handles complex SVGs with gradients, filters, masks, and clip paths.

html
<img src="complex-illustration.svg">

Geometry Mode ​

SVG paths are parsed and converted into 3D mesh geometry. Each closed path becomes a flat polygon, with optional extrusion depth.

html
<img src="logo.svg" data-foldpage-svg-mode="geo" data-foldpage-depth="40" data-foldpage-lit="metal">

Geometry mode supports:

  • data-foldpage-depth — extrudes paths forward (positive) or backward (negative) in CSS pixels
  • data-foldpage-lit — any material preset (see below)
  • Per-path colors from SVG fill attributes
  • Complex multi-path logos and icons

Inline <svg> Elements ​

Inline <svg> tags placed directly in the page are supported without any additional configuration. Fold detects them automatically and routes them through the geometry pipeline, giving each path its own mesh. (An inline SVG that uses texture-only features and has no data-foldpage-depth falls back to texture mode — add data-foldpage-svg-mode="geo" to force geometry.)

The most useful feature of inline SVGs is per-element depth: adding data-foldpage-depth to individual child shapes controls how far that shape is extruded forward, independently of the others. Combined with data-foldpage-lit on the root <svg>, this lets you build layered 3D compositions entirely in markup:

html
<svg data-foldpage-lit xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 320">
  <!-- Base background — sits at z=0 -->
  <rect width="640" height="320" fill="#111720"/>

  <!-- Card surface — raised 30px above the background -->
  <rect data-foldpage-depth="30"
        x="36" y="36" width="568" height="248" rx="18"
        fill="#1f252c" stroke="#313944"/>

  <!-- Avatar circle — floats 40px above the background -->
  <circle data-foldpage-depth="40"
          cx="164" cy="160" r="60"
          fill="#6bb7ff"/>

  <!-- Heading bar — raised 70px -->
  <rect data-foldpage-depth="70"
        x="268" y="106" width="220" height="30" rx="8"
        fill="#8ad7c1"/>

  <!-- Subheading bar — raised 100px, closest to the viewer -->
  <rect data-foldpage-depth="100"
        x="268" y="156" width="160" height="24" rx="8"
        fill="#ffd27a"/>
</svg>

Each shape becomes a separate mesh at its own Z position. The data-foldpage-lit on the root <svg> applies a lit material to every child mesh simultaneously — the same as placing it on a parent HTML element. Shapes without a data-foldpage-depth attribute render flat at Z=0.


Lit Materials ​

By default, images and SVGs are unlit — they show their exact colors regardless of scene lighting. To make an image respond to lights, add data-foldpage-lit:

html
<img src="coin.png" data-foldpage-lit="metal">
<img src="logo.svg" data-foldpage-svg-mode="geo" data-foldpage-lit="glossy">

Available presets:

PresetDescription
(absent)Unlit — full color, no lighting response
standardBalanced PBR — responds to lights, roughness 0.5
reflectiveChrome mirror — roughness 0, metalness 0.5
roughDiffuse matte — roughness 1, metalness 0
glossyShiny plastic — roughness 0.15, metalness 0
metalBrushed metal — roughness 0.2, metalness 0.6
glowEmissive — glows with its own color, independent of lighting
vividLambertian + 50% self-emission — colors stay close to CSS values while responding to lights

data-foldpage-lit can also be placed on a parent element to apply to all descendant meshes simultaneously — see Data Attribute API — Lighting.


3D Models (GLB / GLTF) ​

Any HTML element can host a 3D model by adding data-foldpage-model-src. Fold loads the file, auto-scales the model to fit the element's CSS width, and positions it in the 3D scene exactly like every other Fold element — inheriting all transform attributes and CSS position routing.

Like any Fold attribute, the host element still has to fall within a .foldpage target to be discovered — either as a descendant of one elsewhere on the page, or, most commonly for a single model anchor, by carrying .foldpage directly on itself:

html
<!-- An empty div becomes a 3D model anchor. .foldpage here makes this div its
     own independent scoped target — it doesn't need to be wrapped in a
     separate .foldpage container, and it doesn't need any children either;
     Fold checks the .foldpage element itself for content, not just its descendants. -->
<div class="foldpage my-model"
     data-foldpage-model-src="/models/plant/scene.glb"
     style="width: 300px; height: 300px;">
</div>

If this div already lives inside a page or section that's already .foldpage-scoped (a wrapping .foldpage ancestor, or Fold.init({ foldpage: true })), you can drop the .foldpage class here — it'll be discovered as a normal descendant instead.

Auto-scaling ​

The model's longest axis (X, Y, or Z) is uniformly scaled to match the element's CSS width. This ensures the model fills its container without stretching.

If the element has no width, the parent's width is used, then half the viewport width.

After auto-scaling, all data-foldpage-scale / CSS scale() transforms are applied on top, so you can fine-tune size without losing the fit behavior.

Draco Compression ​

Standard and Draco-compressed GLBs are handled by the same loader instance — no extra configuration needed. Fold shares a single DRACOLoader (decoder fetched from the Google CDN on demand) across all models.

Transforms ​

Like any other element, a model is positioned and rotated with CSS transform, so it follows media queries and other responsive CSS:

AttributeEffect
data-foldpage-scaleUniform scale multiplier (applied after auto-fit)
data-foldpage-scale-originCustom pivot point for scale (Y positive = down, CSS convention)
CSS transformtranslate, rotate, scale — all parsed and composed
CSS transform-originPivot for CSS transform
html
<!-- Model floated forward and tilted -->
<div data-foldpage-model-src="/models/trophy.glb"
     style="width: 200px; height: 200px;
            transform: translateZ(60px) rotateY(15deg) rotateX(-5deg);">
</div>

CSS Position ​

GLB elements follow the same CSS position routing as all other Fold elements:

CSS positionBehavior in 3D
static / relativePlaced in the scroll scene at DOM position
absolutePositioned relative to nearest positioned ancestor
fixedRendered in the fixed overlay group — stays in view
stickyDual scroll + fixed instances, toggled at stick threshold

Loading ​

Models are loaded lazily so the scene renders without blocking while the GLB fetches; the model appears once loaded with no layout shift.

Tip: For best results, give the host element explicit width and height in CSS.

Fold.page — 3D UI for the web.