PrismPoster Creator Tools

com.prismposter由 prismposter.com 发布官方发布者v1.0.0更新于 Oct 24, 2026

Social media frame sizes with sourced safe areas, plus aspect-ratio, bitrate and subtitle tools.

已验证Streamable HTTP可网页运行数据与分析媒体与设计

概览

AI 生成的概览

面向视频与社交媒体创作者只读计算工具:带来源的平台画幅与安全区、宽高比裁切、码率、字幕与节拍计算。

可以做什么
查询社交媒体版位,比较画幅尺寸、宽高比、安全区内边距与可用区域,附第一方来源链接,并给出源尺寸的居中裁切或加边方案。检查字幕、标志或按钮矩形是否位于版位安全区内,以及超出各边缘多少像素。化简宽高比、按编码器块对齐尺寸,并计算目标比例的居中裁切或加边方案。估算编码文件大小、符合容量上限的码率以及每像素比特密度。在 SRT 与 WebVTT 之间转换字幕文本,可整体平移时间,并返回字幕条数与解析警告。根据敲击时间戳估算 BPM,或按已知 BPM 给出拍长、小节时长与延迟表。
适用场景
适合在准备视频或社交发布时使用:需要准确且有来源的画幅与安全区数据而非网上猜测的像素表,或在剪辑中快速做宽高比、码率、字幕与节拍计算。
运行要求
可使用 prismposter.com 上的托管 Streamable HTTP 端点,或通过 stdio 在本地运行 npm 包 @prismposter/creator-tools(例如用 npx),后者需要 Node.js。未声明需要账号、API 密钥、环境变量或请求头。
安装前请注意
工具被描述为只读、确定性且不发起网络请求,因此不会写入或外发数据。托管端点使用比本地包更大的数据集并额外提供能力查询工具,两者结果可能不同。平台未公布固定数值时安全区返回 null,这是有意为之,不应以零替代。

安装

在 SourceWeft 中

  1. 打开 控制台中的 PrismPoster Creator Tools,将其添加到工作区。
  2. 为需要使用其工具的对话启用该服务。

Web executable,通过 Streamable HTTP。 远程服务在工作区中配置后即可从网页运行时运行。

交给智能体安装

把这段提示词粘贴到 Claude Code、Codex、Cursor 等智能体,或 SourceWeft 对话中。智能体会读取该服务器的安装指南,先向你展示发布者、端点和登录方式,经你同意后再把它添加到你的客户端。密钥不会写进任何命令。

阅读 https://sourceweft.com/mcp/com.prismposter%2Fcreator-tools/install.md,并按其中说明把这个 MCP 服务器接入我的客户端。修改任何配置之前,先告诉我它的发布者、端点和登录方式,等我确认。不要把 API 密钥写进命令或我会提交的文件;问我密钥应从哪里获取。

查看智能体所依据的安装指南

其他 MCP 客户端

把它添加到你客户端的 mcpServers 配置中。

{
  "mcpServers": {
    "prismposter-creator-tools": {
      "type": "http",
      "url": "https://www.prismposter.com/api/mcp"
    }
  }
}

README

creator-tools

Zero-dependency TypeScript utilities for video and social creators: aspect-ratio maths, tap tempo, subtitle parsing and conversion, platform frame sizes with sourced safe areas, encoding calculators, colour-palette extraction, GIF encoding, image metadata, and C2PA / AI-provenance detection.

No runtime dependencies. No network calls. Works in the browser, in Node, and in a worker. Every number it returns is one you could check by hand — and where a platform doesn't publish a number, it says so instead of inventing one.

bash
npm install @prismposter/creator-tools

Why this exists

Most of these calculations are scattered across blog posts that quote each other, and a surprising number of the quoted figures are wrong. The one that started this library: every "TikTok safe area" pixel table on the open web is invented. TikTok publishes an overlay template, not a fixed inset — the occluded zone varies with frame dimensions, caption length, and which ad formats are running. There is no correct constant, so this library returns null for it and explains why, rather than shipping a plausible-looking number.

That's the rule the whole package follows:

  • Derived numbers are derived. A 9:16 frame at 1080 wide is 1920 tall because that's what the ratio says. Every size in social-sizes is asserted against its own declared ratio by the test suite.
  • Quoted numbers name their source. Every safe area links the first-party page it was read from. safeAreaSourceUrl(placement) returns that URL.
  • Unknown is a value, not a blank. A platform that publishes nothing gets an explicit kind: 'unpublished' with the reason attached.

