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 整合