Focal Point Editor 

Extension key

nnfocalpoint

Package name

nng/nnfocalpoint

Version

main

Language

en

Author

99grad

Email

info@99grad.de

License

This document is published under the GNU General Public License v2.0 or later

Rendered

Fri, 12 Dec 2025 11:00:30 +0000


The Focal Point Editor extension adds an interactive focal point editor to TYPO3's file references (sys_file_reference). It allows editors to define focus points for different crop variants, ensuring that the most important part of an image remains visible regardless of how the image is cropped or displayed.


Table of Contents

Introduction 

What does it do? 

The Focal Point Editor extension enhances TYPO3's native image handling by allowing editors to define focal points for images. A focal point marks the most important area of an image – the part that should always remain visible, regardless of how the image is cropped or scaled.

This is particularly useful for:

  • Responsive images: Ensure the subject of a photo remains visible across all device sizes and aspect ratios
  • Portrait photography: Keep faces visible when images are cropped
  • Product images: Ensure the product remains centered in all crop variants
  • Hero images: Maintain focus on key visual elements across different layouts

Features 

  • Interactive Editor: Click directly on the image to set the focal point
  • Per-Variant Focal Points: Define different focal points for each crop variant (e.g., landscape, portrait, square)
  • Visual Feedback: See focal points displayed on crop previews in the backend
  • Fluid ViewHelpers: Easy integration with global nnfp namespace
  • Drop-in f:image Replacement: <nnfp:image> adds focal point styling automatically
  • Background Image Support: <nnfp:backgroundStyle> for hero sections
  • CSS Object-Position: Generate CSS object-position values automatically
  • Non-Destructive: Focal points are stored separately from the image and crop data

How it works 

The extension adds a new field to sys_file_reference that stores focal point coordinates as JSON. Each crop variant can have its own focal point, stored as percentage-based coordinates (0-1 range):

{
  "default": {"x": 0.5, "y": 0.3},
  "landscape": {"x": 0.9, "y": 0.712},
  "portrait": {"x": 0.2, "y": 0.5}
}
Copied!

The coordinates represent:

  • x: 0 = left edge, x: 1 = right edge
  • y: 0 = top edge, y: 1 = bottom edge

Screenshots 

Backend Editor 

The focal point editor appears below the crop options in the file reference editing form. Click the "Fokus-Punkt bearbeiten" button to open the modal editor. The focal point is displayed as a visual indicator on each crop variant preview.

Backend button with focal point preview

The "Fokus-Punkt bearbeiten" button appears below the crop variants, showing a preview of the focal point position on each crop.

Frontend Result 

Using the ViewHelpers, the focal point is applied via CSS object-position. This ensures the important part of the image remains visible regardless of container size.

Frontend result with scaled container

The focal point keeps the subject visible when the container is scaled or the image is displayed in different aspect ratios.

Use Cases 

Responsive Hero Images 

A hero image might be displayed as a wide banner on desktop but as a square on mobile. By setting appropriate focal points for each variant, you ensure the subject remains visible in both cases.

Portrait Galleries 

When displaying portraits in different aspect ratios (e.g., 3:4 for cards, 1:1 for avatars), focal points ensure faces are always visible and properly positioned.

E-Commerce Product Images 

Product images often need to be displayed in various formats. Focal points help maintain product visibility across different layouts and crop variants.

Installation 

Requirements 

  • TYPO3 12.4 LTS or TYPO3 13.x
  • PHP 8.2 or higher

Classic Installation 

  1. Download the extension from the TYPO3 Extension Repository (TER) or GitHub
  2. Extract the archive to typo3conf/ext/nnfocalpoint
  3. Activate the extension in the Extension Manager

Database Update 

After installation, you need to update the database schema:

  1. Go to Admin Tools → Maintenance → Analyze Database Structure
  2. Apply the suggested changes to add the tx_nnfocalpoint_points field to sys_file_reference

Alternatively, run the following SQL manually:

ALTER TABLE sys_file_reference ADD tx_nnfocalpoint_points text;
Copied!

Verification 

After installation, verify the extension is working correctly:

  1. Go to any content element with an image (e.g., Text & Media)
  2. Edit the image reference
  3. You should see a "Fokus-Punkt bearbeiten" button below the crop options

Upgrading 

From earlier versions 

When upgrading from an earlier version:

  1. Update the extension files
  2. Clear all caches
  3. Run the Database Analyzer to apply any schema changes

Configuration 

The Focal Point Editor extension works out of the box with minimal configuration. This chapter covers the technical configuration and customization options.

TCA Configuration 

