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

flag-resizer

v0.0.3

Published

Generate typed, optimized PNG and WebP flag assets from bundled SVG artwork.

Readme

🏁 Flag Resizer

Generate typed, optimized PNG and WebP flag assets from bundled SVG artwork.

npm version Test PR License

npm · Changelog · Source

flag-resizer converts its bundled flag artwork into application-ready image sets. Configure one or more profiles, choose the regions, dimensions, and formats you need, and generate a deterministic TypeScript manifest alongside the assets.

✨ Why use it?

| Feature | Details | | --------------------------------- | ---------------------------------------------------------------------------------------------- | | 🏳️ Bundled flags | Includes 627 regional and subdivision flags across Twemoji, FlagCDN, and ISO 3166-2 sources. | | 🖼️ Optimized image sets | Generates PNG, WebP, or both at every configured size and quality. | | 🧩 Typed application paths | Produces country, size, format, dimension, and public-path constants with a typed path helper. | | 🎯 Reusable profiles | Supports independent country filters, dimensions, formats, and output locations. | | 🧹 Safe deterministic updates | Tracks owned files, removes stale generated output, and preserves unrelated files. | | 🛠️ CLI and programmatic API | Works in package scripts or directly from TypeScript build tooling. |

🚀 Quick start

Node.js 22 or newer is required.

1. Install

With Bun:

bun add --dev flag-resizer

With npm:

npm install flag-resizer --save-dev

2. Configure

Create flag-resizer.config.ts in your project:

import { defineConfig } from 'flag-resizer';

export default defineConfig({
  default: {
    filter: {
      type: 'whitelist',
      values: ['cz', 'gb', 'us-*'],
    },
    sizes: [
      [20, 15],
      [40, 30],
      [60, 45],
      [80, 60],
      [120, 90],
    ],
    quality: 100,
    formats: ['png', 'webp'],
    output: {
      png: {
        dir: 'public/flags/png',
        publicPath: '/flags/png',
      },
      webp: {
        dir: 'public/flags/webp',
        publicPath: '/flags/webp',
      },
      ts: 'src/generated/flags.ts',
    },
  },
});

Filter values are lowercase flag or country codes, not language codes. They can be exact codes or patterns using * as a wildcard. For example, use cz for the Czech flag, gb for the British flag, or us-* for all 50 U.S. subdivision flags. The us-* pattern does not include the national us flag; add us separately if needed. Likewise, ar-* selects Argentinian subdivisions, at-* selects Austrian states, ca-* selects Canadian subdivisions, au-* selects Australian subdivisions, br-* selects Brazilian federative units, ch-* selects Swiss cantons, co-* selects Colombian subdivisions, de-* selects German states, es-* selects Spanish autonomous communities and cities, gr-* selects the four Greek subdivision codes with bundled artwork, it-* selects Italian regions, jp-* selects Japanese prefectures, mx-* selects Mexican federal entities, pl-* selects Polish voivodeships, pt-* selects Portuguese subdivisions, and * selects every bundled flag.

To generate only national and territorial flags, blacklist *-*:

filter: {
  type: 'blacklist',
  values: ['*-*'],
}

Every bundled subdivision code contains a hyphen, so *-* matches all subdivisions without matching national or territorial codes such as us, hk, mo, or ac. Whitelisting *-* instead generates only subdivisions. Additional exact exclusions can be combined with the global pattern; for example, values: ['*-*', 'cz'] excludes every subdivision and the Czech flag.

Subdivision codes can also be selected individually: gb-eng, gb-nir, gb-sct, and gb-wls for the United Kingdom; us-ca for California; ca-on for Ontario; or au-nsw for New South Wales. Unknown codes, malformed patterns, and patterns that match no bundled flags fail validation.

The Northern Ireland asset is the historical Ulster Banner from flag-icons. Northern Ireland has no current distinct official flag; the United Kingdom flag is its official flag.

The 50 U.S. state assets come from FlagCDN, whose flag artwork is based on Wikimedia Commons vectors and identified as public domain in Flagpedia's terms. The source artwork is normalized to the same rounded 36×36 canvas as the bundled Twemoji flags.

