Skip to content
Apexify.jsDocs
Apexify.js version v5.4.5

Node / Images Shapes · guide

Grouped layers (isGrouped, groupTransform)

Current Apexify.js 6.0.0 documentation for Grouped layers (isGrouped, groupTransform).

apexify.jsRuntime: nodeCURRENTSince 6.0.0

Pass CreateImageOptions as the third argument to createImage when you want multiple ImageProperties entries composited as one logical layer.


Activation rules

SOURCEtypescript
typescript
Studio
await painter.createImage(  [    { source: './bg.jpg', x: 0, y: 0, width: 600, height: 400 },    { source: './fg.png', x: 120, y: 80, width: 320, height: 240, fit: 'contain' },  ],  buffer,  {    isGrouped: true,    groupTransform: {      rotation: -6,      pivotX: 300,      pivotY: 200,      opacity: 0.95,      shadow: { color: '#00000066', offsetY: 18, blur: 28 },      filters: [{ type: 'gaussianBlur', intensity: 0.08 }],      filterOrder: 'post',    },  });

Requirements:

  1. images must be an array with more than one entry.
  2. options.isGrouped must be true and you supply groupTransform — otherwise paintImageLayersOntoContext falls back to drawing items sequentially like unrelated layers.

What groupTransform can do

Mirrors many ImageProperties fields:

AreaSupported keys
Motionrotation, translateX, translateY, scaleX, scaleY, pivotX, pivotY
Layer styleopacity, blur, blendMode
Clip / plateborderRadius, borderPosition, clipPath, boxBackground
Typed, not wired on groupmask, distortion, meshWarp on groupTransform exist in TS but the renderer ignores them — assign on each ImageProperties instead.

Implementation notes worth remembering:

  • filterOrder: 'pre' composites every child bitmap into an off-screen buffer clipped to the axis-aligned group bounding box, filters once, then blits — per-layer rotations are stripped (rotation: 0 clone). Early return skips transforms/effects/stroke pipeline besides what that branch draws.
  • filterOrder: 'post' (default behaviour when unset or non-pre) rasterises transformed corners into a tighter rectangle estimate before filtering — heavily rotated groups might crop imperfectly near edges.
  • Per-layer rotation values are intentionally forced to 0 inside the grouped loop — rotate with groupTransform.rotation instead.

Stroke after grouping

After transforms restore, groupTransform.stroke outlines the original axis-aligned union rectangle (groupBox) optionally re-applying rotation/scale translation — handy for framing stickers.


When not to group

  • You need independent effects timings per bitmap with precise stroke ordering alongside meshWarp — split layers instead.
  • Only one image is present — isGrouped adds no benefit.


Next steps