Search by

wapplersystems / herobuilder

svewap

Graphical per-breakpoint hero composition builder (drag & drop FAL layers, carousel of collages) for TYPO3.

Package info

github.com/WapplerSystems/t3-herobuilder

Language:JavaScript

Type:typo3-cms-extension

pkg:composer/wapplersystems/herobuilder

Statistics

Installs: 14

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

dev-release/v14 2026-10-28 13:13 UTC

This package is auto-updated.

Last update: 2026-10-28 13:25:30 UTC


README

Graphical, per-breakpoint hero composition builder for TYPO3.

Editors drag & drop FAL image layers, text and linked button layers onto a stage, position/scale/rotate them per breakpoint, and manage multiple collages that render as a Bootstrap 5 carousel. Layers stay individual, CSS-positioned elements (%-based) — no server-side flattening for the frontend — with optional AOS entrance animations.

A 3-column canvas editor (toolbar · layer panel · stage · property tabs, based on Moveable) provides a full WYSIWYG workflow, including reusable templates, one-click social / OG image export (ImageMagick), and a live preview rendered with the real frontend CSS.

  • Extension key: herobuilder
  • Content element (CType): herobuilder
  • TYPO3: 12.4 · PHP: ≥ 8.1
  • State: beta (0.1.0)

Table of contents

Concepts

  • Stage — the hero canvas. Each breakpoint has a fixed aspect ratio (frontend) and a realistic reference device width (backend editor), so what you edit matches the device.
  • Breakpoints — Bootstrap 5: xs (<576px), sm (576–767), md (768–991), lg (992–1199), xl (1200–1399), xxl (≥1400). Every layer is positioned independently per breakpoint.
  • Collage — one slide. A content element holds n collages → rendered as a carousel.
  • Layer — an image (FAL), a text block, or a button (text + TYPO3 link), freely placed within the stage.
  • Template — a reusable composition (record in tx_herobuilder_template or a shipped preset) that can be applied to a collage or created from one.

Feature list

Content element & rendering

  • Dedicated herobuilder content element with a New-Content-Element wizard entry.
  • 1:n collages (tx_herobuilder_collage) rendered as a Bootstrap 5 carousel (autoplay, interval, loop, prev/next controls, indicators, pause-on-hover, slide/fade transition).
  • Per-breakpoint stage aspect ratios (frontend) via scoped, media-query CSS — or a fixed stage height per breakpoint, switchable per content element.
  • Responsive images — every image layer gets a WebP srcset (480–3200px, capped at the cropped source) and a sizes computed from its per-breakpoint geometry, including the overflow of cover (e.g. a wide background on a tall phone stage is painted much wider than the screen).
  • Accessible carousel — localized labels (locallang.xlf), carousel/slide roles, a pause/play button whenever autoplay is on (WCAG 2.2.2), no autoplay and no AOS entrance animations under prefers-reduced-motion, autoplay holds while keyboard focus is inside, visible focus rings on the controls. Prev · indicators · next sit together in a dark pill at the bottom centre: never on the composition's text, >= 3:1 contrast on any artwork, 24 px targets.
  • CSP-ready frontend — the scoped composition CSS goes into the <head> via the AssetCollector with csp="true" (hash/nonce), no inline <style> in the body.
  • Backend page-module preview renderer (slide + layer thumbnails / text chips).

Layers

  • Image layers from FAL (native TYPO3 file browser via the sibling assets field → real sys_file_reference, clean reference index).
  • Text layers — plain text, styled exclusively via predefined classes (safe, auto-escaped). The HTML element is selectable (div, p, h1–h6) for semantics only: hero.css resets the element's own styles, so a heading looks exactly like the same layer as a div.
  • Button layers — text + TYPO3 link (page/url/file/mail/…) via the native Link Browser, styled with btn classes; rendered as a <a> typolink on the frontend.
  • Per-breakpoint geometry — x / y / width / height (%), rotation, z-index, visibility.
  • Image fit — fill / cover / contain (no distortion for cover/contain).
  • Focus point — object-position picker (which part stays visible when cover crops).
  • Art direction — "Crop & focus only for XS" gives a breakpoint its own crop and focus point. The frontend renders a <picture> whose <source> for that breakpoint carries physically cropped derivatives: a phone loads the phone framing (e.g. 588 px) instead of a desktop image it would mostly crop away.
  • Predefined CSS classes — multi-select (chips) per layer from a page-TSconfig list (Bootstrap 5 set); validated against the same whitelist on the frontend (injection-safe).
  • Darkening overlay behind text — adjustable scrim (0–100 %) for readability over busy images.
  • Per-layer TYPO3 link on any layer (native Link Browser).
  • AOS entrance animation per layer (effect, delay, duration).