Modules

aspect-ratio

Ratio arithmetic for frames about to be encoded. Handles non-integral cinema ratios (2.39:1) the same way it handles 16:9.

ts
import {  simplifyRatio, cropToRatio, padToRatio, alignToBlock,} from '@prismposter/creator-tools/aspect-ratio';
simplifyRatio({ width: 1920, height: 1080 });   // { w: 16, h: 9 }
cropToRatio({ width: 1920, height: 1080 }, { w: 9, h: 16 });// { result: { width: 608, height: 1080 },//   removed: { top: 0, right: 656, bottom: 0, left: 656 },//   areaKept: 0.3167 }
// Codecs want even dimensions; H.264 chroma subsampling makes an odd// width an encoder error or a silent rescale.alignToBlock({ width: 1081, height: 607 });      // { width: 1082, height: 608 }alignToBlock({ width: 1080, height: 1920 }, 16); // { width: 1088, height: 1920 }

An odd crop remainder always goes to the bottom/right edge. That's arbitrary, but it's consistent — splitting it differently per call is how a batch of clips ends up a pixel out of register with each other.

social-sizes

Platform frames and safe areas, with sources.

ts
import {  getPlacement, frameSize, safeAreaPx, safeAreaBox, safeAreaSourceUrl,} from '@prismposter/creator-tools/social-sizes';
const reels = getPlacement('instagram-reels')!;frameSize(reels);           // { width: 1080, height: 1920 }safeAreaPx(reels);          // { top: 269, bottom: 672, left: 65, right: 65 }safeAreaBox(reels);         // { width: 950, height: 979 }safeAreaSourceUrl(reels);   // Meta's Reels ads-guide page
const tiktok = getPlacement('tiktok-video')!;safeAreaPx(tiktok);         // null — and that is the correct answertiktok.safeArea.reason;     // explains why no fixed table can be right

Meta publishes Reels and Stories as 14% top, 35% bottom, 6% each side. On a 1080×1920 frame that's 269 / 672 / 65 px. The bottom third is not a typo.

safeAreaPx returning null is meaningful — surface it to your user as "this platform publishes no fixed safe area". Don't substitute zeros, and don't borrow another platform's numbers.

subtitles

SRT, WebVTT, and ASS/SSA parsing, conversion, and timing edits. Everything routes through one neutral Cue shape rather than converting format-to-format: six formats would otherwise need thirty converters, each a place a rounding rule can quietly differ.

ts
import { convert, parse, shift, scale, deoverlap }  from '@prismposter/creator-tools/subtitles';
const { output, warnings } = convert(srtText, 'vtt');
// Fix subtitles authored against a different frame rate.scale(parse(srtText).cues, 23.976 / 25);
// Nudge everything 500ms later; cues pushed before zero clamp to zero.shift(cues, 500);
// Clip overlaps so only one cue is ever on screen.deoverlap(cues);

Parsing is tolerant: a malformed block produces a warning and is skipped, rather than costing you the other 899 cues in the file. UTF-8 BOMs and CRLF endings are handled. VTT NOTE/STYLE blocks and inline tags (<v Roger>, <i>) are stripped; ASS override blocks ({\an8}) are too.

ASS stores centiseconds, so an ASS round-trip is lossy below 10 ms. convert() tells you so in warnings rather than letting you discover it later.

tempo

Tap tempo and the beat arithmetic an edit timeline needs.

ts
import { estimateTempo, beatMs, noteMs, beatGrid, snapToBeat }  from '@prismposter/creator-tools/tempo';
estimateTempo(tapTimestamps);// { bpm: 128.02, taps: 16, spreadMs: 8.4, discarded: 1 }
beatMs(120);                              // 500noteMs(120, 'quarter', { triplet: true }); // 333.333beatGrid(120, 10_000);                     // [0, 500, 1000, … 10000]snapToBeat(480, 120);                      // { timeMs: 500, deltaMs: 20 }

The estimator takes the median of a trailing window, not the mean. A tap sequence has two failure modes a mean handles badly: the first taps run late while the user finds the beat, and one missed tap creates an interval at roughly double the true period. Outliers are discarded against the median, because a mean would already have been dragged far enough to keep the bad interval inside tolerance.