The extension automatically adds the focal point field to sys_file_reference through TCA overrides.

Default Configuration 

The field is added to the imageoverlayPalette after the crop field:

Configuration/TCA/Overrides/sys_file_reference.php
$newSysFileReferenceColumns = [
    'tx_nnfocalpoint_points' => [
        'label' => 'Fokus-Punkte',
        'config' => [
            'type' => 'user',
            'renderType' => 'focalPointElement',
        ],
    ],
];

\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns(
    'sys_file_reference',
    $newSysFileReferenceColumns
);

\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette(
    'sys_file_reference',
    'imageoverlayPalette',
    '--linebreak--,tx_nnfocalpoint_points',
    'after:crop'
);
Copied!

Custom Palettes 

If you want to add the focal point field to a custom palette, use:

\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette(
    'sys_file_reference',
    'yourCustomPalette',
    'tx_nnfocalpoint_points',
    'after:crop'
);
Copied!

Crop Variants 

The focal point editor automatically reads the crop variants defined in your TCA configuration. Each crop variant gets its own focal point.

Example crop variant configuration:

Configuration/TCA/Overrides/tt_content.php
$GLOBALS['TCA']['tt_content']['columns']['image']['config']['overrideChildTca']['columns']['crop']['config'] = [
    'cropVariants' => [
        'default' => [
            'title' => 'Default',
            'allowedAspectRatios' => [
                '16:9' => ['title' => '16:9', 'value' => 16 / 9],
                '4:3' => ['title' => '4:3', 'value' => 4 / 3],
                'free' => ['title' => 'Free', 'value' => 0.0],
            ],
        ],
        'mobile' => [
            'title' => 'Mobile',
            'allowedAspectRatios' => [
                '1:1' => ['title' => 'Square', 'value' => 1.0],
                '3:4' => ['title' => 'Portrait', 'value' => 3 / 4],
            ],
        ],
    ],
];
Copied!

With this configuration, the focal point editor will show two variants: "Default" and "Mobile", each with its own focal point.

JavaScript Module 

The JavaScript module is registered in Configuration/JavaScriptModules.php:

Configuration/JavaScriptModules.php
return [
    'dependencies' => ['core', 'backend'],
    'imports' => [
        '@nng/nnfocalpoint/' => 'EXT:nnfocalpoint/Resources/Public/JavaScript/',
    ],
];
Copied!

AJAX Routes 

The extension registers two AJAX routes for the backend modal:

Configuration/Backend/AjaxRoutes.php
return [
    'nnfocalpoint_wizard' => [
        'path' => '/nnfocalpoint/wizard',
        'target' => FocalPointController::class . '::wizardAction',
    ],
    'nnfocalpoint_image' => [
        'path' => '/nnfocalpoint/image',
        'target' => FocalPointController::class . '::imageAction',
    ],
];
Copied!

Styling 

The extension includes CSS for the backend editor. The stylesheet is loaded globally in the backend via ext_localconf.php:

ext_localconf.php
$GLOBALS['TYPO3_CONF_VARS']['BE']['stylesheets']['nnfocalpoint'] =
    'EXT:nnfocalpoint/Resources/Public/Css/FocalPointEditor.css';
Copied!

Custom Styling 

To customize the appearance of the focal point editor, you can override the CSS classes in your own backend stylesheet:

  • .nnfocalpoint-container - Main container
  • .nnfocalpoint-trigger - The button to open the editor
  • .nnfocalpoint-modal - Modal container
  • .nnfocalpoint-thumbnails - Thumbnail row
  • .nnfocalpoint-thumbnail - Individual thumbnail
  • .nnfocalpoint-editor - Editor area
  • .nnfocalpoint-image-container - Image container
  • .nnfocalpoint-point - Focal point marker

Editor's Guide 

This chapter explains how to use the Focal Point Editor in the TYPO3 backend.

Accessing the Focal Point Editor 

The focal point editor is available for any image that is added to a content element or other record through a file reference.

  1. Edit a content element that contains an image (e.g., Text & Media)
  2. Click on the image to expand its settings
  3. Look for the "Fokus-Punkt bearbeiten" button below the crop options
  4. Click the button to open the focal point editor modal
Backend button location

The focal point button appears below the crop variant previews. Existing focal points are shown as indicators on each crop preview.

The Focal Point Modal 

The modal window consists of two main areas:

Thumbnail Row 

At the top of the modal, you see thumbnails for each available crop variant. These correspond to the crop variants defined in your TYPO3 configuration (e.g., "Default", "Mobile", "Portrait").

  • Click a thumbnail to select that crop variant
  • Green dot indicator shows which variants have a focal point set
  • Blue border indicates the currently selected variant