Templates & export

  • Templates gallery (“Templates” button) — apply a reusable composition to the current collage; shows rendered thumbnails of shipped presets + user templates.
  • Save as template — store the current composition as a tx_herobuilder_template record.
  • Social / OG image export — render the composition to a downloadable image in OG, 16:9, Instagram 1:1 / 4:5 and Story 9:16 formats (ImageMagick, cached).
  • See Templates and Social / OG image export.

Backend editor (3-column, Moveable-based WYSIWYG)

  • Toolbar: title, breakpoint pills (active = accent border), and actions (Add image/text/button, Templates, Save as template, Export image, Live preview toggle).
  • Left — Layer panel: rows with color/thumbnail chip, name, eye (visibility) and lock; drag-reorder the z-stack; right-click for actions (duplicate, align, front/back, delete).
  • Center — Stage: drag / resize / rotate with snapping & guide lines (stage edges/center
    • other layers); zoom badge (Ctrl+wheel cursor-anchored, click = fit ↔ 100 %); pan via scrollbars, middle-mouse or Space+drag.
  • Right — Property tabs, fields per layer type: Content (text, HTML element, link — or for images crop/flip/auto-trim/own framing, fit, focus point for cover/contain, alternative text, link), Design (grouped class chips, text darkening), Position (numeric X/Y/W/H/rotation + arrow-key nudging, align icons, visible on this breakpoint, copy to all breakpoints), Animation (effect, delay, duration, replay). Delete via the layer list, context menu or Del.
  • Undo / redo (100-step history) + keyboard shortcuts.

Quality & i18n

  • Fully localized UI (English source + German de. translation) — TCA, tabs, buttons, canvas panel, context menu, layer list, zoom, templates, export and preview.
  • CSP-safe live preview — no inline <script> (external same-origin JS) and no inline <style> (dynamic CSS delivered as a JSON data island, injected via a constructable stylesheet). Works under a strict backend CSP (script-src 'self', style-src without 'unsafe-inline').

Editor GUI

A single field renders the whole editor in a 3-column grid under a toolbar:

[ Toolbar: title · breakpoint pills · Add image/text/button · Templates · Save as template · Export · Live preview ]
[ left ~230px: LAYERS | center: stage (zoom badge) | right ~340px: Transform · Style · Animation ]
  • Selecting a layer (in the stage or the layer list) fills the right property panel.
  • The Style tab shows only the controls relevant to the layer type (e.g. fit/focus for images, scrim for text, link for all).
  • The live preview and the export both reuse the rendering paths described below.

Templates

Reusable compositions applied to a collage or created from one.

  • Storage — the tx_herobuilder_template table (records editable like any other TYPO3 record; put them in a sysfolder). Plus shipped, read-only presets as JSON under Resources/Private/Templates/Presets/.
  • Gallery — the “Templates” toolbar button opens a modal with a card per template (rendered 21:9 thumbnail + name). Select a card → “Apply template” replaces the current collage’s layers.
  • Save as template — the “Save as template” button stores the current composition as a new tx_herobuilder_template record (via DataHandler) in the folder configured by tx_herobuilder.templatePid (page TSconfig; falls back to the record’s pid — a sysfolder is recommended, see Configuration).
  • Thumbnails are generated by CompositeImageService and cached in typo3temp/assets/herobuilder/.

Social / OG image export

