Focus Filmstrip
A cinematic portrait filmstrip with landscape thumbnails, an expanding portrait selection and a synchronized full-image backdrop.
Install the component, then paste your configured usage. Your settings are included in the code below.
Pro source comes with Arclen UI Pro. See plans
| Property | Type | Default |
|---|---|---|
imagesPhotographs Bundled portrait-01 through portrait-07, legacy illustration-01 through illustration-06, or complete HTTPS image URLs. Minimum 0 itemsMaximum 12 itemsUp to 2048 characters per item | string-list | ["portrait-01","portrait-02","portrait-03","portrait-04","portrait-05","portrait-06","portrait-07"] |
backgroundImagesWide background photographs Optional HTTPS URLs or bundled wide keys. Empty uses matching bundled wide frames, or the selected custom image. Minimum 0 itemsMaximum 12 itemsUp to 2048 characters per item | string-list | [] |
titlesProject titles Minimum 0 itemsMaximum 12 itemsUp to 160 characters per item | string-list | ["Cobalt Haze","Solar Drift","Acid Current","Red Signal","Night Signal","Violet Echo","Golden Static"] |
captionsProject credits Minimum 0 itemsMaximum 12 itemsUp to 160 characters per item | string-list | ["By Studio Arclen","By Studio Arclen","By Studio Arclen","By Studio Arclen","By Studio Arclen","By Studio Arclen","By Studio Arclen"] |
linksProject link URLs Minimum 0 itemsMaximum 12 itemsUp to 2048 characters per item | string-list | ["","","","","","",""] |
imageWidthMaximum tile width Desktop tiles fit the complete collection up to this width. Phone tiles use a scrollable row. 120–440Step 1 | number | 300 |
imageHeightLandscape height ratio Nominal height relative to maximum tile width. 300 × 200 gives a 3:2 landscape thumbnail. 80–320Step 1 | number | 200 |
gapThumbnail gap 0–120Step 1 | number | 4 |
focusScalePortrait height multiplier Selected tile height compared with its landscape height. 2 produces a 3:4 portrait at the default dimensions. 1.05–3Step 0.05 | number | 2 |
inactiveScaleNeighbor inset scale Insets unselected photographs within their landscape slots. 1 leaves the row edge-to-edge. 0.4–1Step 0.05 | number | 1 |
inactiveOpacityNeighbor opacity 0.15–1Step 0.05 | number | 1 |
radiusCorner radius 0–64Step 1 | number | 2 |
heightFixed scene height 360–1400Step 1 | number | 900 |
titleSizeTitle size 24–160Step 1 | number | 84 |
captionSizeMetadata size 8–36Step 1 | number | 10 |
fontFamilyTitle font Options: component (Component default), system (System sans), serif (System serif) | select | "component" |
backgroundBackground | color | "#201414" |
textColorText color | color | "#ffffff" |
detailsProject details Minimum 0 itemsMaximum 12 itemsUp to 160 characters per item | string-list | ["Sound & Image","Sound & Image","Sound & Image","Sound & Image","Sound & Image","Sound & Image","Sound & Image"] |
locationsProject locations Minimum 0 itemsMaximum 12 itemsUp to 160 characters per item | string-list | ["London","Accra","Seoul","Paris","Lagos","Berlin","Tokyo"] |
collectionTitleCollection label Up to 80 characters | text | "Sound / Image" |
initialIndexStarting project Zero-based project index, clamped to the available collection. 0–11Step 1 | number | 3 |
sizingScene sizing Options: fill (Fill parent), fixed (Fixed height) | select | "fill" |
stripPositionStrip vertical position 38–64Step 1 | number | 50 |
gutterText gutter 8–64Step 1 | number | 16 |
backgroundDimBackdrop dimming 0–0.75Step 0.01 | number | 0.08 |
focalYPhotograph focal height 0–100Step 1 | number | 40 |
backgroundFocalYBackdrop focal height 0–100Step 1 | number | 36 |
durationSelection transition 0–1200Step 50 | number | 450 |
showControlsShow previous / next | boolean | false |
showMetadataShow project metadata | boolean | true |
adaptiveTextAdapt text for light photographs Uses dark text on the included acid-green and golden photographs. Disable to always use Text color. | boolean | true |
Focus Filmstrip
A full-image portrait gallery. Every thumbnail is landscape until selected; the selected photograph opens downward into portrait while a matching wider frame fills the backdrop. Large sans-serif project titles and small monospaced credits sit immediately above the strip. There are no visible slide numbers, progress bars or default pause controls.
React
Copy this complete component directory into your project. React 19 and React DOM 19 are peer requirements. Inter is bundled under the SIL Open Font License 1.1. No additional runtime libraries or remote fonts are required.
import {FocusFilmstrip} from './components/focus-filmstrip/src/react';
export default function Portraits() {
return <div style={{height: 900}}>
<FocusFilmstrip
images={['portrait-01', 'portrait-02', 'portrait-03']}
titles={['Cobalt Haze', 'Solar Drift', 'Acid Current']}
captions={['By your studio', 'Photography', 'Art direction']}
details={['Campaign', 'Editorial', 'Campaign']}
locations={['London', 'Accra', 'Seoul']}
initialIndex={1}
collectionTitle="Selected portraits"
links={['', '', '']}
/>
</div>;
}For a standalone scene with its own height, use sizing="fixed" and height={900}. The default fill composition needs a bounded parent. Heights below 480px are intentionally given a minimum scene height so the selected portrait and text remain usable.
JavaScript
import {mount, defaults} from './components/focus-filmstrip/src/core';
import './components/focus-filmstrip/src/styles.css';
const host = document.querySelector<HTMLElement>('#portraits')!;
const gallery = mount(host, {sizing: 'fixed', height: 900});
gallery.update({backgroundDim: 0.2, radius: 6, gap: 6});
gallery.pause();
gallery.resume();
gallery.update({...defaults});
// Before removing the host:
gallery.destroy();render(settings, id) returns the initial selected state for server HTML. mount owns the host's children and returns update, pause, resume and destroy. Invalid updates throw before changing the scene. React handles a unique instance ID automatically; use distinct IDs with standalone render/mount.
Photography and content
Bundled portrait keys are portrait-01 through portrait-07. Each includes a portrait crop and a wide derivative of the same original campaign photograph. The full-width background uses the wide frame; the thumbnail and expanded selection use a central portrait crop of that exact photograph. Generated images depict fictional adults. Full generation and artwork records accompany the assets.
The optional backgroundImages list supplies custom wide backgrounds. An empty list automatically uses the matching bundled wide photographs for bundled portraits, or the selected custom image for other sources. An empty individual entry also chooses that automatic behavior. Custom image and destination URLs must be complete HTTPS URLs without credentials. Every image is statically imported into the portable package; no third-party image service is required for the default gallery.
The earlier illustration-01 through illustration-06 keys remain available for existing integrations. They use the same illustration as their backdrop unless you supply a background override. Lists allow up to twelve projects; an empty primary list restores defaults. Short companion lists fall back to corresponding built-in content, while an empty individual string hides that field or destination. Replace sample copy before publishing. There are no default project destinations.
initialIndex is zero-based and clamps to the last available project. It applies on first render and when explicitly included in an update. Other updates retain the current selection, clamped to the updated collection.
Geometry, colour and typography
At 1200 × 900, seven photographs fit edge-to-edge in one row, separated by 4px. The strip starts halfway down the hero. Landscape slots are 3:2; the selected tile is twice as tall, producing a 3:4 portrait with a common top edge. Below 620px, a horizontally scrollable row keeps a larger selected portrait and adjacent context. Native vertical scrolling can still reach the surrounding page. One project remains one tile; no filler duplicates are added. Dense desktop collections retain a 72px minimum tile width and scroll when larger gaps prevent the whole row fitting.
imageWidth caps desktop tile width. imageHeight / imageWidth defines the landscape height ratio. focusScale now multiplies that landscape height to produce the portrait height; it no longer enlarges width. inactiveScale insets unselected media within its slot, and inactiveOpacity controls its opacity. These existing keys remain accepted with the new composition semantics. Extreme ratios may need a lower strip position or taller scene.
stripPosition, gutter, radius and gap adjust composition. focalY controls portrait/thumbnail framing; backgroundFocalY controls wide-background framing. backgroundDim adjusts the overlay, background is the fallback colour and textColor changes foreground text. By default, adaptiveText uses dark text on the bundled acid-green and golden fields; disable it to apply textColor everywhere. Phone captions retain the chosen text colour over a soft readability scrim. The main title uses bundled Inter by default, with system sans and system serif choices. titleSize is the responsive title ceiling; phone titles use a separate readable 36–56px scale. captionSize controls technical metadata. collectionTitle can be empty. showMetadata hides the metadata group. Long titles use smaller type and wrap; empty fields do not leave printed placeholder labels.
Selection and motion
Click a thumbnail to select it. Drag or swipe horizontally; on a row that fits, a deliberate horizontal drag selects the next or previous project. On an overflowing row, native scrolling selects the image nearest the viewport centre. Left/right arrows, Page Up/Page Down and Home/End also work inside the gallery. Navigation stops at the endpoints. Thumbnail buttons select images and do not open destinations. An optional project link appears only when that project has a destination. showControls enables previous/next buttons, hidden by default.
The portrait aperture and image framing change together with a short CSS transition, and matching backgrounds crossfade after their image is ready. Rapid selections invalidate outdated background loads. Background, title, metadata, project link and accessibility state all follow the current selection. There is no autoplay, idle animation loop, or hidden countdown. A polite live region announces the selected title.
Pause, hidden documents, offscreen state and reduced motion disable transitions and smooth scrolling. Manual selection remains available. Resume retains selection. Destroy releases pointer capture, event listeners, observers and queued animation frames; late image-decode callbacks cannot mutate a destroyed or replaced scene. Failed custom images fall back once to a bundled portrait. Without JavaScript the initial state remains readable and native scrolling exposes the other photographs, but selection does not change.
Settings
The settings table is generated from the component manifest.
The preview runs the component’s own JavaScript. It respects reduced motion and pauses when off screen. The HTML bundle includes a poster fallback.
Every setting in this panel comes from the component manifest. Preview size, pause and replay stay in the inspector.