@believablecreations/ngx-focus-point
v21.0.1
Published
Angular 21 media focus components for responsive image crops, video focus over time, timeline editing, and YouTube iframe focus.
Maintainers
Readme
ngx-focus-point
Angular 21 components for responsive image focus, video focus over time, focus timeline editing, and YouTube iframe crops.
@believablecreations/ngx-focus-point lets you upload one media source and store small focus metadata beside it. The components then crop, pan, zoom, and clamp the media at runtime so the important subject stays visible across wide, square, portrait, and custom containers.
Compatibility
- Angular:
^21.0.0 - RxJS:
^7.8.0 - Package style: standalone Angular components
- Runtime dependency:
tslib
Angular 20 and earlier are no longer supported by this package line.
Documentation and Live Tools
- Technical documentation: https://believablecreations.com/ngx-focus-point/technical-document
- Image focus tool: https://believablecreations.com/ngx-focus-point
- Video focus tool: https://believablecreations.com/ngx-focus-point/video
- YouTube focus demo: https://believablecreations.com/ngx-focus-point/youtube
Installation
npm i @believablecreations/ngx-focus-pointyarn add @believablecreations/ngx-focus-pointExports
import {
NgxFocusPointComponent,
NgxFocusPointSelectComponent,
NgxFocusPointVideoComponent,
NgxFocusPointVideoSelectComponent,
NgxFocusPointVideoTimelineComponent,
NgxFocusListComponent,
FocusPositionModel,
VideoPosition,
VideoPositions,
NgxFocusPointWorkerOptions,
} from '@believablecreations/ngx-focus-point';Main Features
- Responsive image and video focus with strict cover behavior.
- Pixel-based positioning with clamped
translate3d(px, px, 0) scale(s)transforms. - Static focus with
focusX,focusY, andscale. - Video focus over time with timestamped focus points.
- Animated video keyframes with
jump,from-previous, andto-nextmodes. - Timeline tooling with waveform display, draggable focus points, timeline zoom, pan, JSON copy and paste, and style controls.
- Video selector tooling for clicking or dragging the subject on a video or YouTube iframe.
- Focus list tooling for reviewing, selecting, copying, and pasting focus point JSON.
- YouTube iframe support with automatic 16:9 source-ratio handling.
- Web Worker focus math with timeout and inline fallback options.
- SSR-safe browser checks around DOM, video, canvas, and worker APIs.
Why It Saves Money
Responsive media workflows often create and store multiple exports of the same asset: one image for wide desktop, another for square cards, another for portrait mobile, plus extra hand-cropped versions for campaigns or product listings. ngx-focus-point lets teams keep one high-quality source image or video and store focus metadata instead.
That can reduce:
- Design and content-production time spent manually cropping assets for every breakpoint.
- Storage costs from duplicated image and video variants.
- Bandwidth waste from maintaining parallel renditions that only differ by crop.
- QA time spent checking whether the subject is cut off in each aspect ratio.
- Rework when layouts change, because the same source asset can be reframed dynamically.
The package also supports zoom through the scale/s value. That means a team can use one source asset, focus on the important subject, zoom in for tighter compositions, and still let the component clamp the crop so the container stays fully covered.
Coordinate Model
Focus coordinates are normalized from -1 to 1.
export interface FocusPositionModel {
x: number;
y: number;
w: number;
h: number;
s?: number;
animationMode?: 'jump' | 'from-previous' | 'to-next';
animationEasing?: 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out';
}
export interface VideoPosition {
x: number;
y: number;
w?: number;
h?: number;
s?: number;
time?: number;
animationMode?: 'jump' | 'from-previous' | 'to-next';
animationEasing?: 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out';
}x: -1is left,x: 0is center, andx: 1is right.y: -1is bottom,y: 0is center, andy: 1is top.sis scale.1is the normal cover crop; values above1zoom in.timeis video playback time in seconds.
Basic Image Usage
import { Component } from '@angular/core';
import { NgxFocusPointComponent } from '@believablecreations/ngx-focus-point';
@Component({
selector: 'app-hero-media',
standalone: true,
imports: [NgxFocusPointComponent],
template: `
<ngx-focus-point
class="hero-media"
[focusX]="0.32"
[focusY]="0.18"
[scale]="1.16"
animationSpeed="220ms">
<img src="/assets/hero.jpg" alt="Featured product">
</ngx-focus-point>
`,
})
export class HeroMediaComponent {}Give the host component a real rendered size with CSS, layout, or aspect ratio:
.hero-media {
display: block;
width: 100%;
aspect-ratio: 16 / 9;
overflow: hidden;
}Video Focus Over Time
Pass focus keyframes with time values in seconds. The component listens to the nested video element's playback time and applies the correct point as the video plays.
import { FocusPositionModel } from '@believablecreations/ngx-focus-point';
type VideoFocusPoint = FocusPositionModel & { time: number; id?: string };
focusKeyframes: VideoFocusPoint[] = [
{
x: -0.36,
y: 0.2,
w: 0,
h: 0,
s: 1.08,
time: 0,
animationMode: 'to-next',
animationEasing: 'ease-in-out',
},
{
x: 0.04,
y: 0.02,
w: 0,
h: 0,
s: 1.22,
time: 4.5,
animationMode: 'from-previous',
animationEasing: 'ease-out',
},
{
x: 0.52,
y: -0.18,
w: 0,
h: 0,
s: 1,
time: 9.8,
},
];<ngx-focus-point
class="video-crop"
[focus]="focusKeyframes"
[scale]="1"
[debounceResizeUpdate]="15"
animationSpeed="180ms">
<video
src="/assets/product-demo.mp4"
controls
muted
playsinline
preload="metadata">
</video>
</ngx-focus-point>Use [time] when an external timeline or scrubber should seek the nested video:
<ngx-focus-point
[focus]="focusKeyframes"
[time]="playbackTime"
[syncMediaTime]="true">
<video src="/assets/product-demo.mp4" controls playsinline></video>
</ngx-focus-point>Set [syncMediaTime]="false" when another player controller owns seeking.
Focus Video Tool Components
The package includes building blocks for an authoring workflow:
NgxFocusPointVideoSelectComponent: wraps a video or YouTube iframe and emits normalized focus points from pointer input.NgxFocusPointVideoTimelineComponent: renders waveform, playhead, time markers, draggable keyframes, keyframe settings, timeline zoom and pan, and timeline style controls.NgxFocusListComponent: renders saved focus points and provides JSON copy and paste.
import {
NgxFocusListComponent,
NgxFocusPointVideoSelectComponent,
NgxFocusPointVideoTimelineComponent,
} from '@believablecreations/ngx-focus-point';<section class="focus-editor">
<ngx-focus-point-video-select
[time]="playbackTime"
[focusPoints]="points"
[selectedFocusPoint]="selectedPoint"
(onFocus)="upsertPoint($event)">
<video
src="/assets/source-video.mp4"
controls
playsinline
preload="metadata">
</video>
</ngx-focus-point-video-select>
<ngx-focus-list
[points]="points"
[activePointId]="selectedPointId"
(pointSelect)="selectPoint($event)"
(pointsPaste)="replacePoints($event)">
</ngx-focus-list>
<ngx-focus-point-video-timeline
[audioBuffer]="audioBuffer"
[currentTime]="playbackTime"
[duration]="duration"
[playing]="playing"
[selectionPoints]="points"
[activeSelectionPointId]="selectedPointId"
(play)="play()"
(pause)="pause()"
(timeUpdate)="setPlaybackTime($event)"
(selectionPointSelect)="selectPoint($event)"
(selectionPointUpdate)="updatePoint($event)"
(selectionPointDelete)="deletePoint($event)">
</ngx-focus-point-video-timeline>
</section>YouTube Iframe Support
YouTube embeds are detected when an iframe has a youtube class or a youtube.com, youtube-nocookie.com, or youtu.be source. The iframe is treated as a 16:9 source before focus and crop math runs.
<ngx-focus-point [focusX]="0.18" [focusY]="0.05" [scale]="1.12">
<iframe
class="youtube"
src="https://www.youtube-nocookie.com/embed/VIDEO_ID?rel=0&controls=0&disablekb=1&fs=0&iv_load_policy=3&mute=1&autoplay=1&loop=1&playlist=VIDEO_ID&playsinline=1"
title="YouTube video player"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture">
</iframe>
</ngx-focus-point>YouTube still controls some overlays, branding, ads, context menus, and end-screen behavior. Deprecated params such as modestbranding and showinfo no longer remove that UI.
Worker Options
NgxFocusPointComponent can run focus calculations in a Web Worker. It falls back to local compute if a worker is unavailable, blocked, or too slow.
import { NgxFocusPointWorkerOptions } from '@believablecreations/ngx-focus-point';
workerOptions: NgxFocusPointWorkerOptions = {
timeoutMs: 300,
allowInlineFallback: true,
};<ngx-focus-point
[focusX]="0"
[focusY]="0"
[scale]="1"
[workerOptions]="workerOptions">
<img src="/assets/hero.jpg" alt="">
</ngx-focus-point>Options:
timeoutMs: max time to wait for a worker response before computing locally for that frame. Default:300.allowInlineFallback: creates an inline Blob worker when the packaged worker cannot load. Default:true. Set tofalsefor strict CSP environments.
Main Component API
ngx-focus-point
| Input or output | Type | Description |
| --- | --- | --- |
| [focus] | FocusPositionModel[] | Keyframed focus data. Add time fields for video focus over time. |
| [focusX], [focusY] | number | Static focus coordinates from -1 to 1. |
| [scale] | number | Zoom multiplier. |
| [time] | number | External playback time used to seek nested videos. |
| [syncMediaTime] | boolean | Syncs nested video current time to [time]. |
| [animationSpeed] | string | CSS transform transition duration. Use '' to disable. |
| [debounceResizeUpdate] | number | Resize debounce in milliseconds. |
| [preservePanOnZoom] | boolean | Preserves pan memory while zoom changes for the same focus. |
| [debug] | boolean | Logs sizing and transform information. |
| [workerOptions] | NgxFocusPointWorkerOptions | Configures worker timeout and inline fallback behavior. |
| (error) | Event | Emits nested media load errors. |
ngx-focus-point-video-select
| Input or output | Description |
| --- | --- |
| [time] | Playback time used to align the selector target. |
| [focusPoints] | Existing points to display and animate between. |
| [selectedFocusPoint] | Active point shown in the selector. |
| [scale] | Scale stored on emitted focus points. |
| (onFocus) | Emits normalized focus data with x, y, w, h, s, and time. |
ngx-focus-point-video-timeline
| Input or output | Description |
| --- | --- |
| [audioBuffer] | Optional audio data for waveform rendering. |
| [currentTime] | Current playback time in seconds. |
| [duration] | Total media duration in seconds. |
| [zoom] | Timeline zoom level. |
| [selectionPoints] | Focus keyframes displayed on the timeline. |
| [activeSelectionPointId] | Active keyframe id. |
| [frameRate] | Keyboard frame-step rate. |
| [playing] | Playback state. |
| (timeUpdate) | Emits timeline seek changes. |
| (selectionPointSelect) | Emits the selected keyframe. |
| (selectionPointUpdate) | Emits edited or moved keyframe data. |
| (selectionPointDelete) | Emits an id to delete. |
| (selectionPointClose) | Emits when the keyframe settings panel closes. |
| (play), (pause) | Emits playback commands. |
ngx-focus-list
| Input or output | Description |
| --- | --- |
| [points] | Focus point list. |
| [activePointId] | Active focus point id. |
| (pointSelect) | Emits the selected point. |
| (pointsPaste) | Emits parsed replacement points from pasted JSON. |
Migration Notes
Current package docs should use the pixel-mode API. Older examples that reference these inputs are obsolete:
[actions][translateMode][edgeMode][panScaleMultiplier][panClampMultiplier][focusW][focusH][resetPanOnScaleChange]
Use focusX, focusY, scale, and focus keyframes instead.
Quick Links
- Technical documentation: https://believablecreations.com/ngx-focus-point/technical-document
- Image focus tool: https://believablecreations.com/ngx-focus-point
- Video focus tool: https://believablecreations.com/ngx-focus-point/video
- YouTube focus demo: https://believablecreations.com/ngx-focus-point/youtube
Build and Test
From the Angular workspace:
npm run build:ngx-focus-point:library
npm run test:ngx-focus-point:library