Editor Area 

The main area shows the full image with a semi-transparent overlay indicating the current crop area.

  • Click anywhere on the image to set the focal point
  • The focal point is shown as a pulsing circle
  • The overlay helps you see which part of the image will be visible in the crop
Focal point modal editor

The modal editor with crop variant thumbnails at the top and the main editing area below. Click on the image to set the focal point.

Setting a Focal Point 

  1. Open the focal point editor modal
  2. Select the crop variant you want to edit (click its thumbnail)
  3. Click on the image where you want the focal point to be
  4. The focal point marker appears at your click position
  5. Repeat for other crop variants if needed
  6. Click "Speichern" (Save) to save your changes

Removing a Focal Point 

To remove a focal point from a crop variant:

  1. Select the crop variant
  2. Click the "Fokus-Punkt entfernen" button at the bottom of the editor
  3. The focal point marker disappears
  4. Save your changes

Visual Feedback 

After saving, the focal point is displayed on the crop preview thumbnails in the file reference form. This gives you immediate visual feedback about where the focal point is positioned relative to each crop.

Best Practices 

Choosing the Right Focal Point 

  • Portraits: Set the focal point on the subject's face, typically between the eyes
  • Products: Center the focal point on the main product
  • Landscapes: Choose the most important element (e.g., a building, person, or natural feature)
  • Text overlays: Consider where text will be placed and avoid setting focal points in those areas

Working with Multiple Variants 

  • Start with the most restrictive crop (usually the smallest or most square)
  • Ensure the focal point works well for that crop
  • Then adjust other variants as needed
  • Preview your changes in the frontend to verify the result

Troubleshooting 

Button not visible 

If the "Fokus-Punkt bearbeiten" button is not visible:

  • Ensure the extension is properly installed and activated
  • Check that the database field tx_nnfocalpoint_points exists in sys_file_reference
  • Clear all TYPO3 caches

Focal point not saved 

If focal points are not being saved:

  • Ensure you click "Speichern" in the modal
  • Save the parent record (content element) after closing the modal
  • Check for any form validation errors

Developer's Guide 

This chapter covers the technical aspects of integrating the Focal Point Editor in your TYPO3 templates and custom extensions.

Namespace 

The extension uses the namespace:

Nng\Nnfocalpoint
Copied!

ViewHelpers 

The extension provides six ViewHelpers for easy frontend integration.

CSS Styles 

The extension includes a frontend CSS file with basic styles. Include it via TypoScript:

page.includeCSS.nnfocalpoint = EXT:nnfocalpoint/Resources/Public/Css/Frontend.css
Copied!

Or include the static TypoScript "Focal Point Editor" in your template.

Available CSS classes:

  • .nnfp-image - Automatically added to images from nnfp:image (width/height 100%, display block)
  • .nnfp-container - Container with overflow hidden for focal point images
  • .nnfp-container--16-9, --4-3, --1-1, --3-2, --21-9 - Aspect ratio helpers
  • .nnfp-bg - Background image helper (background-size: cover, no-repeat)

Registering the Namespace 

The extension registers a global namespace nnfp automatically. You can use the ViewHelpers without any namespace declaration:

<!-- Global namespace - no declaration needed -->
<nnfp:image image="{image}" width="400" />
<div style="{nnfp:backgroundStyle(image: image)}">
Copied!

Alternatively, you can use the full namespace declaration:

{namespace nnfocalpoint=Nng\Nnfocalpoint\ViewHelpers}
Copied!

Or use the XML namespace syntax:

<html xmlns:nnfocalpoint="http://typo3.org/ns/Nng/Nnfocalpoint/ViewHelpers"
      data-namespace-typo3-fluid="true">
Copied!

ImageViewHelper (Drop-in f:image replacement) 

A drop-in replacement for f:image that automatically adds focal point styling. All standard f:image arguments are supported.

Class: Nng\Nnfocalpoint\ViewHelpers\ImageViewHelper

Additional Arguments:

Argument Type Required Description
objectFit string No CSS object-fit value (default: cover)
disableFocalPoint bool No Set to true to disable focal point styling

Usage:

<!-- Simple usage - replaces f:image -->
<nnfp:image image="{image}" width="400" height="300" />

<!-- With crop variant -->
<nnfp:image image="{image}" width="800c" height="600c" cropVariant="mobile" />

<!-- With custom object-fit -->
<nnfp:image image="{image}" width="400" objectFit="contain" />

