Surface Parallax Layer
The surface parallax layer is Hs2dParallaxLayer, implemented as a CompositorSurfaceLayer. It creates a cached surface, places one source sprite inside a compositor, moves that sprite as the camera changes, redraws the surface only when dirty, and composes the surface into the scene.
Use it when a parallax background needs surface composition, repeat-height behavior, side-layer clamping, zoom constraints, or other compositor-surface behavior. If the art is already a simple final strip, consider direct parallax first.
When To Use
Use surface parallax for:
| Good fit | Better alternative |
|---|---|
| Parallax strip with repeat Y or a controlled surface size. | Direct parallax for one finished strip that only scrolls horizontally. |
| Layer that should react to camera zoom with min/max scale. | Sky for screen-fixed art. |
| Background assembled through a compositor surface. | Cached surface for large static world art. |
Construction Pattern
Manual construction:
world.addParallaxLayer({
id: 'near-nebula',
source: nebulaBitmap,
surfaceWidth: screenWidth,
surfaceHeight: 360,
drawX: 0,
drawY: 120,
parallaxX: 0.35,
parallaxY: 0.1,
cameraOriginX: startCameraX,
cameraOriginY: startCameraY,
scrollSlack: 640,
driftXPxPerSec: -8,
zoomScaleRatio: 0.2,
minScale: 0.96,
maxScale: 1.04,
});
Tiled construction:
Image layer: near-nebula
hs2d:role = parallax
hs2d:compose = surface
hs2d:surfaceWidth = 1280
hs2d:surfaceHeight = 360
hs2d:scrollSlack = 640
hs2d:driftX = -8
hs2d:zoomScaleRatio = 0.2
hs2d:minScale = 0.96
hs2d:maxScale = 1.04
The builder treats surface as the default compose mode for parallax image layers.
Update, Render, And Compose Behavior
| Phase | Behavior |
|---|---|
| Attach | Creates a surface, compositor, source region, and one compositor sprite. |
| Drift | advanceDrift(deltaMs) updates bounded drift offsets. |
| Update | Computes the next sprite position from camera delta, parallax, scroll slack, repeat height, side-layer mode, and drift. If the position changes, moves the sprite and marks the surface dirty. |
| Render | Clears and redraws the compositor surface only when dirty. |
| Compose | Draws or scaled-draws the cached surface to the screen. |
The layer's render scale follows world zoom through CompositorSurfaceLayer.setRenderScale, using zoomScaleRatio, minScale, and maxScale.
Performance Notes
- Surface parallax can cost more than direct parallax because a moving strip can require a sprite move, a surface redraw, and a surface compose.
- Keep
surfaceWidthandsurfaceHeighttight around the visual area. - Use
hs2d:designHeightto scale art once at build time, not per frame. - Use
scrollSlackfor seamless wrap instead of oversized doubled bitmaps. - Do not use a parallax surface as an ad hoc gameplay draw target.
Code Sample
const world = Hs2dWorld.create({
x: startCameraX,
y: startCameraY,
viewportWidth: screenWidth,
viewportHeight: screenHeight,
worldWidth,
worldHeight,
});
world.addParallaxLayer({
id: 'side-rocks',
source: rocksBitmap,
surfaceWidth: screenWidth,
surfaceHeight: screenHeight,
parallaxX: 0.18,
parallaxY: 0.4,
cameraOriginX: startCameraX,
cameraOriginY: startCameraY,
drawX: 0,
drawY: 0,
zoomScaleRatio: 0,
minScale: 1,
maxScale: 1,
});
Source References
| Source | Why it matters |
|---|---|
../games/hosanna-ui/src/hosanna-game/scene/GameSceneRenderer.ts | Hs2dParallaxLayer, CompositorSurfaceLayer, dirty rendering, zoom scaling, repeat and scroll behavior. |
../games/hosanna-ui/src/hosanna-game/hosanna2d/Hs2dWorld.ts | addParallaxLayer, addParallaxStrip, and drift advancement. |
../games/hosanna-ui/src/hosanna-game/hosanna2d/Hs2dWorldBuilder.ts | Tiled image-layer mapping for surface parallax options. |
../hosanna-ui-game-samples-public/src/hosanna-game-examples/native-shoot-em-up/VerticalShooterLevelScene.ts | Example map-driven shooter background stack built from level image layers. |