npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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-config

Quick 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.frameElement is 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 adFormat is one of the supported values.
  • Positioning looks wrong:
    • Check host URL matches a known Nine site config.
    • Tune stickyOffset for fireplace/collant integrations.