<!-- Disable focal point (use as regular f:image) -->
<nnfp:image image="{image}" width="400" disableFocalPoint="true" />
Copied!

Output:

<img src="/fileadmin/_processed_/image.jpg" 
     width="400" height="300"
     class="nnfp-image"
     style="object-fit: cover; object-position: 50% 30%;" />
Copied!

FocalCropViewHelper (Server-side focal crop) 

Crops images to exact dimensions while keeping the focal point centered. Unlike nnfp:image which uses CSS positioning, this ViewHelper performs actual server-side cropping - the generated image file has the exact target dimensions.

Class: Nng\Nnfocalpoint\ViewHelpers\FocalCropViewHelper

Arguments:

Argument Type Required Description
image object Yes The file reference object
width string No Width specification (append "c" for crop)
height string No Height specification (append "c" for crop)
cropVariant string No Crop variant for focal point lookup (default: default)
absolute bool No Force absolute URL (default: false)

Usage:

<!-- Crop to 400x200, focal point centered horizontally -->
<nnfp:focalCrop image="{image}" width="400c" height="200" />

<!-- Square crop -->
<nnfp:focalCrop image="{image}" width="200c" height="200c" />

<!-- With specific crop variant -->
<nnfp:focalCrop image="{image}" width="800c" height="600" cropVariant="mobile" />
Copied!

How it works:

The "c" suffix indicates that dimension should be cropped. The ViewHelper:

  1. Calculates the target aspect ratio (e.g., 400:200 = 2:1)
  2. Crops the original image to match that aspect ratio, centered on the focal point
  3. Scales the cropped result to the final dimensions

Example: For a 1200x800 image with focal point at (0.7, 0.3):

  • width="400c" height="200" creates a 2:1 crop (800x400 from original)
  • The crop window is positioned to keep the focal point (at x=840, y=240) as centered as possible
  • Result is scaled to 400x200

Output:

<img src="/fileadmin/_processed_/image_cropped.jpg" 
     width="400" height="200" />
Copied!

Replacing CropVariants with FocalCrop 

The nnfp:focalCrop ViewHelper can largely replace the need for multiple crop variants. Traditional TYPO3 crop variants require editors to manually define crop areas for each aspect ratio (desktop, tablet, mobile, square, etc.). This is time-consuming and error-prone.

With focal points, you can simplify this workflow:

  1. Use only the default crop variant in your TCA configuration
  2. Let editors set a single focal point on the important part of the image
  3. Use nnfp:focalCrop with different dimensions - the focal point stays centered automatically

Before (traditional approach):

<!-- Editor must define 4 different crop areas -->
<f:image image="{image}" cropVariant="desktop" width="1920c" height="600c" />
<f:image image="{image}" cropVariant="tablet" width="1024c" height="768c" />
<f:image image="{image}" cropVariant="mobile" width="768c" height="768c" />
<f:image image="{image}" cropVariant="square" width="400c" height="400c" />
Copied!

After (with focal point):

<!-- Editor sets ONE focal point, all crops are calculated automatically -->
<nnfp:focalCrop image="{image}" width="1920c" height="600" />  <!-- wide banner -->
<nnfp:focalCrop image="{image}" width="1024c" height="768" />  <!-- 4:3 -->
<nnfp:focalCrop image="{image}" width="768c" height="768" />   <!-- square -->
<nnfp:focalCrop image="{image}" width="400c" height="600" />   <!-- portrait -->
Copied!

Benefits:

  • Less editor work: One focal point instead of multiple crop definitions
  • Consistent results: The important subject stays visible in all aspect ratios
  • Flexible frontend: Developers can use any aspect ratio without backend changes
  • Simpler TCA: No need to configure multiple crop variants

Uri\FocalCropViewHelper (URI only) 

Returns only the URI of a focal-point-cropped image. Use this when you need the image URL for custom markup, srcset, or JavaScript.

Class: Nng\Nnfocalpoint\ViewHelpers\Uri\FocalCropViewHelper

Arguments: Same as FocalCropViewHelper

Usage:

<!-- In custom img tag -->
<img src="{nnfp:uri.focalCrop(image: image, width: '400c', height: '200')}" 
     alt="{image.alternative}" />

<!-- In srcset -->
<img src="{nnfp:uri.focalCrop(image: image, width: '400c', height: '200')}"
     srcset="{nnfp:uri.focalCrop(image: image, width: '400c', height: '200')} 1x,
             {nnfp:uri.focalCrop(image: image, width: '800c', height: '400')} 2x" />

