powered-ad-config
v0.1.6
Published
Configure Ads to load smoothly and at the right position on All Nine's websites
Downloads
2,419
Readme
powered-ad-config
Configure Nine masthead/takeover ad formats from inside the ad iframe.
Install
npm install powered-ad-configQuick Start
import initAd from 'powered-ad-config';
if (window.frameElement) {
const cleanup = initAd({
adFormat: 'fireplace',
stickyOffset: 0,
});
// Call when unmounting / replacing the ad
// cleanup();
}Real-World Pattern (16145-paramount fireplace)
In your fireplace project, you load from CDN first and fall back to npm import if needed.
import poweredAdConfigNpm from 'powered-ad-config';
export async function loadAdConfig() {
try {
await new Promise((resolve, reject) => {
const script = document.createElement('script');
// Intentionally using @latest so runtime always picks up newest published powered-ad-config release.
// Note: this can change behavior between deployments if a new version is published.
script.src = 'https://cdn.jsdelivr.net/npm/powered-ad-config@latest/dist/powered-ad-config.umd.js';
script.onload = resolve;
script.onerror = reject;
document.head.appendChild(script);
});
if (typeof window.poweredAdConfig === 'function') {
console.log('CDN loaded successfully');
return window.poweredAdConfig;
}
throw new Error('poweredAdConfig global not available');
} catch (error) {
console.error('Failed to load from CDN, falling back to npm package:', error);
return poweredAdConfigNpm;
}
}Then initialize from your component onMount (or equivalent lifecycle hook):
async function initAdConfig() {
const adConfig = await loadAdConfig();
if (adConfig) {
if (window.frameElement) {
adConfig({
adFormat: 'fireplace',
stickyOffset: window.customScrollTop,
});
}
} else {
console.error('Failed to load adConfig');
}
}
onMount(async () => {
await initAdConfig();
});This pattern is useful when you want runtime fallback resilience while still bundling npm for local/dev reliability.
If you use @latest, runtime behavior can change between deployments as soon as a new package version is published.
If you need deterministic behavior, pin an explicit version in the CDN URL.
API
initAd(options)
Initializes one of the supported formats and returns a cleanup function.
const cleanup = initAd({
adFormat,
stickyOffset,
logoPosX,
logoHeight,
logoSmallHeight,
});Options
| Option | Type | Default | Used by | Description |
|---|---|---:|---|---|
| adFormat | string | '' | all | Format selector. Supported: fireplace, fireplace-collant, logomorph, interscroller |
| stickyOffset | number | 0 | fireplace, fireplace-collant | Extra offset added to sticky/scroll threshold calculations |
| logoPosX | number | 0 | logomorph | Scroll threshold where logo transitions to small state |
| logoHeight | number | 0 | logomorph | Height (px) for large logo state |
| logoSmallHeight | number | 0 | logomorph | Height (px) for small logo state |
Return value
() => void: Removes scroll listeners and pending timers added by the selected format.
Supported Formats
fireplace: Billboard/fireplace behavior with sticky scroll transforms.fireplace-collant: Fireplace behavior with collant transition and content masking.logomorph: Large-to-small logo takeover behavior on scroll.interscroller: Full-viewport scroll-through ad with sticky bands, GSAP stretch animation, and scroll progress callbacks.
Interscroller
Expands the ad container to a configurable scroll height (e.g. 300vh) and locks a full-viewport-width creative iframe behind the page content using clip-path. As the user scrolls, the ad reveals and the top/bottom bands animate accordingly.
Quick start
import initAd from 'powered-ad-config';
initAd({
adFormat: 'interscroller',
// optional overrides (see CONFIG table below)
adScrollHeight: '200vh',
onProgress({ scrollProgress, adExposure, viewportCoverage, pxRemaining }) {
gsap.set(myElement, { y: scrollProgress * -100 });
},
thresholds: [
{ at: 0.2, onEnter: () => playVideo(), onLeave: () => pauseVideo() },
],
});CONFIG options
All options are optional. The defaults are shown below.
Ad scroll zone
| Option | Type | Default | Description |
|---|---|---|---|
| adScrollHeight | string | '300vh' | CSS height of the ad container. Controls how long the ad stays in view. 100vh = standard; 200vh = twice as long. Accepts any CSS length ('150vh', '600px', etc.). |
Bands
| Option | Type | Default | Description |
|---|---|---|---|
| bandHeight | number | 24 | Height in px of both the top and bottom bands. |
| bandBg | string | '#222' | Band background colour. |
| bandColor | string | '#fff' | Band text colour. |
| bandFontSize | string | '10px' | Band font size. |
| bandFontFamily | string | 'Arial, Helvetica, sans-serif' | Band font family. |
| bandLetterSpacing | string | '1px' | Band letter spacing. |
| labelTop | string | 'Advertisement' | Text shown in the top band. |
| labelBottomResume | string | 'Content resumes in {n}px' | Bottom band text while scrolling through the ad. {n} is replaced with the live pixel count. |
| labelBottomNow | string | 'Content resumes now ↓' | Bottom band text once the post-ad content enters the viewport. |
| zIndexTop | number | 9 | z-index of the top band (keep below the page header). |
| zIndexBottom | number | 8 | z-index of the bottom band. |
Stretch animation
The top band stretches downward as the two bands approach each other, then snaps back with an elastic ease.
| Option | Type | Default | Description |
|---|---|---|---|
| snapPx | number | 30 | Gap in px between the bands at which the elastic snap fires. |
| snapOverlap | number | 2 | Fires the snap this many px before snapPx is reached (trigger timing adjustment). |
| stretchOverlap | number | 2 | Starts the stretch this many px before the bands touch, and extends the band this many px past the touchpoint — eliminates the sub-pixel rendering gap. |
| snapDuration | number | 0.9 | Duration in seconds of the elastic return animation. |
| snapEase | string | 'cubic-bezier(0.175, 0.885, 0.32, 1.275)' | CSS timing function for the snap. Any valid CSS transition-timing-function value works. |
Scroll callbacks
onEnter() · onExit()
Lifecycle callbacks fired once per ad pass.
onEnter() {
// ad top band just entered the viewport — start intro animation
},
onExit() {
// post-ad content entered — pause video, clean up, etc.
},onProgress(state)
Fired on every scroll event while the page is within range of the ad.
onProgress({ scrollProgress, adExposure, viewportCoverage, pxRemaining }) {
// drive your scroll-synced animation here
}| Property | Range | Description |
|---|---|---|
| scrollProgress | 0 → 1 | Overall position through the full scroll zone. 0 = ad top enters viewport, 1 = ad bottom exits. |
| adExposure | 0 → 1 | Fraction of the ad's total height (adScrollHeight) that has scrolled into view. Useful for a multi-screen creative (e.g. a 300vh mini-page) — at 0.33, one-third of the creative has been seen. |
| viewportCoverage | 0 → 1 | Fraction of the screen currently filled by the ad. Useful for parallax, opacity, or scale effects tied to how "dominant" the ad is on screen. |
| pxRemaining | ≥ 0 | Pixels left to scroll until the ad clears the bottom band. Same value shown in the bottom band counter. |
thresholds
An array of trigger points keyed to scrollProgress. Each fires onEnter when scrolling forward past at, and onLeave when scrolling back — direction-aware, so rubber-banding and reverse scrolling work correctly.
thresholds: [
{
at: 0.2, // fires when scrollProgress crosses 20%
onEnter: (progress) => playVideo(),
onLeave: (progress) => pauseVideo(),
},
{
at: 0.5,
onEnter: () => triggerSecondAnimation(),
// onLeave is optional
},
],| Property | Type | Description |
|---|---|---|
| at | number (0–1) | scrollProgress value at which to cross. |
| onEnter | function(progress) | Called when scrolling forward past at. |
| onLeave | function(progress) | Called when scrolling back below at. Optional. |
Integration Notes
- Must run from inside an iframe (
window.frameElementis required). - Parent page access must be same-origin (the package reads and mutates parent DOM/CSS).
- Site-specific behavior is selected from the parent URL; unknown URLs no-op safely.
- Calling
initAd(...)again automatically cleans up the previous setup.
Example: Re-initialize on format change
import initAd from 'powered-ad-config';
let cleanup = () => {};
function mount(format) {
cleanup();
cleanup = initAd({
adFormat: format,
stickyOffset: 0,
logoPosX: 120,
logoHeight: 250,
logoSmallHeight: 100,
});
}Troubleshooting
- Nothing happens:
- Verify code runs inside an iframe.
- Verify iframe and parent page are same-origin.
- Verify
adFormatis one of the supported values.
- Positioning looks wrong:
- Check host URL matches a known Nine site config.
- Tune
stickyOffsetfor fireplace/collant integrations.
