txtreel
Free iMessage, WhatsApp, Instagram DM and Reddit chat videos (1080x1920 MP4) and screenshots.
我该使用它吗
质量与安全性
发现(4)
- HIGH
- MEDIUM在 chat_validate 中
- MEDIUM在 chat_render_video 中
- MEDIUM在 chat_screenshot 中
基于对工具定义和协议合规性的自动分析。
上下文开销
这是每次将服务器的工具加载到模型上下文窗口时所消耗的大致 token 数。数值越高,可用于其他任务的注意力就越少。
安装
一键安装
将以下内容添加到你的 `claude_desktop_config.json` 文件中:
{
"mcpServers": {
"txtreel": {
"url": "https://txtreel.com/mcp"
}
}
}远程端点
https://txtreel.com/mcpstreamable-http它能做什么
工具清单
工具(5)
🟢chat_validate(platform, theme, contact, script, messages, ...)
Checks a txtreel conversation (script or messages) without rendering anything. It is fast and free. On success returns { ok: true, durationSeconds, messageCount, conversation } where "conversation" is the fully-resolved object (all defaults applied). On failure returns { ok: false, errors: string[] } — one message per problem; when the input was a script, errors are prefixed with the offending line number. Videos longer than the server limit are rejected here too. Conversation script format (one event per line): them: hey, you up? me: yeah why [pause 1.5] wait 1.5 s --- Today 9:41 PM date/time separator me: [photo URL] caption a photo (URL, local file path, or an uploaded photo's number) [them reacts ❤️] reaction on my last message [read] they read my messages === everything above is already on screen at the start === scroll 3 same, but open on the oldest message and skim down in 3 s # comment "Name: text" also means "them" when Name matches contact.name (e.g. contact.name "Sam" lets you write "Sam: omg" instead of "them: omg"). A literal "\n" inside a message becomes a line break. Lines starting with # are comments. Photos: "me: [photo https://example.com/image.jpg] optional caption" (https URLs only; local file paths are not available). "=== scroll 3" opens on the oldest message of a longer history and skims down to the live part in 3 s. With keyboard true (the default), the newest messages stay above the area where the Reels caption sits.
输入模式
{
"type": "object",
"properties": {
"platform": {
"description": "Chat app to render: \"imessage\", \"whatsapp\", or \"instagram\". Default: imessage.",
"type": "string",
"enum": [
"imessage",
"whatsapp",
"instagram"
]
},
"theme": {
"description": "Color theme, \"light\" or \"dark\". Default: light.",
"type": "string",
"enum": [
"light",
"dark"
]
},
"contact": {
"description": "Contact header info.",
"type": "object",
"properties": {
"name": {
"description": "Contact display name shown in the header. Also usable as the \"them\" prefix in script lines. Default: Alex.",
"type": "string",
"maxLength": 60
},
"avatar": {
"description": "Contact avatar as an image URL or a data: URI. Omitted: an initials monogram is drawn instead.",
"type": "string",
"maxLength": 3000000
},
"subtitle": {
"description": "Text under the contact name, e.g. WhatsApp \"online\" or Instagram \"Active now\". Default depends on platform.",
"type": "string",
"maxLength": 60
},
"unread": {
"description": "Unread-count badge shown on the back button.",
"type": "integer",
"minimum": 0,
"maximum": 9999
},
"verified": {
"description": "Show a verified badge next to the contact name.",
"type": "boolean"
}
}
},
"script": {
"description": "Conversation as a plain-text script. Use this OR messages, not both.\n\nConversation script format (one event per line):\n\nthem: hey, you up?\nme: yeah why\n[pause 1.5] wait 1.5 s\n--- Today 9:41 PM date/time separator\nme: [photo URL] caption a photo (URL, local file path, or an uploaded photo's number)\n[them reacts ❤️] reaction on my last message\n[read] they read my messages\n=== everything above is already on screen at the start\n=== scroll 3 same, but open on the oldest message and skim down in 3 s\n# comment\n\n\"Name: text\" also means \"them\" when Name matches contact.name (e.g. contact.name \"Sam\" lets you write \"Sam: omg\" instead of \"them: omg\"). A literal \"\\n\" inside a message becomes a line break. Lines starting with # are comments.\n\nPhotos: \"me: [photo https://example.com/image.jpg] optional caption\" (https URLs only; local file paths are not available). \"=== scroll 3\" opens on the oldest message of a longer history and skims down to the live part in 3 s. With keyboard true (the default), the newest messages stay above the area where the Reels caption sits.",
"type": "string"
},
"messages": {
"description": "Conversation as an array of event objects instead of a script string (use this OR script, not both). Passed through to the txtreel API as-is; each item is one of: {from:\"me\"|\"them\", text, delay?, typing?, hold?, time?, instant?} (type \"message\" is the default and can be omitted), {type:\"pause\", seconds}, {type:\"timestamp\", text, instant?}, {type:\"read\", time?}, {type:\"react\", from:\"me\"|\"them\", emoji}.",
"type": "array",
"items": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
}
},
"startTime": {
"description": "Clock used for messages, read receipts, and WhatsApp bubble times, e.g. \"9:41 PM\". Default: 9:41 PM.",
"type": "string",
"maxLength": 20
},
"speed": {
"description": "Pacing multiplier; 2 = twice as fast, 0.5 = half speed. Default: 1.",
"type": "number",
"minimum": 0.25,
"maximum": 4
},
"keyboard": {
"description": "Show the iOS keyboard, which keeps the latest messages above the Reels caption area. Default: true.",
"type": "boolean"
},
"sounds": {
"description": "Real UI sounds: iOS key clicks while typing, the app's send and receive sounds. Default: true.",
"type": "boolean"
},
"composerTyping": {
"description": "Type \"me\" messages into the input bar before sending them. Default: true.",
"type": "boolean"
},
"autoRead": {
"description": "Mark \"me\" messages as read as soon as the other person starts typing. Default: true.",
"type": "boolean"
},
"endHold": {
"description": "Seconds to hold on the final frame before the video ends. Default: 2.",
"type": "number",
"minimum": 0,
"maximum": 15
},
"statusBar": {
"description": "Phone status bar shown at the top of the frame.",
"type": "object",
"properties": {
"time": {
"description": "Status bar clock text, e.g. \"9:41\". Default: startTime without AM/PM.",
"type": "string",
"maxLength": 10
},
"battery": {
"description": "Battery percentage shown in the status bar. Default: 100.",
"type": "number",
"minimum": 0,
"maximum": 100
},
"signal": {
"description": "Cell signal bars, 0-4. Default: 4.",
"type": "integer",
"minimum": 0,
"maximum": 4
},
"wifi": {
"description": "Show the wifi icon in the status bar. Default: true.",
"type": "boolean"
},
"recording": {
"description": "Red pill behind the time, as in an iPhone screen recording. Makes the clip read as a real screen recording. Default: false.",
"type": "boolean"
}
}
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
}🟡chat_render_video(platform, theme, contact, script, messages, ...)
Render a txtreel conversation (script or messages) to an MP4 and wait for it to finish. This queues a render, waits for it, and returns once it is done (or after failing/timing out). A short render (a handful of messages) typically takes 20-60 seconds. Returns a public link to the MP4; the file is deleted after 24 hours. If txtreel is busy or you hit the rate limit, the result is an error with the message. Conversation script format (one event per line): them: hey, you up? me: yeah why [pause 1.5] wait 1.5 s --- Today 9:41 PM date/time separator me: [photo URL] caption a photo (URL, local file path, or an uploaded photo's number) [them reacts ❤️] reaction on my last message [read] they read my messages === everything above is already on screen at the start === scroll 3 same, but open on the oldest message and skim down in 3 s # comment "Name: text" also means "them" when Name matches contact.name (e.g. contact.name "Sam" lets you write "Sam: omg" instead of "them: omg"). A literal "\n" inside a message becomes a line break. Lines starting with # are comments. Photos: "me: [photo https://example.com/image.jpg] optional caption" (https URLs only; local file paths are not available). "=== scroll 3" opens on the oldest message of a longer history and skims down to the live part in 3 s. With keyboard true (the default), the newest messages stay above the area where the Reels caption sits.
输入模式
{
"type": "object",
"properties": {
"platform": {
"description": "Chat app to render: \"imessage\", \"whatsapp\", or \"instagram\". Default: imessage.",
"type": "string",
"enum": [
"imessage",
"whatsapp",
"instagram"
]
},
"theme": {
"description": "Color theme, \"light\" or \"dark\". Default: light.",
"type": "string",
"enum": [
"light",
"dark"
]
},
"contact": {
"description": "Contact header info.",
"type": "object",
"properties": {
"name": {
"description": "Contact display name shown in the header. Also usable as the \"them\" prefix in script lines. Default: Alex.",
"type": "string",
"maxLength": 60
},
"avatar": {
"description": "Contact avatar as an image URL or a data: URI. Omitted: an initials monogram is drawn instead.",
"type": "string",
"maxLength": 3000000
},
"subtitle": {
"description": "Text under the contact name, e.g. WhatsApp \"online\" or Instagram \"Active now\". Default depends on platform.",
"type": "string",
"maxLength": 60
},
"unread": {
"description": "Unread-count badge shown on the back button.",
"type": "integer",
"minimum": 0,
"maximum": 9999
},
"verified": {
"description": "Show a verified badge next to the contact name.",
"type": "boolean"
}
}
},
"script": {
"description": "Conversation as a plain-text script. Use this OR messages, not both.\n\nConversation script format (one event per line):\n\nthem: hey, you up?\nme: yeah why\n[pause 1.5] wait 1.5 s\n--- Today 9:41 PM date/time separator\nme: [photo URL] caption a photo (URL, local file path, or an uploaded photo's number)\n[them reacts ❤️] reaction on my last message\n[read] they read my messages\n=== everything above is already on screen at the start\n=== scroll 3 same, but open on the oldest message and skim down in 3 s\n# comment\n\n\"Name: text\" also means \"them\" when Name matches contact.name (e.g. contact.name \"Sam\" lets you write \"Sam: omg\" instead of \"them: omg\"). A literal \"\\n\" inside a message becomes a line break. Lines starting with # are comments.\n\nPhotos: \"me: [photo https://example.com/image.jpg] optional caption\" (https URLs only; local file paths are not available). \"=== scroll 3\" opens on the oldest message of a longer history and skims down to the live part in 3 s. With keyboard true (the default), the newest messages stay above the area where the Reels caption sits.",
"type": "string"
},
"messages": {
"description": "Conversation as an array of event objects instead of a script string (use this OR script, not both). Passed through to the txtreel API as-is; each item is one of: {from:\"me\"|\"them\", text, delay?, typing?, hold?, time?, instant?} (type \"message\" is the default and can be omitted), {type:\"pause\", seconds}, {type:\"timestamp\", text, instant?}, {type:\"read\", time?}, {type:\"react\", from:\"me\"|\"them\", emoji}.",
"type": "array",
"items": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
}
},
"startTime": {
"description": "Clock used for messages, read receipts, and WhatsApp bubble times, e.g. \"9:41 PM\". Default: 9:41 PM.",
"type": "string",
"maxLength": 20
},
"speed": {
"description": "Pacing multiplier; 2 = twice as fast, 0.5 = half speed. Default: 1.",
"type": "number",
"minimum": 0.25,
"maximum": 4
},
"keyboard": {
"description": "Show the iOS keyboard, which keeps the latest messages above the Reels caption area. Default: true.",
"type": "boolean"
},
"sounds": {
"description": "Real UI sounds: iOS key clicks while typing, the app's send and receive sounds. Default: true.",
"type": "boolean"
},
"composerTyping": {
"description": "Type \"me\" messages into the input bar before sending them. Default: true.",
"type": "boolean"
},
"autoRead": {
"description": "Mark \"me\" messages as read as soon as the other person starts typing. Default: true.",
"type": "boolean"
},
"endHold": {
"description": "Seconds to hold on the final frame before the video ends. Default: 2.",
"type": "number",
"minimum": 0,
"maximum": 15
},
"statusBar": {
"description": "Phone status bar shown at the top of the frame.",
"type": "object",
"properties": {
"time": {
"description": "Status bar clock text, e.g. \"9:41\". Default: startTime without AM/PM.",
"type": "string",
"maxLength": 10
},
"battery": {
"description": "Battery percentage shown in the status bar. Default: 100.",
"type": "number",
"minimum": 0,
"maximum": 100
},
"signal": {
"description": "Cell signal bars, 0-4. Default: 4.",
"type": "integer",
"minimum": 0,
"maximum": 4
},
"wifi": {
"description": "Show the wifi icon in the status bar. Default: true.",
"type": "boolean"
},
"recording": {
"description": "Red pill behind the time, as in an iPhone screen recording. Makes the clip read as a real screen recording. Default: false.",
"type": "boolean"
}
}
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
}🟡chat_screenshot(platform, theme, contact, script, messages, ...)
Render a single frame of a txtreel conversation (script or messages) to a PNG and return it as an image. Defaults to the last frame — pass "frame" to capture an earlier moment (30 fps). Returns the PNG as image content, plus a text line with the PNG's URL (expires after 24 hours). Conversation script format (one event per line): them: hey, you up? me: yeah why [pause 1.5] wait 1.5 s --- Today 9:41 PM date/time separator me: [photo URL] caption a photo (URL, local file path, or an uploaded photo's number) [them reacts ❤️] reaction on my last message [read] they read my messages === everything above is already on screen at the start === scroll 3 same, but open on the oldest message and skim down in 3 s # comment "Name: text" also means "them" when Name matches contact.name (e.g. contact.name "Sam" lets you write "Sam: omg" instead of "them: omg"). A literal "\n" inside a message becomes a line break. Lines starting with # are comments. Photos: "me: [photo https://example.com/image.jpg] optional caption" (https URLs only; local file paths are not available). "=== scroll 3" opens on the oldest message of a longer history and skims down to the live part in 3 s. With keyboard true (the default), the newest messages stay above the area where the Reels caption sits.
输入模式
{
"type": "object",
"properties": {
"platform": {
"description": "Chat app to render: \"imessage\", \"whatsapp\", or \"instagram\". Default: imessage.",
"type": "string",
"enum": [
"imessage",
"whatsapp",
"instagram"
]
},
"theme": {
"description": "Color theme, \"light\" or \"dark\". Default: light.",
"type": "string",
"enum": [
"light",
"dark"
]
},
"contact": {
"description": "Contact header info.",
"type": "object",
"properties": {
"name": {
"description": "Contact display name shown in the header. Also usable as the \"them\" prefix in script lines. Default: Alex.",
"type": "string",
"maxLength": 60
},
"avatar": {
"description": "Contact avatar as an image URL or a data: URI. Omitted: an initials monogram is drawn instead.",
"type": "string",
"maxLength": 3000000
},
"subtitle": {
"description": "Text under the contact name, e.g. WhatsApp \"online\" or Instagram \"Active now\". Default depends on platform.",
"type": "string",
"maxLength": 60
},
"unread": {
"description": "Unread-count badge shown on the back button.",
"type": "integer",
"minimum": 0,
"maximum": 9999
},
"verified": {
"description": "Show a verified badge next to the contact name.",
"type": "boolean"
}
}
},
"script": {
"description": "Conversation as a plain-text script. Use this OR messages, not both.\n\nConversation script format (one event per line):\n\nthem: hey, you up?\nme: yeah why\n[pause 1.5] wait 1.5 s\n--- Today 9:41 PM date/time separator\nme: [photo URL] caption a photo (URL, local file path, or an uploaded photo's number)\n[them reacts ❤️] reaction on my last message\n[read] they read my messages\n=== everything above is already on screen at the start\n=== scroll 3 same, but open on the oldest message and skim down in 3 s\n# comment\n\n\"Name: text\" also means \"them\" when Name matches contact.name (e.g. contact.name \"Sam\" lets you write \"Sam: omg\" instead of \"them: omg\"). A literal \"\\n\" inside a message becomes a line break. Lines starting with # are comments.\n\nPhotos: \"me: [photo https://example.com/image.jpg] optional caption\" (https URLs only; local file paths are not available). \"=== scroll 3\" opens on the oldest message of a longer history and skims down to the live part in 3 s. With keyboard true (the default), the newest messages stay above the area where the Reels caption sits.",
"type": "string"
},
"messages": {
"description": "Conversation as an array of event objects instead of a script string (use this OR script, not both). Passed through to the txtreel API as-is; each item is one of: {from:\"me\"|\"them\", text, delay?, typing?, hold?, time?, instant?} (type \"message\" is the default and can be omitted), {type:\"pause\", seconds}, {type:\"timestamp\", text, instant?}, {type:\"read\", time?}, {type:\"react\", from:\"me\"|\"them\", emoji}.",
"type": "array",
"items": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
}
},
"startTime": {
"description": "Clock used for messages, read receipts, and WhatsApp bubble times, e.g. \"9:41 PM\". Default: 9:41 PM.",
"type": "string",
"maxLength": 20
},
"speed": {
"description": "Pacing multiplier; 2 = twice as fast, 0.5 = half speed. Default: 1.",
"type": "number",
"minimum": 0.25,
"maximum": 4
},
"keyboard": {
"description": "Show the iOS keyboard, which keeps the latest messages above the Reels caption area. Default: true.",
"type": "boolean"
},
"sounds": {
"description": "Real UI sounds: iOS key clicks while typing, the app's send and receive sounds. Default: true.",
"type": "boolean"
},
"composerTyping": {
"description": "Type \"me\" messages into the input bar before sending them. Default: true.",
"type": "boolean"
},
"autoRead": {
"description": "Mark \"me\" messages as read as soon as the other person starts typing. Default: true.",
"type": "boolean"
},
"endHold": {
"description": "Seconds to hold on the final frame before the video ends. Default: 2.",
"type": "number",
"minimum": 0,
"maximum": 15
},
"statusBar": {
"description": "Phone status bar shown at the top of the frame.",
"type": "object",
"properties": {
"time": {
"description": "Status bar clock text, e.g. \"9:41\". Default: startTime without AM/PM.",
"type": "string",
"maxLength": 10
},
"battery": {
"description": "Battery percentage shown in the status bar. Default: 100.",
"type": "number",
"minimum": 0,
"maximum": 100
},
"signal": {
"description": "Cell signal bars, 0-4. Default: 4.",
"type": "integer",
"minimum": 0,
"maximum": 4
},
"wifi": {
"description": "Show the wifi icon in the status bar. Default: true.",
"type": "boolean"
},
"recording": {
"description": "Red pill behind the time, as in an iPhone screen recording. Makes the clip read as a real screen recording. Default: false.",
"type": "boolean"
}
}
},
"frame": {
"description": "Frame index to capture, at 30 fps (e.g. 30 = one second in). Omit to capture the final frame of the conversation.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
}🟡reddit_render_video(theme, statusBar, subreddit, script, post, ...)
Render a Reddit thread (script, or post+comments) to an MP4 and wait for it to finish. This queues a render, waits for it, and returns once it is done (or after failing/timing out). A short render typically takes 20-60 seconds. Returns a public link to the MP4; the file is deleted after 24 hours. If txtreel is busy or you hit the rate limit, the result is an error with the message. If the thread is invalid, this returns an error result with the validation messages (script errors are prefixed with the offending line number) instead of rendering. Reddit thread script format (post + nested comments): title: AITA for not going to my sister's wedding? body: First paragraph of the post (optional, one line per paragraph) body: Second paragraph [photo URL] a photo in the post (URL, file path or uploaded photo's number) sleepy_joe: A top-level comment > OP: A reply by the post's author (blue OP label) >> sleepy_joe [2.1K 3h]: A reply to that reply, with its votes and age [91 more replies] collapsed replies under the comment above [pause 2] wait 2 s # comment The video is a screen recording of a thread on mobile reddit.com in iOS Safari: the page is laid out once and the view scrolls from block to block, holding each one long enough to read. The title is on screen from frame 0. Scores and ages left out of the script are generated (decreasing down the thread, never older than the post).
输入模式
{
"type": "object",
"properties": {
"theme": {
"description": "Color theme, \"light\" or \"dark\". Default: light.",
"type": "string",
"enum": [
"light",
"dark"
]
},
"statusBar": {
"description": "Phone status bar shown above the Safari toolbar.",
"type": "object",
"properties": {
"time": {
"description": "Status bar clock text, e.g. \"9:41\". Default: \"9:41\".",
"type": "string",
"maxLength": 10
},
"battery": {
"description": "Battery percentage shown in the status bar. Default: 100.",
"type": "number",
"minimum": 0,
"maximum": 100
},
"signal": {
"description": "Cell signal bars, 0-4. Default: 4.",
"type": "integer",
"minimum": 0,
"maximum": 4
},
"wifi": {
"description": "Show the wifi icon in the status bar. Default: true.",
"type": "boolean"
},
"recording": {
"description": "Red pill behind the time, as in an iPhone screen recording. Makes the clip read as a real screen recording. Default: false.",
"type": "boolean"
}
}
},
"subreddit": {
"description": "The subreddit the thread is posted in.",
"type": "object",
"properties": {
"name": {
"description": "Subreddit shown in the header and post byline, without \"r/\". Default: \"AskReddit\".",
"type": "string",
"maxLength": 40
},
"icon": {
"description": "Subreddit icon as an image URL or a data: URI. Omitted: a plain fallback community icon.",
"type": "string",
"maxLength": 3000000
}
}
},
"script": {
"description": "Thread as a plain-text script. Use this OR post/comments, not both.\n\nReddit thread script format (post + nested comments):\n\ntitle: AITA for not going to my sister's wedding?\nbody: First paragraph of the post (optional, one line per paragraph)\nbody: Second paragraph\n[photo URL] a photo in the post (URL, file path or uploaded photo's number)\nsleepy_joe: A top-level comment\n> OP: A reply by the post's author (blue OP label)\n>> sleepy_joe [2.1K 3h]: A reply to that reply, with its votes and age\n[91 more replies] collapsed replies under the comment above\n[pause 2] wait 2 s\n# comment\n\nThe video is a screen recording of a thread on mobile reddit.com in iOS Safari: the page is laid out once and the view scrolls from block to block, holding each one long enough to read. The title is on screen from frame 0. Scores and ages left out of the script are generated (decreasing down the thread, never older than the post).",
"type": "string"
},
"post": {
"description": "The post. Use this OR script, not both.",
"type": "object",
"properties": {
"title": {
"description": "The post title. Required when not using script — this is the hook, on screen from frame 0.",
"type": "string",
"minLength": 1,
"maxLength": 400
},
"body": {
"description": "Post body text; each line becomes its own paragraph and gets its own reading beat.",
"type": "string",
"maxLength": 40000
},
"image": {
"description": "A photo under the title: image URL or data: URI.",
"type": "string",
"maxLength": 15000000
},
"author": {
"description": "Poster's username. Default: \"throwaway_4412\".",
"type": "string",
"maxLength": 40
},
"age": {
"description": "Post age, e.g. \"5h\". Default: \"5h\".",
"type": "string",
"maxLength": 20
},
"score": {
"description": "Post votes as shown, e.g. \"14K\". Default: made up, always above the top comment.",
"type": "string",
"maxLength": 12
},
"comments": {
"description": "Comment count shown on the post, e.g. \"1.2K\". Default: made up.",
"type": "string",
"maxLength": 12
},
"flair": {
"description": "Post flair, e.g. \"Not the A-hole\".",
"type": "string",
"maxLength": 60
},
"flairColor": {
"description": "Flair background color (CSS color). Default: a Reddit blue.",
"type": "string",
"maxLength": 30
}
}
},
"comments": {
"description": "Comments as an array of event objects instead of a script string (use this OR script, not both). Each item is one of: {author, text, depth (0 top-level, 1 reply to the nearest depth-0 comment above, 2 reply to that, …), score?, age?, op?, avatar?, moreReplies?, hold?} or {type:\"pause\", seconds}. \"op\" or an author matching the post author gets the blue OP label automatically.",
"type": "array",
"items": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
}
},
"speed": {
"description": "Pacing multiplier; 2 = twice as fast, 0.5 = half speed. Default: 1. Use 1.3-1.5 for a faster reel.",
"type": "number",
"minimum": 0.25,
"maximum": 4
},
"endHold": {
"description": "Seconds to hold on the final frame before the video ends. Default: 2.",
"type": "number",
"minimum": 0,
"maximum": 15
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
}🟡reddit_screenshot(theme, statusBar, subreddit, script, post, ...)
Render a single frame of a Reddit thread (script, or post+comments) to a PNG and return it as an image. Defaults to the last frame — pass "frame" to capture an earlier moment (30 fps). Returns the PNG as image content, plus a text line with the PNG's URL (expires after 24 hours). If the thread is invalid, this returns an error result with the validation messages instead of an image. Reddit thread script format (post + nested comments): title: AITA for not going to my sister's wedding? body: First paragraph of the post (optional, one line per paragraph) body: Second paragraph [photo URL] a photo in the post (URL, file path or uploaded photo's number) sleepy_joe: A top-level comment > OP: A reply by the post's author (blue OP label) >> sleepy_joe [2.1K 3h]: A reply to that reply, with its votes and age [91 more replies] collapsed replies under the comment above [pause 2] wait 2 s # comment The video is a screen recording of a thread on mobile reddit.com in iOS Safari: the page is laid out once and the view scrolls from block to block, holding each one long enough to read. The title is on screen from frame 0. Scores and ages left out of the script are generated (decreasing down the thread, never older than the post).
输入模式
{
"type": "object",
"properties": {
"theme": {
"description": "Color theme, \"light\" or \"dark\". Default: light.",
"type": "string",
"enum": [
"light",
"dark"
]
},
"statusBar": {
"description": "Phone status bar shown above the Safari toolbar.",
"type": "object",
"properties": {
"time": {
"description": "Status bar clock text, e.g. \"9:41\". Default: \"9:41\".",
"type": "string",
"maxLength": 10
},
"battery": {
"description": "Battery percentage shown in the status bar. Default: 100.",
"type": "number",
"minimum": 0,
"maximum": 100
},
"signal": {
"description": "Cell signal bars, 0-4. Default: 4.",
"type": "integer",
"minimum": 0,
"maximum": 4
},
"wifi": {
"description": "Show the wifi icon in the status bar. Default: true.",
"type": "boolean"
},
"recording": {
"description": "Red pill behind the time, as in an iPhone screen recording. Makes the clip read as a real screen recording. Default: false.",
"type": "boolean"
}
}
},
"subreddit": {
"description": "The subreddit the thread is posted in.",
"type": "object",
"properties": {
"name": {
"description": "Subreddit shown in the header and post byline, without \"r/\". Default: \"AskReddit\".",
"type": "string",
"maxLength": 40
},
"icon": {
"description": "Subreddit icon as an image URL or a data: URI. Omitted: a plain fallback community icon.",
"type": "string",
"maxLength": 3000000
}
}
},
"script": {
"description": "Thread as a plain-text script. Use this OR post/comments, not both.\n\nReddit thread script format (post + nested comments):\n\ntitle: AITA for not going to my sister's wedding?\nbody: First paragraph of the post (optional, one line per paragraph)\nbody: Second paragraph\n[photo URL] a photo in the post (URL, file path or uploaded photo's number)\nsleepy_joe: A top-level comment\n> OP: A reply by the post's author (blue OP label)\n>> sleepy_joe [2.1K 3h]: A reply to that reply, with its votes and age\n[91 more replies] collapsed replies under the comment above\n[pause 2] wait 2 s\n# comment\n\nThe video is a screen recording of a thread on mobile reddit.com in iOS Safari: the page is laid out once and the view scrolls from block to block, holding each one long enough to read. The title is on screen from frame 0. Scores and ages left out of the script are generated (decreasing down the thread, never older than the post).",
"type": "string"
},
"post": {
"description": "The post. Use this OR script, not both.",
"type": "object",
"properties": {
"title": {
"description": "The post title. Required when not using script — this is the hook, on screen from frame 0.",
"type": "string",
"minLength": 1,
"maxLength": 400
},
"body": {
"description": "Post body text; each line becomes its own paragraph and gets its own reading beat.",
"type": "string",
"maxLength": 40000
},
"image": {
"description": "A photo under the title: image URL or data: URI.",
"type": "string",
"maxLength": 15000000
},
"author": {
"description": "Poster's username. Default: \"throwaway_4412\".",
"type": "string",
"maxLength": 40
},
"age": {
"description": "Post age, e.g. \"5h\". Default: \"5h\".",
"type": "string",
"maxLength": 20
},
"score": {
"description": "Post votes as shown, e.g. \"14K\". Default: made up, always above the top comment.",
"type": "string",
"maxLength": 12
},
"comments": {
"description": "Comment count shown on the post, e.g. \"1.2K\". Default: made up.",
"type": "string",
"maxLength": 12
},
"flair": {
"description": "Post flair, e.g. \"Not the A-hole\".",
"type": "string",
"maxLength": 60
},
"flairColor": {
"description": "Flair background color (CSS color). Default: a Reddit blue.",
"type": "string",
"maxLength": 30
}
}
},
"comments": {
"description": "Comments as an array of event objects instead of a script string (use this OR script, not both). Each item is one of: {author, text, depth (0 top-level, 1 reply to the nearest depth-0 comment above, 2 reply to that, …), score?, age?, op?, avatar?, moreReplies?, hold?} or {type:\"pause\", seconds}. \"op\" or an author matching the post author gets the blue OP label automatically.",
"type": "array",
"items": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
}
},
"speed": {
"description": "Pacing multiplier; 2 = twice as fast, 0.5 = half speed. Default: 1. Use 1.3-1.5 for a faster reel.",
"type": "number",
"minimum": 0.25,
"maximum": 4
},
"endHold": {
"description": "Seconds to hold on the final frame before the video ends. Default: 2.",
"type": "number",
"minimum": 0,
"maximum": 15
},
"frame": {
"description": "Frame index to capture, at 30 fps (e.g. 30 = one second in). Omit to capture the final frame of the thread.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
}社区
证据