<!-- As CSS background -->
<div style="background-image: url('{nnfp:uri.focalCrop(image: image, width: '1920c', height: '600')}')">
</div>

<!-- With absolute URL -->
{nnfp:uri.focalCrop(image: image, width: '400c', height: '200', absolute: 1)}
Copied!

Output:

/fileadmin/_processed_/csm_image_abc123.jpg
Copied!

BackgroundStyleViewHelper 

Returns a complete style attribute value for background images with focal point. Use this for divs or other elements with background images.

Class: Nng\Nnfocalpoint\ViewHelpers\BackgroundStyleViewHelper

Arguments:

Argument Type Required Description
image mixed Yes The file reference object or array
cropVariant string No The crop variant (default: default)
width string No Width for image processing (e.g., "1920" or "1920c")
height string No Height for image processing
backgroundSize string No CSS background-size value (default: cover)
includeRepeat bool No Include background-repeat: no-repeat (default: true)
fallbackPosition string No Fallback position if no focal point (default: 50% 50%)

Usage:

<!-- Simple usage -->
<div style="{nnfp:backgroundStyle(image: image)}">
    Content here
</div>

<!-- With image processing -->
<div class="hero" style="{nnfp:backgroundStyle(image: image, width: '1920')}">
    <h1>Hero Title</h1>
</div>

<!-- With crop variant -->
<div style="{nnfp:backgroundStyle(image: image, cropVariant: 'hero', width: '1920')}">
    Content
</div>

<!-- Custom background-size -->
<div style="{nnfp:backgroundStyle(image: image, backgroundSize: 'contain')}">
    Content
</div>
Copied!

Output:

<div style="background-image: url('/fileadmin/image.jpg'); background-size: cover; background-position: 50% 30%; background-repeat: no-repeat">
    Content here
</div>
Copied!

ObjectPositionViewHelper 

Returns a CSS object-position value based on the focal point coordinates.

Class: Nng\Nnfocalpoint\ViewHelpers\ObjectPositionViewHelper

Arguments:

Argument Type Required Description
image mixed Yes The file reference object or array
cropVariant string No The crop variant to get the focal point for (default: default)
fallback string No Fallback value if no focal point is set (default: 50% 50%)

Usage:

<img src="{image.publicUrl}"
     style="object-fit: cover; object-position: {nnfp:objectPosition(image: image, cropVariant: 'default')}" />
Copied!

Output:

<img src="/fileadmin/image.jpg"
     style="object-fit: cover; object-position: 50% 30%" />
Copied!

With fallback:

<img src="{image.publicUrl}"
     style="object-fit: cover; object-position: {nnfp:objectPosition(image: image, fallback: 'center top')}" />
Copied!

FocalPointViewHelper 

Returns the raw focal point data for a specific crop variant.

Class: Nng\Nnfocalpoint\ViewHelpers\FocalPointViewHelper

Arguments:

Argument Type Required Description
image mixed Yes The file reference object or array
cropVariant string No The crop variant to get the focal point for (default: default)
as string No Variable name to assign the focal point to

Usage (inline):

<f:debug>{nnfp:focalPoint(image: image, cropVariant: 'default')}</f:debug>
Copied!

Usage (with variable):

<nnfp:focalPoint image="{image}" cropVariant="default" as="fp">
    <f:if condition="{fp}">
        <p>Focal point: {fp.x} / {fp.y}</p>
        <div style="position: absolute; left: {fp.x * 100}%; top: {fp.y * 100}%;"></div>
    </f:if>
</nnfp:focalPoint>
Copied!

Return value:

Returns an array with x and y keys (values 0-1), or null if no focal point is set:

['x' => 0.5, 'y' => 0.3]
Copied!

Data Format 

Focal points are stored in the sys_file_reference.tx_nnfocalpoint_points field as a JSON string:

{
  "default": {"x": 0.5, "y": 0.3},
  "landscape": {"x": 0.9, "y": 0.712},
  "portrait": {"x": 0.2, "y": 0.5}
}
Copied!

Coordinate System:

  • x: 0 = left edge
  • x: 1 = right edge
  • y: 0 = top edge
  • y: 1 = bottom edge
  • x: 0.5, y: 0.5 = center of the image

Accessing Focal Points in PHP 

From FileReference Object 

use TYPO3\CMS\Core\Resource\FileReference;

/** @var FileReference $image */
$focalPointsJson = $image->getProperty('tx_nnfocalpoint_points');
$focalPoints = json_decode($focalPointsJson, true) ?: [];

