Skip to main content

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 fitBetter 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

PhaseBehavior
AttachCreates a surface, compositor, source region, and one compositor sprite.
DriftadvanceDrift(deltaMs) updates bounded drift offsets.
UpdateComputes 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.
RenderClears and redraws the compositor surface only when dirty.
ComposeDraws 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 surfaceWidth and surfaceHeight tight around the visual area.
  • Use hs2d:designHeight to scale art once at build time, not per frame.
  • Use scrollSlack for 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

SourceWhy it matters
../games/hosanna-ui/src/hosanna-game/scene/GameSceneRenderer.tsHs2dParallaxLayer, CompositorSurfaceLayer, dirty rendering, zoom scaling, repeat and scroll behavior.
../games/hosanna-ui/src/hosanna-game/hosanna2d/Hs2dWorld.tsaddParallaxLayer, addParallaxStrip, and drift advancement.
../games/hosanna-ui/src/hosanna-game/hosanna2d/Hs2dWorldBuilder.tsTiled image-layer mapping for surface parallax options.
../hosanna-ui-game-samples-public/src/hosanna-game-examples/native-shoot-em-up/VerticalShooterLevelScene.tsExample map-driven shooter background stack built from level image layers.
Talk to us