The “Export image” button renders the current composition into a downloadable raster image via ImageMagick (CompositeImageService), cached by a hash of the inputs.

Format Size Use
og 1200×630 Open Graph / Facebook / LinkedIn
wide 1200×675 16:9 (Twitter/X, YouTube)
square 1080×1080 Instagram 1:1
portrait 1080×1350 Instagram 4:5
story 1080×1920 Story / Reel 9:16

For each format the breakpoint whose design ratio is closest is used, so the layout looks intended. Image layers are composited with cover/contain/fill; text/button layers are approximated (font size scales with canvas width, colors/alignment from classes, buttons as a filled box) — CSS-styled text can’t be reproduced pixel-perfectly by ImageMagick, which is acceptable for share images/thumbnails. Requires ImageMagick ($GLOBALS['TYPO3_CONF_VARS']['GFX']['processor_path']).

Data model

tt_content (CType herobuilder, carousel settings) → 1:n tx_herobuilder_collage (one row per slide). Each collage stores its layer geometry in composition (JSON):

{
  "layers": [
    {
      "id": "bg",
      "type": "image",
      "fileUid": 71877,
      "alt": "",
      "link": "",
      "fit": "cover",
      "focusX": 50,
      "focusY": 50,
      "overlay": 0,
      "locked": false,
      "anim": { "effect": "fade-up", "delay": 200, "duration": 600 },
      "placements": {
        "xs": { "x": 0, "y": 0, "w": 100, "h": 100, "rot": 0, "z": 1, "visible": true }
      }
    },
    {
      "id": "t1",
      "type": "text",
      "text": "DEV LAND 2026",
      "cssClass": "display-3 text-white fw-bold text-center",
      "overlay": 55,
      "placements": { "lg": { "x": 20, "y": 60, "w": 60, "h": 12, "rot": 0, "z": 3, "visible": true } }
    },
    {
      "id": "b1",
      "type": "button",
      "text": "Register now",
      "cssClass": "btn btn-primary",
      "link": "t3://page?uid=42",
      "placements": { "lg": { "x": 40, "y": 75, "w": 20, "h": 8, "rot": 0, "z": 4, "visible": true } }
    }
  ]
}