// Get focal point for a specific variant
$defaultFocalPoint = $focalPoints['default'] ?? null;
if ($defaultFocalPoint) {
    $x = $defaultFocalPoint['x'];
    $y = $defaultFocalPoint['y'];
}
Copied!

From Extbase FileReference 

use TYPO3\CMS\Extbase\Domain\Model\FileReference;

/** @var FileReference $image */
$originalResource = $image->getOriginalResource();
$focalPointsJson = $originalResource->getProperty('tx_nnfocalpoint_points');
$focalPoints = json_decode($focalPointsJson, true) ?: [];
Copied!

Custom Integration Examples 

The following examples show how to use the focal point data in your templates. The result ensures that the important part of the image remains visible when the container is scaled or cropped.

Frontend result with focal point

Using object-position with the focal point coordinates keeps the subject visible regardless of container dimensions.

Required CSS 

For focal points to work correctly, you need CSS that allows the image to be positioned within its container. Here are the essential styles:

/* Basic focal point container */
.focal-container {
    position: relative;
    overflow: hidden;
}

/* Image with focal point - fills container and respects focal point */
.focal-container img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* object-position is set inline via ViewHelper */
}

/* Fixed aspect ratio containers */
.focal-container--16-9 {
    aspect-ratio: 16 / 9;
}

.focal-container--4-3 {
    aspect-ratio: 4 / 3;
}

.focal-container--1-1 {
    aspect-ratio: 1 / 1;
}

/* Background image with focal point */
.focal-bg {
    background-size: cover;
    background-repeat: no-repeat;
    /* background-position is set inline via ViewHelper */
}
Copied!

Example 1: Simple IMG Tag 

The most basic usage with a standard <img> tag:

<!-- Basic usage -->
<div class="focal-container" style="width: 300px; height: 200px;">
    <img src="{image.publicUrl}" 
         alt="{image.alternative}"
         style="object-fit: cover; object-position: {nnfp:objectPosition(image: image)}" />
</div>

<!-- With aspect ratio class -->
<div class="focal-container focal-container--16-9" style="width: 100%; max-width: 800px;">
    <img src="{image.publicUrl}" 
         alt="{image.alternative}"
         style="object-fit: cover; object-position: {nnfp:objectPosition(image: image, cropVariant: 'default')}" />
</div>
Copied!

Example 2: Using f:image ViewHelper 

Combine TYPO3's f:image ViewHelper with focal point positioning:

<!-- f:image with focal point -->
<div class="focal-container" style="width: 400px; height: 300px;">
    <f:image image="{image}" 
             alt="{image.alternative}"
             width="800" 
             style="object-fit: cover; object-position: {nnfp:objectPosition(image: image)}" />
</div>

<!-- f:image with crop variant -->
<div class="focal-container focal-container--4-3">
    <f:image image="{image}" 
             cropVariant="mobile"
             width="600c" 
             height="450c"
             style="object-fit: cover; object-position: {nnfp:objectPosition(image: image, cropVariant: 'mobile')}" />
</div>
Copied!

Example 3: Background Images 

Use focal points with CSS background images:

<!-- Simple background image -->
<div class="hero focal-bg" 
     style="height: 400px; 
            background-image: url('{image.publicUrl}'); 
            background-position: {nnfp:objectPosition(image: image)};">
    <h1>Hero Title</h1>
</div>

<!-- With f:uri.image for processed images -->
<div class="hero focal-bg" 
     style="height: 500px; 
            background-image: url('{f:uri.image(image: image, width: 1920)}'); 
            background-position: {nnfp:objectPosition(image: image, cropVariant: 'hero')};">
    <div class="hero__content">
        <h1>{headline}</h1>
        <p>{subheadline}</p>
    </div>
</div>
Copied!

CSS for the hero section:

.hero {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    color: white;
    text-align: center;
}

.hero::before {
    content: '';
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.4);
}

.hero__content {
    position: relative;
    z-index: 1;
    padding: 2rem;
}
Copied!

Example 4: Custom Logic with FocalPoint ViewHelper 

For advanced use cases, access the raw focal point data:

<nnfp:focalPoint image="{image}" cropVariant="default" as="fp">
    <f:if condition="{fp}">
        <f:then>
            <!-- Display focal point coordinates -->
            <p class="debug">Focal point: X={fp.x}, Y={fp.y}</p>
            
            <!-- Use in calculations -->
            <div class="image-with-hotspot" style="position: relative;">
                <img src="{image.publicUrl}" alt="" />
                
                <!-- Hotspot marker at focal point -->
                <span class="hotspot" 
                      style="left: {fp.x * 100}%; top: {fp.y * 100}%;">
                </span>
            </div>
            
            <!-- Conditional positioning based on focal point location -->
            <f:if condition="{fp.x} < 0.5">
                <f:then>
                    <div class="text-overlay text-overlay--right">
                        Text on right (focal point is on left)
                    </div>
                </f:then>
                <f:else>
                    <div class="text-overlay text-overlay--left">
                        Text on left (focal point is on right)
                    </div>
                </f:else>
            </f:if>
        </f:then>
        <f:else>
            <!-- Fallback when no focal point is set -->
            <img src="{image.publicUrl}" alt="" style="object-position: center center;" />
        </f:else>
    </f:if>
