---
title: "meme.render@1 · OpenVibe.Services"
canonical: "https://openvibe.services/docs/contracts/meme.render"
updated: null
---

# meme.render@1 · OpenVibe.Services

HTML: [meme.render@1 · OpenVibe.Services](https://openvibe.services/docs/contracts/meme.render)

# MemeRenderRequest `meme.render@1`

Generated at 2026-11-13 06:25:48 UTC from [`openvibe-contracts v0.419.0`](https://github.com/OpenVibers/OpenVibe.Contracts/tree/v0.419.0) and [`openvibe-sdk v0.161.0`](https://github.com/OpenVibers/OpenVibe.SDK/tree/v0.161.0).

- Version: 1.0.0
- Owner: meme
- Visibility: public
- Status: active
- Compatibility: backward
- Schema: [`https://openvibe.network/contracts/meme/render.v1.json`](/docs/contracts/meme.render.json)

meme.render@1: a request to render 1–4 caption lines over an approved template. PNG is the default; GIF and MP4 return short, looped exports. Editor positions and crop coordinates are percentages of the canvas.

## Fields

| Field | Type | Required | Description | Constraints |
| --- | --- | --- | --- | --- |
| `template_id` | string | yes |  | - `minLength 1`<br>- `maxLength 80` |
| `lines` | array of string | yes |  | - `minItems 1`<br>- `maxItems 4`<br>- `items: maxLength 120` |
| `format` | enum |  |  | - `one of "png", "gif", "mp4"`<br>- `default "png"` |
| `editor` | object |  |  | - `no other fields` |
| `editor.font_style` | enum |  |  | - `one of "impact", "modern", "soft"` |
| `editor.font_size` | integer |  |  | - `minimum 10`<br>- `maximum 64` |
| `editor.color` | string |  |  | - `pattern ^#[0-9a-fA-F]{6}$` |
| `editor.outline` | string |  |  | - `pattern ^#[0-9a-fA-F]{6}$` |
| `editor.outline_width` | integer |  |  | - `minimum 0`<br>- `maximum 8` |
| `editor.crop_x` | number |  |  | - `minimum 0`<br>- `maximum 100` |
| `editor.crop_y` | number |  |  | - `minimum 0`<br>- `maximum 100` |
| `editor.boxes` | array of object |  |  | - `minItems 1`<br>- `maxItems 4`<br>- `items: no other fields` |
| `editor.boxes[].x` | number | yes |  | - `minimum 0`<br>- `maximum 100` |
| `editor.boxes[].y` | number | yes |  | - `minimum 0`<br>- `maximum 100` |
| `editor.boxes[].w` | number | yes |  | - `maximum 100` |
| `editor.boxes[].h` | number | yes |  | - `maximum 100` |
| `editor.stickers` | array of object |  |  | - `maxItems 8`<br>- `items: no other fields` |
| `editor.stickers[].emoji` | enum | yes |  | - `one of "✨", "😂", "🔥", "💀", "👀", "❤️", "🙌"` |
| `editor.stickers[].x` | number | yes |  | - `minimum 0`<br>- `maximum 100` |
| `editor.stickers[].y` | number | yes |  | - `minimum 0`<br>- `maximum 100` |

## Examples

From the contract's own test fixtures: valid ones validate, rejected ones must fail.

 Valid: editor-mp4

~~~~
{
  "template_id": "tpl_classic",
  "lines": [
    "Ship the fix",
    "then celebrate"
  ],
  "format": "mp4",
  "editor": {
    "font_style": "impact",
    "font_size": 30,
    "color": "#ffffff",
    "outline": "#000000",
    "outline_width": 3,
    "crop_x": 50,
    "crop_y": 50,
    "boxes": [
      {
        "x": 5,
        "y": 7,
        "w": 90,
        "h": 24
      },
      {
        "x": 5,
        "y": 68,
        "w": 90,
        "h": 24
      }
    ],
    "stickers": [
      {
        "emoji": "🔥",
        "x": 52,
        "y": 54
      }
    ]
  }
}
~~~~

Rejected: empty-lines

~~~~
{
  "template_id": "tpl_classic",
  "lines": [],
  "format": "png"
}
~~~~

## Validate

~~~~
const contracts = require('openvibe-contracts');
contracts.validate('meme.render@1', value);   // { valid, errors: [{ path, message }] }
~~~~
