Tiled Layer Properties
Hs2d reads normal Tiled layer fields plus a small hs2d:* custom-property vocabulary. Put engine directives under hs2d:*; keep game-specific properties unprefixed or under your own prefix.
Properties are flattened by name. If the same custom property appears more than once on the same source, the later entry wins.
Property Value Rules
Hs2dLevel has helpers for common property types:
| Helper | Accepted values |
|---|---|
getNumberProperty(source, name, fallback) | Numbers, or decimal strings such as 12, -4, 0.5. |
getStringProperty(source, name, fallback) | Strings, or number/boolean values converted with String(value). |
getBooleanProperty(source, name, fallback) | Booleans, or exact strings true and false. |
Color properties use parseHs2dColorProperty:
| Tiled value | Runtime color |
|---|---|
#RRGGBB | 0xRRGGBBff |
#AARRGGBB | 0xRRGGBBAA |
| number | Used as-is, already in Hs2d 0xRRGGBBAA form. |
Invalid color strings are ignored and the relevant fallback is used.
Map Properties
| Property | Type | Default | Runtime behavior |
|---|---|---|---|
hs2d:clearColor | color string or number | Builder clearColor, then 0x000000ff | World clear color. Also used as the fallback sky clear color. |
| Any other property | any | none | Preserved on level.properties for game code. |
Use map properties for level-wide data such as music keys or difficulty only when runtime code reads them through Hs2dLevel.
Native Tiled Layer Fields
These are not custom properties, but Hs2d parses them on tile, image, object, and group layers:
| Tiled field | Runtime name | Behavior |
|---|---|---|
parallaxx | parallaxX | Multiplied through group ancestry. Used by image parallax and decor defaults. |
parallaxy | parallaxY | Multiplied through group ancestry. Used by image parallax and decor defaults. |
offsetx | offsetX | Added through group ancestry. Used by image layer draw offsets. |
offsety | offsetY | Added through group ancestry. Used by image layer draw offsets. |
visible | visible | Inherited through groups. Invisible layers are skipped by Hs2dWorldBuilder. |
opacity | opacity | Multiplied through groups and preserved on parsed layers. The current builder paths do not apply opacity. |
repeatx | repeatX | Parsed for image layers. Current parallax builder does not use horizontal repeat. |
repeaty | repeatY | Parsed for image layers. Surface parallax uses it as repeatHeight; direct parallax does not. |
Image Layer Properties
Image layers are built by Hs2dWorldBuilder.buildImageLayer. The default image role is parallax.
| Property | Type | Default | Applies to | Behavior |
|---|---|---|---|---|
hs2d:asset | string | layer name | sky, parallax | Asset-gate bitmap name. This must match the name passed to Hs2dAssetGate.add(name, uri), not necessarily the namespaced manifest key. |
hs2d:role | string | parallax | image layer | sky builds a screen-fit sky layer. Any other value follows the parallax path. |
hs2d:clearColor | color | world clear color | sky | Clear color used by world.addSky. |
hs2d:designHeight | number | 0 | parallax | If greater than zero and different from viewport height, the bitmap and pixel-space options are scaled once at build time. |
hs2d:compose | string | surface | parallax | direct creates a direct parallax layer. Other values create a surface parallax layer. |
hs2d:scrollSlack | number | 0 | direct, surface parallax | Extra strip slack for scroll coverage. Scaled by designHeight fit. |
hs2d:driftX | number | 0 | direct, surface parallax | Horizontal drift in pixels per second. Scaled by designHeight fit. |
hs2d:anchorBottomWorldY | number | unset | direct parallax | World-space Y line used to pin the strip bottom to the screen until the camera rises above it. Not scaled by designHeight. |
hs2d:anchorWorldHeight | number | unset | direct parallax with bottom anchor | World-space band height. Scales the source vertically with camera zoom so its top remains world-aligned. Not scaled by designHeight. |
hs2d:surfaceWidth | number | bitmap width | surface parallax | Cached parallax surface width. Scaled by designHeight fit. |
hs2d:surfaceHeight | number | bitmap height | surface parallax | Cached parallax surface height. Scaled by designHeight fit. |
hs2d:z | number | builder layer order | surface parallax | Explicit z order. Values below 0 are ignored. |
hs2d:zoomScaleRatio | number | 0 | surface parallax | Zoom scale ratio passed to the parallax layer. |
hs2d:minScale | number | 1 | surface parallax | Minimum zoom-constrained scale. |
hs2d:maxScale | number | 1 | surface parallax | Maximum zoom-constrained scale. |
Direct image layers are the low-overhead path for finished strip art: one clipped blit per frame, no intermediate surface. Surface parallax layers are appropriate when the layer needs a cached surface, vertical repeat, z control, or zoom constraints.
The bottom-anchor properties are useful for water, fog, or foreground bands that meet a fixed world line. Hosanario's water layer uses hs2d:anchorBottomWorldY=2176 and hs2d:anchorWorldHeight=120.
Example:
{
"type": "imagelayer",
"name": "clouds",
"image": "clouds-strip.png",
"parallaxx": 0.08,
"parallaxy": 0,
"offsety": 24,
"properties": [
{ "name": "hs2d:asset", "type": "string", "value": "clouds-strip" },
{ "name": "hs2d:designHeight", "type": "int", "value": 720 },
{ "name": "hs2d:compose", "type": "string", "value": "direct" },
{ "name": "hs2d:scrollSlack", "type": "int", "value": 1280 },
{ "name": "hs2d:driftX", "type": "int", "value": 7 }
]
}
Tile Layer Properties
Tile layer properties control which renderer is built.
| Property | Type | Default | Applies to | Behavior |
|---|---|---|---|---|
hs2d:mode | string | auto | tile layer | auto, dynamic, static, or cached. Invalid values fall back to auto. |
hs2d:z | number | order * 10 | dynamic tile layer | Tile sprite z order. |
hs2d:spriteLayer | string | builder spriteLayerId | dynamic tile layer | Hosting Hs2dSpriteLayer id. In ordinary builder use, this must equal the configured spriteLayerId; see Named Sprite Layers. |
hs2d:poolPadding | number | 2 | dynamic/auto estimate | Extra tile columns/rows around the visible window. Also affects auto-mode pool sizing. |
hs2d:chunkWidth | number | 512 | cached tile layer | Cached chunk surface width, unless tileLayerChunkSizes[layerId].width overrides it. |
hs2d:chunkHeight | number | 512 | cached tile layer | Cached chunk surface height, unless tileLayerChunkSizes[layerId].height overrides it. |
hs2d:clearColor | color | transparent/implementation default | static, cached | Static uses it as clearColor; cached uses it as surfaceClearColor. |
hs2d:viewportClearColor | color | implementation default | static | Viewport clear color for static tile layers. |
hs2d:allowLargeWorldSurface | boolean | false | static | Allows a static whole-layer surface to exceed the normal guard. Use only for intentionally small-risk targets. |
Mode behavior:
| Mode | Builder path |
|---|---|
auto | Estimates worst-case dynamic pool from viewport, minScale, tile size, and poolPadding. If the estimate is over 4096, builds cached chunks; otherwise builds the dynamic tile layer. |
dynamic | Forces the dynamic tile-layer branch. |
static | Builds one whole-layer cached surface. Does not require the default foreground sprite layer. |
cached | Builds cached chunks. Does not require the default foreground sprite layer. |
Example:
{
"type": "tilelayer",
"name": "terrain",
"width": 228,
"height": 34,
"data": [0, 1, 2],
"properties": [
{ "name": "hs2d:mode", "type": "string", "value": "auto" },
{ "name": "hs2d:z", "type": "int", "value": 40 }
]
}
Object Group Properties
Object groups are built by role. The default object role is entities.
| Property | Type | Default | Applies to | Behavior |
|---|---|---|---|---|
hs2d:role | string | entities | object group | decor, entities, and zones are the verified roles. Unknown roles stay data-only. |
hs2d:z | number | order * 10 | decor, entities | Default z for decor objects or entity groups. Entity binding zIndex overrides it. |
hs2d:spriteLayer | string | builder spriteLayerId | decor, entity groups without binding layer | Hosting sprite layer id. In ordinary builder use, this must equal the configured spriteLayerId; see Named Sprite Layers. |
hs2d:cullPaddingX | number | 512 | decor | Default horizontal decor culling slack. |
hs2d:cullPaddingY | number | 512 | decor | Default vertical decor culling slack. |
Role behavior:
| Role | Builder behavior |
|---|---|
decor | Converts objects into parallax sprite items using per-object decor properties. |
entities | Looks up each object type in the code-side entities binding map and creates bound sprites. |
zones | Does not build render objects. Game code queries the objects from Hs2dLevel. |
| unknown | Does not build render objects. The objects remain queryable. |
Decor Object Properties
Decor objects are read by Hs2dLevel.getParallaxSpriteSpecs.
| Property | Type | Default | Behavior |
| --- | --- | --- |
| frame | string | object name, then object type | Decor frame id. Builder maps this through decorFrames or uses it as the asset name. |
| parallaxX | number | object-group parallaxX, then 1 | Per-object horizontal parallax multiplier. |
| parallaxY | number | object-group parallaxY, then 1 | Per-object vertical parallax multiplier. |
| zIndex | number | object-group hs2d:z, then order * 10 | Per-object z order. |
| cullPaddingX | number | object-group hs2d:cullPaddingX, then 512 | Horizontal culling slack. |
| cullPaddingY | number | object-group hs2d:cullPaddingY, then 512 | Vertical culling slack. |
Example:
{
"type": "objectgroup",
"name": "background-decals",
"properties": [{ "name": "hs2d:role", "type": "string", "value": "decor" }],
"objects": [{
"name": "moon",
"type": "decal",
"x": 179.12,
"y": 4915.2,
"properties": [
{ "name": "frame", "type": "string", "value": "moon" },
{ "name": "parallaxX", "type": "float", "value": 0.035 },
{ "name": "parallaxY", "type": "float", "value": 0.075 },
{ "name": "zIndex", "type": "int", "value": 12 },
{ "name": "cullPaddingX", "type": "int", "value": 720 },
{ "name": "cullPaddingY", "type": "int", "value": 520 }
]
}]
}
Entity Object Properties
The engine does not reserve hs2d:* properties for individual entity objects today. Entity object properties are game-owned data read by spawn callbacks and simulations.
Examples from the samples:
| Property | Owner | Use |
|---|---|---|
variant | vertical shooter, Hosanario | Selects enemy frame/behavior. |
health | vertical shooter | Initial enemy health override. |
axis | Hosanario | Moving platform axis. |
order | Hosanario | Checkpoint ordering. |
Use level.getNumberProperty, level.getStringProperty, and level.getBooleanProperty in binding code so Tiled's property type choices do not leak into gameplay logic.
Named Sprite Layers
Hs2dWorldBuilder.fromLevel(...) creates a private world and lazily creates one default foreground Hs2dSpriteLayer. Its id is the spriteLayerId option, defaulting to hs2d-foreground.
In the normal builder path:
- omit
hs2d:spriteLayerand entity bindinglayerto use that default - or set them to the same id passed as
spriteLayerId
The public builder options do not accept pre-created layers or an existing world, so a distinct named layer cannot be injected before fromLevel() resolves the map. Build the world imperatively when multiple independently configured sprite layers are required. The current source error suggesting that callers “add it before building” does not describe an available public builder path.
Zone Objects
Zones are ordinary Tiled objects in an object group with hs2d:role=zones. The builder skips them, and game code reads them by group and type.
Example:
{
"type": "objectgroup",
"name": "zones",
"properties": [{ "name": "hs2d:role", "type": "string", "value": "zones" }],
"objects": [
{ "name": "spawn", "type": "player-spawn", "x": 128, "y": 1856, "width": 64, "height": 64 },
{ "name": "pit-46", "type": "hazard", "x": 2944, "y": 2112, "width": 192, "height": 64 }
]
}
Do And Don't
Do:
- use
hs2d:*only for properties the builder understands - use native Tiled parallax fields for image/decor layer movement
- set
hs2d:assetwhen the asset-gate name differs from the layer name - use
hs2d:compose=directfor simple strip backgrounds - leave gameplay tuning data as object properties read by code
Don't:
- assume every parsed native Tiled field is applied by the builder
- rely on image layer
imageas the asset key whenhs2d:assetis set - put entity binding details such as sprite frames in Tiled
- point
hs2d:spriteLayerat an id other than the builder's configuredspriteLayerId - use
statictile mode for large worlds unless the surface size is known to be safe
Source Reference
| Source | Confirms |
|---|---|
../games/hosanna-ui/src/hosanna-game/hosanna2d/Hs2dWorldBuilder.ts | All verified hs2d:* builder properties, defaults, color parsing, tile mode selection, decor/entity/zones behavior. |
../games/hosanna-ui/src/hosanna-game/hosanna2d/level/Hs2dLevel.ts | Property helper coercion, parallax sprite spec defaults, tile solidity, and object lookup. |
../games/hosanna-ui/src/hosanna-game/hosanna2d/level/Hs2dTiledLevel.ts | Native Tiled fields parsed on layers and group composition. |
../games/hosanna-ui/src/hosanna-game/hosanna2d/Hs2dWorldBuilder.test.ts | Tested builder behavior for modes, chunk sizing, visibility skips, color parsing, decor asset failures, entity binding, and auto tile mode. |
../hosanna-ui-game-samples-public/asset-bundles/hosanario/levels/level-1.json | Real direct parallax, terrain, entities, and zones properties. |
../hosanna-ui-game-samples-public/asset-bundles/native-shoot-em-up/levels/level-1.json | Real sky, surface parallax, decor, and entity properties. |