spreadMs tells you how much to trust the result — under ~20 ms is a steady tapper, over ~60 ms means the estimate is soft. beatGrid computes each position from its index rather than accumulating, so a long sequence cannot drift.

encoding

File size, bitrate, timecode, and frame counts.

ts
import { fileSizeBytes, targetBitrateKbps, bitsPerPixel, toDropFrame }  from '@prismposter/creator-tools/encoding';
fileSizeBytes(60, 8_000);          // 60_000_000 bytestargetBitrateKbps(120, 50_000_000); // kbps to hit a 50 MB capbitsPerPixel(1920, 1080, 30, 8_000); // 0.1286toDropFrame(1_800, 29.97);           // '00:01:00;02'

Unit convention, stated once: bitrates are decimal (1 Mbps = 1,000,000 bits/s, as every encoder and platform spec means it) and file sizes are binary (1 MiB = 1,048,576 bytes, as every OS reports it). Mixing the two is why online calculators disagree by about 5%. formatBytesBinary and formatBytesDecimal are separate functions so the choice is always explicit.

Drop-frame timecode skips labels, never frames: numbers 00 and 01 are omitted at the start of each minute except every tenth. That's what keeps 29.97 timecode matching wall clock, which non-drop drifts from by ~3.6 s per hour.


palette

Median-cut colour quantisation, plus the contrast maths for putting text on what it returns.

ts
import { extractPalette, toHex, readableTextOn } from '@prismposter/creator-tools/palette';
const swatches = extractPalette(pixels, 5);  // pixels: { r, g, b }[]swatches.map(toHex);                          // ['#1b2430', '#3f6d8e', ...]readableTextOn(swatches[0]);                  // { onColour: 'black' | 'white', ratio: 8.7 }

The box split is chosen at the widest gap along the dominant axis, not at the median pixel count. The textbook median split gives every box the same number of pixels, which is exactly wrong for a photograph: a large flat sky gets subdivided repeatedly while a small saturated accent -- the one colour a designer actually wants -- is averaged into its neighbour and disappears. Splitting at the gap keeps it.

When the source has fewer distinct colours than requested slots you get fewer swatches. Padding the result with near-duplicates would be a palette that lies about the image.

provenance

Is there provenance on this file, and does it say the asset was AI-generated?

ts
import { inspectProvenance } from '@prismposter/creator-tools/provenance';
inspectProvenance(bytes);// { hasC2paManifest: true, hasIptcSourceType: true, hasProvenance: true,//   declaresAiGenerated: true, declaresCapture: false,//   digitalSourceTypes: ['.../digitalsourcetype/trainedAlgorithmicMedia'],//   assertionLabels: ['c2pa.actions.v2', 'c2pa.claim.v2'],//   manifestOffset: 41, signatureVerified: false }

Two markings are in circulation and they are constantly confused:

  1. A C2PA manifest -- a cryptographically signed Content Credential in a JUMBF box.
  2. An IPTC digital source type -- a plain XMP/EXIF string with no signature at all, which anyone can write with exiftool.

A file can carry either, both, or neither. They are reported separately because they carry entirely different weight, and a great many "AI detector" write-ups treat the second as though it were the first.

It does not verify the signature. signatureVerified is always false, deliberately. Proving a manifest is valid needs the full C2PA trust list and certificate-chain validation -- that is what c2patool and c2pa-node are for, and you should use them when trust is the question. This answers the cheaper question those are overkill for, and which is often impossible in a serverless runtime that cannot ship a native binary: is a credential present, and what does it claim? That is the check you want when triaging an upload queue and routing only the interesting files on to a real verifier.

A present manifest is not a trusted manifest. Anyone can sign anything with a self-signed certificate, including a lie.

image-metadata

Read what a file says about itself -- and, more usefully, notice when it says nothing.

ts
import { readImageMetadata, isStripped } from '@prismposter/creator-tools/image-metadata';
const meta = readImageMetadata(bytes);meta.format;   // 'jpeg' | 'png' | 'webp' | 'gif' | ...meta.fields;   // parsed EXIF / XMP / text fieldsisStripped(meta);

Most platforms strip metadata on upload, so an image with none is the normal case rather than a suspicious one. isStripped exists so you can tell a user that instead of showing them an empty table.