</nnfp:focalPoint>
Copied!

CSS for hotspot marker:

.image-with-hotspot {
    position: relative;
    display: inline-block;
}

.hotspot {
    position: absolute;
    width: 20px;
    height: 20px;
    background: rgba(255, 0, 0, 0.7);
    border: 2px solid white;
    border-radius: 50%;
    transform: translate(-50%, -50%);
    pointer-events: none;
    animation: pulse 2s infinite;
}

@keyframes pulse {
    0%, 100% { transform: translate(-50%, -50%) scale(1); }
    50% { transform: translate(-50%, -50%) scale(1.2); }
}
Copied!

Example 5: Responsive Images with Picture Element 

Different focal points for different crop variants:

<picture>
    <!-- Mobile: square crop with mobile focal point -->
    <source media="(max-width: 767px)"
            srcset="{f:uri.image(image: image, cropVariant: 'mobile', width: '767c', height: '767c')}" />
    
    <!-- Tablet: 4:3 crop -->
    <source media="(max-width: 1023px)"
            srcset="{f:uri.image(image: image, cropVariant: 'tablet', width: '1023c', height: '767c')}" />
    
    <!-- Desktop: 16:9 crop -->
    <source media="(min-width: 1024px)"
            srcset="{f:uri.image(image: image, cropVariant: 'default', width: '1920c', height: '1080c')}" />
    
    <!-- Fallback image -->
    <img src="{f:uri.image(image: image, cropVariant: 'default', width: '1920c')}"
         alt="{image.alternative}"
         class="responsive-hero"
         style="object-fit: cover; object-position: {nnfp:objectPosition(image: image, cropVariant: 'default')}" />
</picture>
Copied!

Example 6: Data Attributes for JavaScript 

Pass focal point data to JavaScript for dynamic effects:

<nnfp:focalPoint image="{image}" cropVariant="default" as="fp">
    <img src="{image.publicUrl}"
         alt="{image.alternative}"
         class="js-parallax-image"
         data-focal-x="{fp.x}"
         data-focal-y="{fp.y}"
         data-has-focal-point="{f:if(condition: fp, then: 'true', else: 'false')}" />
</nnfp:focalPoint>
Copied!

Example JavaScript for parallax effect respecting focal point:

document.querySelectorAll('.js-parallax-image').forEach(img => {
    const focalX = parseFloat(img.dataset.focalX) || 0.5;
    const focalY = parseFloat(img.dataset.focalY) || 0.5;
    
    window.addEventListener('scroll', () => {
        const rect = img.getBoundingClientRect();
        const scrollProgress = 1 - (rect.bottom / (window.innerHeight + rect.height));
        
        // Parallax offset based on focal point
        const offsetY = (scrollProgress - 0.5) * 50 * (1 - focalY);
        img.style.objectPosition = `${focalX * 100}% calc(${focalY * 100}% + ${offsetY}px)`;
    });
});
Copied!

Extending the Extension 

Custom Form Element 

The focal point form element is registered in ext_localconf.php:

$GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1702100000] = [
    'nodeName' => 'focalPointElement',
    'priority' => 40,
    'class' => \Nng\Nnfocalpoint\Form\Element\FocalPointElement::class,
];
Copied!

You can create a custom form element by extending FocalPointElement and registering it with a higher priority.

Custom ViewHelper 

Create custom ViewHelpers by extending the existing ones:

namespace YourVendor\YourExtension\ViewHelpers;

use Nng\Nnfocalpoint\ViewHelpers\ObjectPositionViewHelper;

class CustomObjectPositionViewHelper extends ObjectPositionViewHelper
{
    public function render(): string
    {
        $position = parent::render();
        // Add custom logic
        return $position;
    }
}
Copied!

API Reference 

FocalPointController 

Class: Nng\Nnfocalpoint\Controller\FocalPointController

Handles AJAX requests for the backend modal.

Methods:

wizardAction(ServerRequestInterface $request): ResponseInterface
Returns JSON data for the focal point wizard modal, including image URL, dimensions, crop variants, and existing focal points.
imageAction(ServerRequestInterface $request): ResponseInterface
Returns image data for a specific crop variant.

FocalPointElement 

Class: Nng\Nnfocalpoint\Form\Element\FocalPointElement

Custom FormEngine element that renders the focal point button and hidden input.

Extends: TYPO3\CMS\Backend\Form\Element\AbstractFormElement

ObjectPositionViewHelper 

Class: Nng\Nnfocalpoint\ViewHelpers\ObjectPositionViewHelper

Extends: TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper

Methods:

render(): string
Returns CSS object-position value (e.g., "50% 30%")

FocalPointViewHelper 

Class: Nng\Nnfocalpoint\ViewHelpers\FocalPointViewHelper

Extends: TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper

Methods:

render(): mixed
Returns focal point array or renders children with focal point variable

FocalCropViewHelper 

Class: Nng\Nnfocalpoint\ViewHelpers\FocalCropViewHelper

Extends: TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper

Methods:

render(): string
Returns <img> tag with server-side cropped image centered on focal point

Uri\FocalCropViewHelper 

Class: Nng\Nnfocalpoint\ViewHelpers\Uri\FocalCropViewHelper

Extends: TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper

Methods:

render(): string
Returns URI of focal-point-cropped processed image

Known Problems 

This chapter documents known issues and limitations of the Focal Point Editor extension.

Limitations 

Image Processing 

The focal point data is stored separately from TYPO3's image processing. When using f:image or f:uri.image ViewHelpers with cropping, the focal point is not automatically applied to the crop calculation.

Workaround: Use the focal point data with CSS object-position to position the image within its container, rather than relying on server-side cropping.

No Automatic Cropping 

The extension does not modify how TYPO3 crops images. It provides focal point data that you can use in your templates to position images correctly using CSS.

Example:

<div style="width: 300px; height: 200px; overflow: hidden;">
    <img src="{image.publicUrl}"
         style="width: 100%; height: 100%; object-fit: cover;
                object-position: {nnfocalpoint:objectPosition(fileReference: image)}" />
</div>
Copied!

Browser Compatibility 

CSS Object-Position 

The object-position CSS property is supported in all modern browsers but may not work in older browsers (IE11 and below).

Fallback: For older browsers, consider using background images instead:

<div style="background-image: url('{image.publicUrl}');
            background-size: cover;
            background-position: {nnfocalpoint:objectPosition(fileReference: image)};">
</div>
Copied!

Backend Issues 

Crop Preview Updates 

After saving focal points, the crop preview indicators may not update immediately in all cases. Refreshing the form or saving the record will update the display.

Reporting Issues 

If you encounter a bug or have a feature request, please report it on the project's issue tracker:

When reporting issues, please include:

  • TYPO3 version
  • PHP version
  • Browser and version
  • Steps to reproduce the issue
  • Any error messages from the browser console or TYPO3 logs

Changelog 

This chapter documents all notable changes to the Focal Point Editor extension.

Version 2.0.0 

Release date: 2024

TYPO3 13 Compatibility

Breaking Changes 

  • Minimum PHP version raised to 8.2 (required by TYPO3 13)
  • Minimum TYPO3 version raised to 12.4 LTS

Features 

  • Full compatibility with TYPO3 13.x
  • Continued support for TYPO3 12.4 LTS

Version 1.0.0 

Release date: 2024

Initial Release

Features 

  • Interactive focal point editor modal in the TYPO3 backend
  • Support for multiple crop variants with individual focal points
  • Visual focal point indicators on crop preview thumbnails
  • ObjectPositionViewHelper for CSS object-position values
  • FocalPointViewHelper for accessing raw focal point data
  • JSON-based storage in sys_file_reference.tx_nnfocalpoint_points
  • Percentage-based coordinates (0-1 range) for responsive layouts
  • Full TYPO3 12 LTS compatibility
  • Modern JavaScript module using TYPO3's ES6 module system

Technical Details 

  • Uses TYPO3's Modal API for the editor interface
  • Implements custom FormEngine element (focalPointElement)
  • AJAX-based data loading for the wizard
  • MutationObserver for dynamic crop preview updates
  • CSS loaded via $GLOBALS['TYPO3_CONF_VARS']['BE']['stylesheets']

Planned Features 

The following features are planned for future releases:

  • Drag-and-drop focal point positioning
  • Keyboard navigation in the modal
  • Focal point presets (center, rule of thirds, etc.)
  • Integration with TYPO3's image processing for automatic cropping

Sitemap