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

@facelessad/cli

v2.2.0

Published

Create faceless video ads from your terminal or build scripts — the FacelessAd command line.

Readme

@facelessad/cli

Create faceless video ads from your terminal or build scripts.

npm install -g @facelessad/cli
facelessad login                # paste an API key from facelessad.com/developers
facelessad tools                # what can be made
facelessad create --tool motion-graphics --url https://your-product.com --wait

Commands: login, create, status, list, download, estimate, tools, voices, brands, balance, parts, regen-part, regen, render, cancel, and webhooks / webhook-add / webhook-rm. Every command accepts --json for scripting; create/estimate accept --dry-run (print the request body without sending) and --file body.json (a base body that flags override).

A finished video can be fixed part by part: parts <id> shows what it is made of and regen-part redoes one clip, image card, graphics block — or, on background-image styles (marked +bg in tools), one bg-N AI photo backdrop with --prompt. The whole video re-renders automatically.

The key is stored in ~/.facelessad/config.json with mode 0600. The environment variable FACELESSAD_API_KEY always wins — that is the way CI should authenticate. FACELESSAD_API_URL overrides the API base.

--wait polls and prints phase + elapsed time, and stops watching after 6 hours (--timeout <seconds> changes that; --timeout 0 waits with no limit). Stopping the wait never cancels the build — API videos run on a bulk lane that can take hours when the queue is busy, and they keep going. A video whose status is draft is not building and will never finish on its own, so --wait stops on it immediately instead of polling forever. For long-running builds a webhook is still the better tool — a stuck shell is a stuck CI job. See https://facelessad.com/developers → Webhooks.

Getting the finished video

--wait tells you when the video is done, but it never prints the video URL. Three ways to get the file:

facelessad download 103 --out ad.mp4        # saves into the CURRENT directory
facelessad status 103 --json | jq -r .url   # the raw link, valid ~24 hours

The third is the browser: every video made through the CLI also appears in My Files at facelessad.com.

Since 1.1.1 download prints the full path and the file size, and fails loudly on an empty file instead of reporting success. The link is signed and expires in about an hour — the video itself does not, so ask for the status again to get a fresh one.

Custom style (1.1.0)

Most tools accept a look of your own instead of one of the built-in styles. facelessad tools marks which ones (supports.customStyle):

facelessad create --tool motion-graphics --url https://your-product.com \
  --style custom \
  --custom-style "Retro terminal — phosphor green on near-black, scan lines, chunky mono type" --wait

What to describe depends on what the tool builds. Animated Ad, Character, Music Video, Inspiration, Motivational and Slideshow render images, so describe the illustration or cinematic style. Motion Graphics, SaaS UI Ad, Text Animation and Video Banner generate their graphics as code, so describe typography, palette and motion. Crude Drawings has no custom style.

Product Showcase builds both — cinematic clips animated from your real product photo, and text graphics drawn in code on top — so it takes two descriptions:

facelessad create --tool product-showcase --product-image https://.../bottle.jpg \
  --text "A steel bottle that keeps drinks cold for 24 hours" \
  --style custom \
  --custom-style "Frozen tundra — cracked ice, pale blue rim light, slow orbiting camera" \
  --custom-graphics-style "Deep navy typography, thin white hairlines — the video reads light" --wait

Leave --custom-graphics-style out and it is written for you from the first description.

Your text is expanded into a full style specification before the video is built. facelessad status <id> --json returns the expanded text as customStyle; feed it back with --no-refine-style to give a whole campaign one identical look.

Flag spellings

One spelling per flag. Up to 1.5.2 seven alternative spellings were also accepted (--brand, --color, --colour, --voice-id, --voice-gender, --no-voice-over, --product-image-url); they were removed in 1.5.3, because two names for one flag is worse for a reader — and for an assistant — than one. An unknown flag stops the command, so a removed spelling fails loudly rather than building a video with the wrong settings.

These are not alternative spellings but forms of their own, and they stay:

| form | means | |---|---| | -o | short for --out | | --no-captions | --captions false | | --no-music | --music false | | --no-sfx | --sfx false | | --no-voice | no narration | | --no-brand-kit | build without the Brand Kit | | --no-refine-style | use the custom style text verbatim | | --visual-direction-refine "<preset\|text>" | how the story is told, not how it looks (2.2.0) | | --layout <A\|HA\|AC\|HAC\|AIA\|HAIA\|AIAC\|HAIAC> | card layout; data card drops if too short, hook/CTA stay (2.2.0) |

--no-brand-kit now works; before 1.0.1 it was accepted on the command line and silently dropped, so the video was built with the Brand Kit anyway. An unknown flag is now an error rather than something quietly ignored — that silence is what hid the whole problem.