gif

An animated GIF encoder: global palette, LZW, sub-blocks, the lot.

ts
import { encodeGif, buildGlobalPalette, indexFrame } from '@prismposter/creator-tools/gif';
const palette = buildGlobalPalette(frames, 256);const bytes = encodeGif({ width, height, palette, frames });

GIF allows 256 colours and one global palette across every frame, so the quantiser matters more than the encoder does -- which is why it shares palette's median cut rather than carrying its own.

mcp (Model Context Protocol Server)

@prismposter/creator-tools ships a zero-dependency MCP stdio server so AI assistants (Claude Desktop, Cursor, Windsurf, Cline) can query verified platform safe areas, aspect-ratio crops, bitrates, and subtitle conversions without hallucinating pixel dimensions.

Add to claude_desktop_config.json or .cursor/mcp.json:

json
{  "mcpServers": {    "prismposter-creator-tools": {      "command": "npx",      "args": ["-y", "@prismposter/creator-tools"]    }  }}

Exposed MCP tools (all read-only, pure local calculations with an output schema):

  • get_social_media_placement — one placement's frame size, safe-area insets in pixels, usable box and first-party documentation URL (instagram-reels, youtube-shorts, tiktok-video, etc.), plus a crop / letterbox plan for your source size
  • list_social_media_placements — every placement, or one platform's, for browsing and comparison
  • check_safe_area — whether a caption, logo or button box stays inside a placement's safe area, and by how many pixels it intrudes past each edge; TikTok answers unknown with the reason
  • calculate_aspect_ratio — simplify any ratio, align to codec blocks, and compute centre-crop / letterbox plans for an arbitrary target ratio
  • estimate_video_bitrate — encoded file size (bytes, MiB, MB), the bitrate that fits a size cap, and bits-per-pixel density
  • convert_subtitles — convert between SRT, WebVTT and ASS/SSA with format detection and a timing shift
  • estimate_tempo — BPM from tap timestamps, or beat and bar lengths for a known BPM

A bad call returns an MCP tool error (isError: true) whose message says how to fix it, for example the valid placement ids for an unknown one.

A hosted version runs at https://www.prismposter.com/api/mcp (Streamable HTTP, no install). It answers from prismposter.com's larger placement dataset (which also accepts the camelCase ids used on the site), takes videoKbps and targetCapMb in its bitrate tool, converts SRT and WebVTT only, and adds a get_prismposter_capabilities tool. Both are listed in the official MCP Registry as com.prismposter/creator-tools.

Design rules

  1. Pure functions, no side effects, no I/O. Everything is synchronous and deterministic.
  2. Invalid input returns null, it does not throw. These functions sit behind text inputs where a half-typed value is normal, not exceptional.
  3. Rounding happens once, at the boundary. Sizes are whole pixels because that's what an encoder takes.
  4. null means "no answer exists", and is always distinguishable from zero.
  5. A wrong type still throws. Rule 2 is about values a user could type. It is not a licence to guess what a caller meant by handing a string to a function that reads bytes.

Development

bash
npm installnpm test          # 173 testsnpm run typechecknpm run build

Contributions welcome — see CONTRIBUTING.md. The bar for a new constant is a first-party source; the bar for a new function is a test that would fail without it.

The same maths, as browser tools

Every module here backs a free tool at prismposter.com/tools -- no account, no upload, no email. If you want the answer rather than the function, start there:

Who maintains this

PrismPoster is an AI content workspace -- image, video, remake, character and music studios that share one project, one asset library, and one timeline you can actually finish in.

This library is the boring half of that product: the arithmetic underneath the studios, extracted because it is genuinely reusable and because a subtitle parser is not a competitive advantage. provenance exists for the same reason in reverse -- building AI disclosure into a media product meant learning where the C2PA tooling is thin, and a dependency-free presence check was the piece that kept being missing.

License

MIT © PrismLabs OÜ

来源:README.md,提交 da90a6e

工具

7

get_social_media_placement

Get one social media placement spec