Field notes:

  • type — "image" (default), "text" or "button".
  • tag — HTML element of a text layer: p, h1–h6 (whitelisted; absent = div).
  • text — label (text/button layers). link — TYPO3 link (t3://…), works on any layer; a button is rendered as an <a> typolink.
  • fit — fill | cover | contain (image layers).
  • focusX / focusY — 0–100 %, → object-position (image layers).
  • cssClass — space-separated, whitelisted predefined classes.
  • overlay — 0–100 %, dark scrim behind text.
  • locked — layer locked in the editor (not draggable).
  • placements[<bp>] — x,y,w,h (%), rot (deg), z, visible; optionally image: {crop, focusX, focusY} — the breakpoint's own framing (art direction), overriding the layer's crop / focusX / focusY there.

tx_herobuilder_template holds the same composition JSON plus a title and an indicator color; presets are shipped as JSON ({title, color, layers}).

Installation

composer require wapplersystems/herobuilder
vendor/bin/typo3 extension:setup   # or activate in the Extension Manager

Then add a Hero Builder content element on any page and open its Collages tab.

Configuration

Stage aspect ratios (TypoScript constants)

Frontend stage ratio per breakpoint (W:H):

plugin.tx_herobuilder.settings.stages {
    xs.ratio  = 9:16
    sm.ratio  = 3:4
    md.ratio  = 16:9
    lg.ratio  = 21:9
    xl.ratio  = 21:9
    xxl.ratio = 21:9
}

The backend editor additionally renders each breakpoint at a realistic reference device width (defaults: xs 390, sm 576, md 768, lg 992, xl 1200, xxl 1400 px).

Fixed stage height (page TSconfig + content element)

Per content element, Stage height (tt_content.stage_mode, tab Collages) switches between Aspect ratio (default, above) and Fixed height. The heights are a site setting:

tx_herobuilder.stages {
    xs.height = 43rem
    lg.height = 55rem
}

Heights are inherited upwards (here: xs–md 43rem, lg and above 55rem); a breakpoint without a height keeps its ratio. Only px and rem are accepted (rem converted at 16px), so the editor can show the stage exactly as the frontend renders it at the reference width. The width stays fluid in the frontend — layers keep their % positions, so between reference widths their proportions shift (as with any fixed-height slider). The canvas follows a change of the field immediately, before the record is saved.

Composition format version and links

The editor writes "version": 1 into the composition JSON (Composition::VERSION). JSON without a version is version 1. When the shape changes incompatibly, raise the constant and add the step to Composition::migrate() — stored collages and templates are then brought forward on read.

Links live on layers only: one link per layer, rendered as an <a> around that layer — never nested. A link on a full-stage background layer makes the whole slide clickable while the buttons on top keep their own links. (A separate "slide link" field existed earlier but was never rendered; it is gone from the form, its database column is left in place.)

Image layers take their alternative text from the file's metadata; the editor shows it as the placeholder of the "Alternative text" field, and a text entered there overrides it for that layer only. The panel warns about a button without a link (not clickable) and a linked image without any alternative text (a link without a name for screen readers).

Predefined layer classes (page TSconfig)

Selectable per layer in the editor and used as the frontend whitelist. One list per layer type — the editor only offers a layer the classes of its type, and the frontend only renders a class on a layer of that type. Override or extend per site.

tx_herobuilder.layerClasses {
    text {
        display-1       = Display 1 (XXL)
        fw-bold         = Bold
        text-bg-primary = Box: primary
        # …
    }
    button {
        btn         = Button base
        btn-primary = Button: primary
        # …
    }
    image {
        rounded-3 = Rounded
        shadow    = Shadow
    }
    # Entries directly under layerClasses (the original flat format) apply to every type.
}

The shipped set covers Bootstrap text utilities, btn/btn-* for buttons and a few image utilities. A class stored on a layer that is not (or no longer) offered for its type shows as "not available" in the editor and is not rendered. Class names may use any utility syntax (md:text-lg, w-1/2); whitespace, quotes and <> are rejected.

Class groups in the editor (page TSconfig)

Optional presentation for the class chips — the whitelist stays layerClasses. Per layer type, numbered groups with a label, a comma list of classes, exclusive = 1 (selecting one class deselects the others of the group) and background = 1 (the classes set the layer background; the text darkening is locked while one of them is selected). Offered classes in no group appear under "More"; without any group configuration the chips stay one plain list.

tx_herobuilder.layerClassGroups.text {
    10 {
        label = Size
        exclusive = 1
        classes = display-1, display-3, fs-1, fs-5
    }
    50 {
        label = Box
        exclusive = 1
        background = 1
        classes = text-bg-primary, text-bg-dark
    }
}

Frame and spacing (TypoScript constant)

The hero renders inside the theme's Default content layout — frame with anchor id, spacing, container, header, background — like any other content element. In a theme's full-bleed hero area that frame would box the hero in, so list those columns in a constant; there the hero renders bare (layout HeroPlain):

# T3Bootstrap's hero area is colPos 5. Empty (default): every hero uses the Default layout.
plugin.tx_herobuilder.settings.framelessColPos = 5

New hero elements start with a hidden header (header_layout = 100), so their title does not appear above the stage unless an editor chooses so.

Overriding the templates

The extension's template, partial and layout paths sit at index 1 of lib.contentElement's templateRootPaths / partialRootPaths / layoutRootPaths — below the theme (T3Bootstrap: 5) and the site's own paths (10). A site overrides Hero.html or the Slide / Layer partials by providing them in its own path; its own Header/… partials and Default layout apply to the hero as well.

The site's own paths come from styles.templates.templateRootPath / partialRootPath / layoutRootPath. With site sets (TYPO3 13+) these are site settings of the Fluid Styled Content set: set them in the site's settings.yaml, not as TypoScript constants — a site setting wins over a constant of the same name, so a constant has no effect.

Template storage folder (page TSconfig)

Where “Save as template” stores tx_herobuilder_template records. Templates are global (listed regardless of pid); point this at a sysfolder. Falls back to the record’s pid if unset.

tx_herobuilder.templatePid = 123

Image format (page TSconfig)

Image layer derivatives are written as WebP by default — several times smaller than PNG cut-outs, with their transparency kept. SVG and GIF sources are never converted.

tx_herobuilder.imageFormat = webp     # default; "original" keeps the source format

The format must be listed in $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] and writable by the configured processor — otherwise the source format is used. (GraphicsMagick usually reads AVIF but cannot write it.)