2.2.0 — --visual-direction-refine

Animated Ad and Music Video: a preset id (metaphoric, realistic, dramatic, calm, playful, dark, bright, magicalfacelessad tools lists them) or your own instruction up to 300 characters. Reshapes how the visual story is told, not how it looks; applied on top of --visual-direction or the generated one. Free.

--layout (same two tools) picks the card layout. Too short for the data card? It is dropped, the hook/CTA you chose stay, and the output says so. facelessad tools lists the layouts and what each becomes per duration.

1.3.0 — turn any text file into a video

Agent skill included. The package ships SKILL.md — drop it where your agent reads skills and Claude Code, Cursor, Codex or OpenClaw can operate the CLI on its own (every command supports --json):

npm install -g @facelessad/cli
cp "$(npm root -g)/@facelessad/cli/SKILL.md" .claude/skills/facelessad/SKILL.md   # Claude Code
# Cursor / Codex / OpenClaw: point your rules or skills folder at the same file

Then just ask: "Take our latest release notes and create three launch videos using our brand kit."

--materials-file <path> reads a local text file — a README, release notes, a blog post, product JSON, docs — and uses it as the materials:

facelessad create --tool motion-graphics --materials-file README.md --wait
facelessad create --tool animated-ad --materials-file release-notes.md --duration short

Send the whole file. Text over ~8000 characters is condensed server-side in a way that keeps that material's own details, numbers and voice — it is not squeezed into a generic brief, so a README and a blog post still produce different videos. The hard ceiling is 200 000 characters, and the CLI checks it before sending. Combines with --text (both are used).

--materials-url <url> is a direct link to a raw text file on the web — a GitHub raw README, a gist, a docs export. The server fetches it with the same protections as landing pages, but without HTML extraction:

facelessad create --tool saas-ui-ad \
  --materials-url https://raw.githubusercontent.com/you/repo/main/README.md --wait

Use --url for HTML pages (the page text is extracted) and --materials-url for files that already are text. There is also POST /api/v1/files for uploading a file once and reusing it across many videos via materials.file_id — the CLI doesn't need it (it inlines the file), but other integrations might; see the developers page.

1.2.0

Video Banner has flags. Its copy and images were reachable through the HTTP API but had no flags at all, so the only way to set them was --file body.json:

facelessad create --tool video-banner --url https://example.com \
  --headline "Ship ads in minutes" --subline "No camera, no crew" \
  --cta-text "Try it free" --badge random_face --photo-query "nordic office" --wait

Leave the three texts out and they are written for you from the materials. Give a headline and only your own copy is used — the fields you leave empty stay empty rather than being written for you (--text-mode makes the choice explicit). --background-image <url> replaces the automatic photo pick entirely, and --badge-image <url> puts your own image in the corner instead of the AI face.

Product Showcase extra angles: --product-images url1,url2,url3 (up to 8), which improves how well the product keeps its shape and label across clips.

SaaS UI Ad takes screenshots. The tool decomposes real screens with vision and rebuilds them animated — that is the whole point of it, and without them the ad is built from your written description alone:

facelessad create --tool saas-ui-ad --url https://your-app.com \
  --screenshots "https://.../dashboard.png,https://.../editor.png" --wait

How many fit depends on the length, because each screen needs time on camera: 1 for short, 3 for medium, 4 for long. facelessad tools --tool saas-ui-ad prints the limits.

Character does dialogue. --speakers 2 makes it a conversation between two characters instead of one narrator, and the ad structure has to match — the two pools are listed by facelessad tools --tool character:

facelessad create --tool character --url https://your-product.com \
  --speakers 2 --structure ch-qa --gender-right male --wait

--voice-right <id> and --gender-right female|male steer the second voice. Leave them out and a distinct one is picked for you — a different gender first, then a different id. They need --speakers 2; without it the command stops before it reaches the network.

A flag that needs a value is an error without one. --brand-kit on its own used to mean brand number 1, and download 5 -o used to write a file called true. Both now stop with missing_value. Flags that are booleans by nature (--sfx, --no-voice, --wait) are unaffected.

Boolean flags are validated. --captions yes, --captions 1 and --captions TRUE used to become false without a word, because only the exact string true was accepted. All the usual spellings now work in both directions, and anything else is an error instead of a silent guess.

facelessad tools --tool <id> shows every ad structure, grouped the way the app groups them. It used to print only the default group — 17 of animated ad's 46, and 6 of motion graphics' 119.

--winners / --no-winners are gone. Winning-ad analyses are not offered through the API while the feature is unfinished; the server no longer reads the field.

Errors are printed with the API's own wording and exit code 1. The machine code (e.g. unknown_style) follows the message.