Look up one social media placement by id and return its frame size, aspect ratio, first-party safe-area insets in px, usable box, and the official page the figures came from. Pass sourceWidth and sourceHeight together to also get the centre-crop and letterbox plan that fits your footage to this placement. Use this when you know the target placement; use list_social_media_placements to browse or compare, check_safe_area to test whether an element is clear of the platform UI, and calculate_aspect_ratio for a ratio that is not a platform placement. For TikTok the insets are null with a reason, because TikTok publishes no fixed safe area. Errors on an unknown id (the message lists valid ids) or on only one source dimension.

输入参数id必填sourceWidthsourceHeight

list_social_media_placements

List social media placement specs

List every supported social media placement (or one platform's) with frame size, aspect ratio, safe-area insets in px, usable box and first-party source URL, plus links to the same dataset as CSV, JSON and its DOI. Use this to browse, compare platforms, or find a placement id; use get_social_media_placement when you already know the id and also need a crop/letterbox plan for your footage. The list is a fixed dataset returned whole, with no paging.

输入参数platform

check_safe_area

Check an element against a placement safe area

Check whether a rectangle (a caption, logo or button, in px on the placement's own frame, origin top-left) stays inside the placement's safe area, and by how many px it intrudes past each edge if not. Use this to validate a layout before export; use get_social_media_placement for the raw insets. Returns verdict "inside", "intrudes" or "unknown"; "unknown" means the platform publishes no fixed safe area (TikTok) and comes with the reason instead of a guess. Errors on an unknown placement id or a box with non-positive size.

输入参数x必填y必填width必填height必填placementId必填

calculate_aspect_ratio

Calculate aspect ratio and crop/pad plan

Reduce any pixel size to its simplest aspect ratio (1920x1080 is 16:9) and the nearest even size an H.264 encoder accepts, and, given a target ratio, solve the missing width or height and return the centre-crop and letterbox/pillarbox plans with the px trimmed or added per edge. Use this for arbitrary sizes and ratios (cinema 2.39:1, a client's 4:5); when the target is a named platform placement, use get_social_media_placement with sourceWidth/sourceHeight instead, which picks the right ratio for you. Errors on a non-integer or out-of-range size, or on only one of targetRatioW/targetRatioH.

输入参数width必填height必填targetRatioHtargetRatioW

estimate_video_bitrate

Estimate video file size and bitrate

Video size and bitrate arithmetic for a clip of durationSec. Pass videoKbps to get the encoded file size (MB, GB, MiB, GiB); pass targetCapMb to get the highest video bitrate that fits that file size. Audio is added at audioKbps (default 192). Every answer also gives the highest video bitrate that fits Discord's 20 MB free upload limit. Kbps is decimal (1 kbps = 1000 bit/s) and MB is 1,000,000 bytes. Use it to plan an export or hit an upload cap; it does not inspect or encode files. Errors when neither videoKbps nor targetCapMb is given.

输入参数audioKbpsvideoKbpsdurationSec必填targetCapMb

convert_subtitles

Convert subtitles between SRT and WebVTT

Convert subtitle text between SubRip (srt) and WebVTT (vtt), optionally shifting every cue by shiftMs, and return the converted text with the detected source format, cue count, parse warnings (with line numbers) and timing issues (overlapping, zero-length or out-of-order cues). Pass the file contents, not a path. Malformed blocks are skipped with a warning instead of failing the whole file. ASS/SSA input is not supported here; the @prismposter/creator-tools package converts it. Errors when no cue could be parsed, the input is over 2 MB, or the shift is beyond one hour.

输入参数input必填shiftMstoFormat必填

estimate_tempo

Estimate tempo, delay times and bar lengths

Tempo arithmetic for editing to music: pass tap timestamps (ms) to estimate BPM with a stability and confidence rating, or pass a known bpm. Either way it returns the beat length, a delay table (straight, dotted and triplet ms for each note value) and how many seconds a number of bars lasts in a time signature. It works on numbers you supply and does not analyse audio. Errors when neither input is given, the taps do not yield a tempo, bpm is outside 30-300, or the time signature is not one listed.

输入参数bpmbarstimestampsMstimeSignature

版本历史

2
  1. v1.0.0最新Oct 24, 2026
  2. v0.5.0Oct 23, 2026

评分

已满足适用检查项的 100%

该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。

  • 近 30 天内可连通必需25 分
  • 已声明认证方式必需10 分
  • 已列出工具必需15 分
  • 描述必需15 分
  • 图标10 分
  • 文档15 分
  • 许可证10 分

其他 Prismposter 集成