The 24 Argentinian, 9 Austrian, 13 Canadian, 8 Australian, 27 Brazilian, 26 Swiss, 33 Colombian, 16 German, 4 Greek, 19 Spanish, 20 Italian, 47 Japanese, 32 Mexican, 16 Polish, and 20 Portuguese subdivision sets primarily come from the MIT-licensed iso3166-flags dataset and use current ISO 3166-2 codes. The ch-ar asset instead uses the square, public-domain flag artwork from Wikimedia Commons; this avoids stretching the shield-shaped upstream artwork. The pt-02 asset likewise uses a higher-detail, public-domain vector from Wikimedia Commons, while pt-12 and pt-17 use higher-resolution Commons artwork under CC BY-SA 3.0. Spain's set covers its 17 autonomous communities and 2 autonomous cities, not its 50 provinces; Italy's set covers its regions, not its provinces or metropolitan cities; Argentina's set covers its 23 provinces and autonomous city; Brazil's set covers its 26 states and Federal District; Colombia's set covers its 32 departments and capital district; Switzerland's set covers its 26 cantons; Japan's set covers its 47 prefectures; Mexico's set covers its 31 states and Mexico City; and Portugal's set covers its 18 districts and 2 autonomous regions. Greece has 14 current ISO 3166-2 subdivisions, but the source provides Mount Athos artwork and reuses the unofficial Greek Macedonia flag for gr-a, gr-b, and gr-c; the other 10 administrative regions are not bundled. Some Mexican subdivision designs are representative de facto banners rather than legally adopted state flags. The Mexico City source and 16 Portuguese district assets are raster-backed. The pt-12 and pt-17 assets use the higher-resolution Commons sources described above; the remaining raster-backed Portuguese assets use source images from the ISO dataset. They are embedded in normalized SVG wrappers. The non-rectangular official silhouettes of pl-28 and pl-30 intentionally retain transparency around their fly edges. All source artwork is normalized to the rounded 36×36 canvas.

All sizes in one profile must use the same aspect ratio. Output paths are resolved relative to the configuration file. A publicPath can be a root-relative path or an absolute CDN URL.

Configuration is loaded by C12 and may use TypeScript, JavaScript, JSON, JSONC, JSON5, YAML, or TOML.

3. Generate

bunx flag-resizer
... Generating flag assets…
✔  default · 2 flags · 20 images · 25 created · 15 ms

🧭 CLI reference

flag-resizer [profiles...] [options]

-c, --config <path>        Use an explicit configuration file.
    --concurrency <count>  Maximum parallel image conversions.
    --dry-run              Preview changes without writing files.
    --verbose              Show configuration and output details.
-h, --help                Display usage information.
-v, --version             Display the installed version.

With no profile arguments, every configured profile is generated. Pass profile names to generate only those profiles:

bunx flag-resizer default marketing

Use an explicit config, limit parallel image conversions, or preview changes:

bunx flag-resizer --config ./config/flags.config.ts --concurrency 4
bunx flag-resizer --dry-run
bunx flag-resizer --dry-run --verbose

Interactive output stays compact and uses color when the terminal supports it. Set NO_COLOR=1 to disable ANSI colors or FORCE_COLOR=1 to enable them when output is redirected.

🎨 Verbose output

Add --verbose to show the loaded configuration, requested sizes and formats, asset output directories, generated TypeScript file, and managed manifest. Paths inside the current project are kept relative for readability:

... Planning flag generation…
✔  default · 2 flags · 8 images · 13 created · 15 ms

   config      flag-resizer.config.ts
   sizes       20x15, 40x30
   formats     png, webp
   png output  public/flags/png
   webp output public/flags/webp
   typescript  src/generated/flags.ts
   manifest    .flag-resizer/manifest.json

📁 Generated assets

Each format is organized into dimension directories:

public/flags/png/
├── ATTRIBUTION.txt
├── LICENSE-GRAPHICS
├── 20x15/
│   ├── cz.png
│   └── gb.png
└── 40x30/
    ├── cz.png
    └── gb.png

The CLI records only files it owns in .flag-resizer/manifest.json. Later runs remove stale generated files while preserving unrelated files in the same directories.

All images are staged before existing outputs or the ownership manifest are updated. A conversion failure therefore leaves the current assets and manifest unchanged.