Live-preview stylesheets (page TSconfig)

CSS pulled into the live-preview iframe so it looks like the frontend. The extension always adds its own hero.css/aos.css; add the site's compiled theme CSS here (absolute URLs used as-is, EXT:/site-relative paths resolved and skipped if missing).

tx_herobuilder.previewCss {
    10 = /typo3temp/assets/css/mytheme.css
    20 = EXT:my_sitepackage/Resources/Public/Css/fonts.css
}

Keyboard shortcuts

Active while the stage/editor is focused.

Shortcut Action
Arrow keys Nudge selected layer 1 % (Shift = 5 %)
Delete / Backspace Delete selected layer
Ctrl/⌘ + Z Undo
Ctrl/⌘ + Y / Ctrl/⌘ + Shift + Z Redo
Ctrl/⌘ + D Duplicate selected layer
Ctrl/⌘ + + / − / 0 Zoom in / out / reset
Ctrl/⌘ + wheel Zoom (anchored at cursor)
Middle-mouse drag · Space + drag Pan the stage
Right-click Context menu (align, fill stage, z-order, …)

Architecture

Backend

  • Backend/Form/Element/CanvasElement — custom FormEngine node herobuilderCanvas (renderType), builds the toolbar/stage/panel and hands localized labels + config to the JS.
  • Resources/Public/JavaScript/Backend/canvas.js — the Moveable-based editor (breakpoint tabs, layers, panel, layer list, snap, zoom/pan, undo/redo, context menu, live-preview driver).
  • AJAX routes: herobuilder_fileinfo (FAL uids → URL/dimensions), herobuilder_preview (composition → HTML document for the iframe), herobuilder_template_list / herobuilder_template_save (templates), herobuilder_export (composition → social/OG image).
  • Backend/Controller/PreviewController — renders the unsaved composition via the shared CompositionProcessor::expand() + the Preview.html partial, CSP-safe (see above).
  • Backend/Controller/TemplateController — lists presets + tx_herobuilder_template records (with thumbnails) and saves new templates via DataHandler.
  • Backend/Controller/ExportController — renders a chosen social/OG format via CompositeImageService.
  • Service/CompositeImageService — flattens a composition to a cached PNG via ImageMagick (used for template thumbnails and export).
  • Backend/Preview/HeroBuilderPreviewRenderer — page-module preview.
  • Records/config: tx_herobuilder_template (table + TCA, allowed on standard pages), presets in Resources/Private/Templates/Presets/*.json.
  • The templates gallery ships its styles inline (GALLERY_CSS in canvas.js) because the TYPO3 modal renders in the top document, where the field stylesheet is not loaded.

Frontend

  • DataProcessing/CompositionProcessor — resolves FAL layers and generates the scoped per-breakpoint CSS (geometry, object-fit, object-position, text scrim, class whitelist) and the image layers' srcset / sizes.
  • Domain/Composition — the composition value object (breakpoints, default stage ratios/widths, JSON parsing incl. text layers).
  • Templates: Templates/Hero.html (carousel) → Partials/Slide.html → Partials/Layer.html; Partials/Preview.html (style-less variant for the CSP-safe live preview).
  • Assets: Css/hero.css, Css/aos.css, JavaScript/hero.js (AOS init), JavaScript/preview-frame.js (in-iframe CSS injection + AOS replay).

Localization — Resources/Private/Language/locallang_db.xlf (en, source) and de.locallang_db.xlf (German). JS strings are localized via a labels payload from PHP.