rendry-io · Schema
TextFit
What the finished render MEASURED for one text layer. Every number is in DSL layout coordinates.
CompanyImage RenderingPDF GenerationTemplate EngineAPIAI Integration
Properties
| Name | Type | Description |
|---|---|---|
| id | string | The measured layer's own id. This is why text_fit is a list: the entry names its layer, the list does not |
| plate | object | Present only for an assembled text plate |
| rotation_origin | object | Present for ordinary raster text with rotation or flips; native document text uses its own placement |
| raster_top | integer | Where the raster image put the top of the text block under vertical_align center or bottom, in whole pixels below the layer's y; absent for top alignment, no box height, a plate, and PDF or HTML outpu |
| size | integer | The size that was asked for |
| fitted_size | integer | The size auto_fit settled on; equal to size when nothing shrank |
| text_w | integer | Width of the rendered text mask |
| text_h | integer | Height of the rendered text mask |
| box_w | integer | Declared layer width; 0 means unconstrained |
| box_h | integer | Declared layer height; 0 means unconstrained |
| lines | integer | Lines after wrapping, not only explicit newlines |
| wraps | array | Where the render broke the text for width: the rune offset, in the text as drawn (variables substituted, list markers and soft hyphens in place, rich_text ** pairs removed), at which each line begins |
| kept_spaces | array | Visible-rune offsets of whitespace replaced with non-breaking spaces by keep_last_words. Shares the wraps coordinate system; absent when no spaces changed. The editor applies these exact substitutions |
| mask_x | integer | mask_text placement inside a shape or image |
| mask_y | integer | |
| mask_w | integer | |
| mask_h | integer | |
| ink_top | integer | Mask offset from the logical text box; a diagnostic, not an alignment source — Pango bounds can include empty rows |
| ink_left | integer | |
| fit_group | string | The layer's fit_group name, present only for a member of one |
| size_alone | integer | The size this member would have taken fitted BY ITSELF, before the group levelled. Present only for a member of a fit_group; a layer in no group reports fitted_size and nothing more |
| fit_group_size | integer | The size the group settled on — the smallest size_alone among its members. A member whose own min_size is above it keeps min_size, so fitted_size can exceed fit_group_size. Present only for a member o |
| origin | object | |
| list_paragraphs | array | Native list geometry on the wraps rune coordinate system; includes blank/trailing paragraphs. Absent for ordinary non-list text. |
| logical_h | integer | Native logical block height for lists and clip_lines, including blank lines and fallback-font metrics; absent legacy measurements keep existing line-step behavior. |
| clip_end | integer | Exclusive rune endpoint in the final parsed/formatted source, present only when clip_lines removed a suffix. Zero keeps a leading blank line. Slice already parsed styled content before applying wraps/ |
| lines_cut | integer | Number of complete native lines removed by clip_lines after full-source fitting. lines is the retained count. Absent when no lines were cut. |
JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://artifacts.apis.io/rendry-io/json-schema/rendry-io-text-fit-schema.json",
"title": "TextFit",
"description": "What the finished render MEASURED for one text layer. Every number is in DSL layout coordinates.",
"x-generated": "2026-10-31",
"x-method": "derived",
"x-generator": "derive-json-schema.py",
"x-source": "openapi/rendry-io-openapi.json#/components/schemas/TextFit",
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The measured layer's own id. This is why text_fit is a list: the entry names its layer, the list does not"
},
"plate": {
"$ref": "#/$defs/TextPlateFit",
"description": "Present only for an assembled text plate"
},
"rotation_origin": {
"$ref": "#/$defs/TextRotationOrigin",
"description": "Present for ordinary raster text with rotation or flips; native document text uses its own placement"
},
"raster_top": {
"type": "integer",
"description": "Where the raster image put the top of the text block under vertical_align center or bottom, in whole pixels below the layer's y; absent for top alignment, no box height, a plate, and PDF or HTML output"
},
"size": {
"type": "integer",
"description": "The size that was asked for"
},
"fitted_size": {
"type": "integer",
"description": "The size auto_fit settled on; equal to size when nothing shrank"
},
"text_w": {
"type": "integer",
"description": "Width of the rendered text mask"
},
"text_h": {
"type": "integer",
"description": "Height of the rendered text mask"
},
"box_w": {
"type": "integer",
"description": "Declared layer width; 0 means unconstrained"
},
"box_h": {
"type": "integer",
"description": "Declared layer height; 0 means unconstrained"
},
"lines": {
"type": "integer",
"description": "Lines after wrapping, not only explicit newlines"
},
"wraps": {
"type": "array",
"items": {
"type": "integer"
},
"description": "Where the render broke the text for width: the rune offset, in the text as drawn (variables substituted, list markers and soft hyphens in place, rich_text ** pairs removed), at which each line begins because the line before it was full. A line an explicit newline starts is not listed; absent when nothing wrapped. The editor draws its lines at these offsets"
},
"kept_spaces": {
"type": "array",
"items": {
"type": "integer"
},
"description": "Visible-rune offsets of whitespace replaced with non-breaking spaces by keep_last_words. Shares the wraps coordinate system; absent when no spaces changed. The editor applies these exact substitutions before painting."
},
"mask_x": {
"type": "integer",
"description": "mask_text placement inside a shape or image"
},
"mask_y": {
"type": "integer"
},
"mask_w": {
"type": "integer"
},
"mask_h": {
"type": "integer"
},
"ink_top": {
"type": "integer",
"description": "Mask offset from the logical text box; a diagnostic, not an alignment source — Pango bounds can include empty rows"
},
"ink_left": {
"type": "integer"
},
"fit_group": {
"type": "string",
"description": "The layer's fit_group name, present only for a member of one"
},
"size_alone": {
"type": "integer",
"description": "The size this member would have taken fitted BY ITSELF, before the group levelled. Present only for a member of a fit_group; a layer in no group reports fitted_size and nothing more"
},
"fit_group_size": {
"type": "integer",
"description": "The size the group settled on — the smallest size_alone among its members. A member whose own min_size is above it keeps min_size, so fitted_size can exceed fit_group_size. Present only for a member of a fit_group"
},
"origin": {
"$ref": "#/$defs/TextDiagnosticOrigin"
},
"list_paragraphs": {
"type": "array",
"items": {
"$ref": "#/$defs/ListParagraph"
},
"description": "Native list geometry on the wraps rune coordinate system; includes blank/trailing paragraphs. Absent for ordinary non-list text."
},
"logical_h": {
"type": "integer",
"minimum": 1,
"maximum": 2097151,
"description": "Native logical block height for lists and clip_lines, including blank lines and fallback-font metrics; absent legacy measurements keep existing line-step behavior."
},
"clip_end": {
"type": "integer",
"minimum": 0,
"description": "Exclusive rune endpoint in the final parsed/formatted source, present only when clip_lines removed a suffix. Zero keeps a leading blank line. Slice already parsed styled content before applying wraps/list_paragraphs; this is server observation, never authored DSL."
},
"lines_cut": {
"type": "integer",
"minimum": 0,
"description": "Number of complete native lines removed by clip_lines after full-source fitting. lines is the retained count. Absent when no lines were cut."
}
},
"$defs": {
"ListParagraph": {
"type": "object",
"additionalProperties": false,
"required": [
"rune_offset",
"prefix_runes",
"reserve_px",
"continued",
"rtl"
],
"properties": {
"rune_offset": {
"type": "integer",
"minimum": 0,
"description": "Paragraph start in the same final parsed rune stream as wraps, including blank paragraphs."
},
"prefix_runes": {
"type": "integer",
"minimum": 0,
"description": "Drawn marker/indent prefix length; zero for a midparagraph flow continuation."
},
"reserve_px": {
"type": "number",
"description": "Native physical continuation reserve in layout pixels: positive left, negative right, zero centered or unconstrained. Never infer RTL from this sign."
},
"continued": {
"type": "boolean",
"description": "Keeps an earlier paragraph marker reserve without drawing that marker again."
},
"rtl": {
"type": "boolean",
"description": "Original native resolved paragraph direction, including empty and continued paragraphs."
}
},
"description": "Measured list paragraph geometry. Bind it and wraps to unchanged render inputs; ordinary non-list text omits this array. Literal list newlines normalize CRLF/CR to LF before formatting."
},
"TextDiagnosticOrigin": {
"type": "object",
"properties": {
"key": {
"type": "string",
"description": "Server-created prepared structural identity; independent of generated cell IDs."
},
"layer_id": {
"type": "string",
"description": "Safe authored layer identifier; values and paths are excluded."
},
"table": {
"type": "boolean"
},
"master": {
"type": "boolean"
},
"page": {
"type": "integer",
"description": "Final page, 1-based."
},
"row": {
"type": "integer",
"description": "Original body row, 1-based; header and footer row zero."
},
"column": {
"type": "integer",
"description": "Column, 1-based."
},
"header": {
"type": "boolean"
},
"master_kind": {
"type": "string",
"enum": [
"first",
"even"
],
"description": "Present for replacement-master origins in diagnostics v2; keys use master_first/N or master_even/N. Default-only diagnostics remain v1."
},
"footer": {
"type": "boolean",
"description": "True for the final table footer; row is zero and header is false."
}
}
},
"TextPlateFit": {
"type": "object",
"description": "Actual unrotated text plate assembly in DSL pixels, before effects and output scaling. Text coordinates identify the logical text box, not tight glyph bounds.",
"required": [
"x",
"y",
"width",
"height",
"text_x",
"text_y",
"text_width"
],
"properties": {
"x": {
"type": "integer",
"description": "Plate left relative to the layer origin"
},
"y": {
"type": "integer",
"description": "Plate top relative to the layer origin"
},
"width": {
"type": "integer",
"description": "Assembled plate width after minimum size and circle sizing"
},
"height": {
"type": "integer",
"description": "Assembled plate height after minimum size and circle sizing"
},
"text_x": {
"type": "integer",
"description": "Logical text origin inside the plate, including stroke and bearing placement"
},
"text_y": {
"type": "integer",
"description": "Logical text origin inside the plate"
},
"text_width": {
"type": "integer",
"description": "Resolved advance or constrained wrap width"
}
}
},
"TextRotationOrigin": {
"type": "object",
"description": "Actual pre-transform assembly center of ordinary raster text relative to the layer origin, in DSL pixels. Half-pixel centers are preserved.",
"required": [
"x",
"y"
],
"properties": {
"x": {
"type": "number"
},
"y": {
"type": "number"
}
}
}
}
}
Work with this as data
Every JSON Schema here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for schemas
4 MCP tools reach this
find_json_schemasBrowse and filter every JSON Schema in the catalog.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.
Call it yourself
curl for this page
This JSON Schema
curl "https://apis.io/api/v1/json-schemas/rendry-io-text-fit"
All schemas
curl "https://apis.io/api/v1/json-schemas?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.