📝 Generated TypeScript

Each profile generates:

  • FLAGS and its filtered CountryCode union.
  • FLAG_SIZES, FlagSize, and FLAG_DIMENSIONS.
  • FLAG_FORMATS and FlagFormat.
  • FLAG_PUBLIC_PATHS.
  • getFlagPath(code, size, format).
import {
  FLAGS,
  FLAG_DIMENSIONS,
  getFlagPath,
  type CountryCode,
  type FlagSize,
} from './generated/flags';

function flagImage(code: CountryCode, size: FlagSize) {
  return {
    src: getFlagPath(code, size, 'png'),
    ...FLAG_DIMENSIONS[size],
  };
}

An Angular component can precompute the generated paths for a responsive picture, keeping function calls out of the template:

function createFlagPicture(code: CountryCode) {
  return {
    webpSrcset: [
      getFlagPath(code, '20x15', 'webp'),
      `${getFlagPath(code, '40x30', 'webp')} 2x`,
      `${getFlagPath(code, '60x45', 'webp')} 3x`,
    ].join(', '),
    pngSrc: getFlagPath(code, '20x15', 'png'),
    alt: FLAGS[code],
  };
}

export class FlagComponent {
  protected readonly flag = createFlagPicture('cz');
}
<picture>
  <source type="image/webp" [attr.srcset]="flag.webpSrcset" />
  <img [src]="flag.pngSrc" [width]="20" [height]="15" [alt]="flag.alt" />
</picture>

🛠️ Programmatic API

Load a discovered or explicit configuration file:

import { generate } from 'flag-resizer';

const result = await generate({
  configFile: './flag-resizer.config.ts',
  profiles: ['default'],
  concurrency: 4,
});

Or supply inline configuration:

import { defineConfig, generate } from 'flag-resizer';

const config = defineConfig({
  icons: {
    filter: { type: 'whitelist', values: ['cz', 'gb'] },
    sizes: [[40, 30]],
    quality: 100,
    formats: ['webp'],
    output: {
      webp: { dir: 'public/flags', publicPath: '/flags' },
      ts: 'src/generated/flags.ts',
    },
  },
});

await generate({ config });

✅ Validation

The generator rejects:

  • Language codes, unknown country codes, malformed patterns, or patterns with no matches.
  • Duplicate formats, sizes, or filter values.
  • Dimensions that are not positive integers.
  • Mixed aspect ratios within a profile.
  • Missing output settings for an enabled format.
  • Output collisions between profiles.

🏗️ Development

Use Node.js 24 from .nvmrc and Bun 1.3.14 from package.json:

bun ci
bun run check

bun run check runs formatting, linting, type checks, runtime and public-API tests, the build, and published-package validation.

Husky installs the repository hooks during bun ci. The pre-commit hook runs ESLint and Prettier on staged files through lint-staged, while the commit-message hook validates Conventional Commits with Quick Commitlint.

🏷️ Releases

Run a release command from a clean working tree:

bun run release:patch
bun run release:minor
bun run release:major

Each command checks out master, validates the package, updates CHANGELOG.md, creates the release commit and v* tag, then pushes the commit and tags. The tag workflow publishes flag-resizer to npm and @celtian/flag-resizer to GitHub Packages.

Create an npm beta release with:

bun run release:beta

Beta tags publish with the npm beta dist-tag and are not copied to GitHub Packages. The repository must provide the NPM_AUTH_TOKEN Actions secret; GitHub Packages uses the workflow's automatic GITHUB_TOKEN.

🤝 Contributing

Contributions are welcome. See CONTRIBUTING.md for the development workflow and pull-request checklist. Participation is governed by the Code of Conduct.

🔒 Security

Report suspected vulnerabilities privately according to SECURITY.md.

📄 License and attribution

Copyright © 2026 Dominik Hladík.

The package code is licensed under the MIT License.

The bundled graphics use source-specific terms: Twemoji is licensed under CC-BY-4.0; the Northern Ireland and ISO-sourced subdivision assets are MIT-licensed; and the FlagCDN U.S. state artwork is public domain. Generated asset roots include attribution and license notices. Keep the required notices when redistributing the graphics. See ATTRIBUTION.txt and LICENSE-GRAPHICS.