The realistic eye on the scene — a camera with true perspective, where distant things look smaller and parallel lines converge, framed with real photographic controls (focal length, sensor size).
JavaScript API:
PerspectiveCamera
This is the perspective member of the AbstractCamera family: the camera
decides how the 3D scene is projected onto the 2D viewport. Declaring one replaces
the scene's default camera.
Aiming a camera is fiddly — a bare camera looks straight down its own local −Z,
so you must position AND rotate it by hand to frame the subject, and it does not
follow anything. For most scenes it is far easier to let a
sk-camera-orbit-control own the framing: it points a camera at a pivot,
fits the scene automatically, and gives you orbit / pan / zoom for free. Reach for a
hand-placed camera only when you want a specific fixed shot.
Key attributes. The lens is described photographically. focal-length (in mm)
sets the field of view — a short focal length (24mm) is a wide angle of view, a long
one (85mm+) is a narrow telephoto; it is animatable, so the lens can zoom in and out.
(The strength of perspective — how much near things loom over far ones — comes from
where the camera stands, not the focal length; a wide lens simply invites you close,
where perspective is strong.) sensor-width is the frame that focal length is
measured against (36mm = full-frame); focal length and sensor width together (with
the viewport aspect) determine the vertical field of view. near and far bound the
visible depth range. Position is the usual node transform — a camera on +Z looking
back at the origin is the simplest fixed setup.
Related. Its sibling sk-orthographic-camera drops perspective entirely
(parallel projection, constant on-screen size). To orbit, pan, and auto-fit instead
of hand-placing, use a sk-camera-orbit-control.
Serve these docs to run the live example.
WebGPU needs a secure context — open this page via grunt serve
rather than double-clicking the file. The Markup tab works from disk.
<!-- Three cubes marching away from the camera down a ground plane, with a
sphere alongside — a scene built to SHOW perspective. The camera sits low
and close and rakes down the row, so the near cube looms large and the far
ones shrink into the distance, and the ground grid converges toward the
horizon: that convergence IS the perspective, set by where the camera
stands. Its focal-length then ANIMATES 18mm to 70mm — a lens ZOOM: the
angle of view narrows and the framing magnifies in on the row (like a
camera's zoom ring), while the camera stays put. Declaring a camera
overrides the scene default; a camera looks down its local -Z, so it is
raised on +Y, pulled back on +Z, and pitched down. -->
<sk-scene>
<sk-directional-light intensity="1" p="42deg" h="20deg"></sk-directional-light>
<sk-ambient-light intensity="0.4"></sk-ambient-light>
<sk-plain-material id="ground" base-color="#8090a0"></sk-plain-material>
<sk-plain-material id="grid" base-color="#4a5766"></sk-plain-material>
<sk-plain-material id="box" base-color="#e0b050"></sk-plain-material>
<sk-plain-material id="ball" base-color="#7fa8d8"></sk-plain-material>
<!-- Ground plane with a subdivided wireframe grid on top: the grid lines
converging into the distance are the clearest read on perspective. -->
<sk-plane width="60" height="60" width-segments="30" height-segments="30"
include-quad-diagonals="false" cull-mode="none">
<sk-surface-paint material="#ground"></sk-surface-paint>
<sk-edge-paint material="#grid"></sk-edge-paint>
</sk-plane>
<!-- A row of equal cubes receding along -Z: perspective makes them shrink. -->
<sk-cube x="-1.5" y="1" z="2" size="2">
<sk-surface-paint material="#box"></sk-surface-paint>
</sk-cube>
<sk-cube x="-1.5" y="1" z="-4" size="2">
<sk-surface-paint material="#box"></sk-surface-paint>
</sk-cube>
<sk-cube x="-1.5" y="1" z="-10" size="2">
<sk-surface-paint material="#box"></sk-surface-paint>
</sk-cube>
<sk-sphere x="1.8" y="1" z="0" radius="1" segments="6">
<sk-surface-paint material="#ball"></sk-surface-paint>
</sk-sphere>
<!-- Fixed camera: low, close, raking down the row; focal length zooms. -->
<sk-perspective-camera sensor-width="36" y="2.5" z="7" p="-12deg"
near="0.1" far="1000" focal-length="18">
<sk-animation duration="5000ms" iterations="Infinity" direction="alternate">
<sk-keyframe offset="0" focal-length="18"></sk-keyframe>
<sk-keyframe offset="1" focal-length="70"></sk-keyframe>
</sk-animation>
</sk-perspective-camera>
</sk-scene>
| Attribute | Type | Default | Description |
|---|---|---|---|
id |
<id> |
— | The element's unique identifier — the standard HTML global id attribute. |
draggable |
<boolean> |
false |
Gets whether this node can be dragged. |
xanimatable |
<number> |
0 |
X position. |
yanimatable |
<number> |
0 |
Y position. |
zanimatable |
<number> |
0 |
Z position. |
hanimatable |
<angle> |
0 |
Heading (Y-axis rotation) in radians. |
panimatable |
<angle> |
0 |
Pitch (X-axis rotation) in radians. |
banimatable |
<angle> |
0 |
Bank (Z-axis rotation) in radians. |
quaternionanimatable |
<quaternion> ({ <number>, <number>, <number>, <number> }) |
— | Rotation as quaternion (overrides h, p, b if provided) |
sxanimatable |
<number> |
1 |
X-axis scale factor. |
syanimatable |
<number> |
1 |
Y-axis scale factor. |
szanimatable |
<number> |
1 |
Z-axis scale factor. |
s |
<number> |
— | Uniform scale factor for all axes (overrides sx, sy, sz if provided) write-only |
focal-lengthanimatable |
<number> |
300 |
Focal length in mm. |
sensor-widthanimatable |
<number> |
36 |
Sensor width in mm. |
nearanimatable |
<number> |
0.1 |
Near clipping plane distance. |
faranimatable |
<number> |
500.0 |
Far clipping plane distance. |
auto-clipping |
<boolean> |
true |
When true, the renderer recomputes near/far each frame from the camera-space |
auto-clipping-margin |
<number> |
0.1 |
Padding applied to the auto-computed depth range as a fraction (e.g. 0.1 = 10%). |
min-near |
<number> |
— | Hard lower clamp on the auto-computed near plane. |
max-far |
<number> |
1e6 |
Hard upper clamp on the auto-computed far plane. |
Standard DOM event-handler content attributes — the value is JavaScript run when the event fires. They behave exactly as on any HTML element.
onclick, ondblclick, onauxclick, oncontextmenu, onpointerdown, onpointerup, onpointermove, onpointercancel, onpointerover, onpointerout, onpointerenter, onpointerleave, ongotpointercapture, onlostpointercapture, onwheel, ondragstart, ondrag, ondragenter, ondragover, ondragleave, ondrop, ondragend
Used in guides: Scene basics