{"id":23882932,"url":"https://github.com/zhengqbbb/x-satori","last_synced_at":"2025-10-13T00:31:12.085Z","repository":{"id":143647800,"uuid":"613921032","full_name":"Zhengqbbb/x-satori","owner":"Zhengqbbb","description":"🌠 Using Astro or Vue file to generate cover, card, Open Graph ... image SVG, powered by Satori and Vite","archived":false,"fork":false,"pushed_at":"2025-07-30T10:54:18.000Z","size":29212,"stargazers_count":52,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-09-19T06:10:22.199Z","etag":null,"topics":["astro","opengragh","opengraph","opengraph-images","satori","satori-html","vite","vue"],"latest_commit_sha":null,"homepage":"https://stackblitz.com/@Zhengqbbb/collections/x-satori-demo","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Zhengqbbb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["Zhengqbbb"],"custom":["https://afdian.net/a/qbbsh"]}},"created_at":"2023-03-14T14:33:52.000Z","updated_at":"2025-09-11T13:34:38.000Z","dependencies_parsed_at":null,"dependency_job_id":"caf6d369-7263-41ca-8895-2a1f6927ef7a","html_url":"https://github.com/Zhengqbbb/x-satori","commit_stats":null,"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/Zhengqbbb/x-satori","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Zhengqbbb%2Fx-satori","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Zhengqbbb%2Fx-satori/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Zhengqbbb%2Fx-satori/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Zhengqbbb%2Fx-satori/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Zhengqbbb","download_url":"https://codeload.github.com/Zhengqbbb/x-satori/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Zhengqbbb%2Fx-satori/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279013643,"owners_count":26085298,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-12T02:00:06.719Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["astro","opengragh","opengraph","opengraph-images","satori","satori-html","vite","vue"],"created_at":"2025-01-04T02:59:05.874Z","updated_at":"2025-10-13T00:31:08.829Z","avatar_url":"https://github.com/Zhengqbbb.png","language":"TypeScript","funding_links":["https://github.com/sponsors/Zhengqbbb","https://afdian.net/a/qbbsh"],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003ex-satori\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://www.npmjs.com/package/x-satori\"\u003e\n        \u003cimg alt=\"version\" src=\"https://img.shields.io/npm/v/x-satori?color=212121\u0026label=\"\u003e\n    \u003c/a\u003e\u003cbr\u003e\u003cbr\u003e\n    Use \u003cb\u003eVue and Astro file to generate SVG image\u003c/b\u003e by \u003ca href=\"https://github.com/vercel/satori\"\u003eSatori\u003c/a\u003e.\u003cbr\u003e\n    The image can be generated by running ESM script or CLI.\n\u003c/p\u003e\n\u003cbr\u003e\n\u003ctable\u003e\n    \u003ctr\u003e\n        \u003ctd align=\"center\" width=\"50%\"\u003e\n        \u003cbr\u003e\n            \u003cp\u003e\u003cb\u003e\u003ca href=\"#-vue\"\u003eVue\u003c/a\u003e\u003c/b\u003e\u003c/p\u003e\n            \u003ca href=\"https://stackblitz.com/edit/x-satori?file=package.json\"\u003e\n                \u003cimg alt=\"Open in StackBlitz\" src=\"https://developer.stackblitz.com/img/open_in_stackblitz.svg\"\u003e\n            \u003c/a\u003e\n        \u003c/td\u003e\n        \u003ctd align=\"center\" width=\"50%\"\u003e\n        \u003cbr\u003e\n            \u003cp\u003e\u003cb\u003e\u003ca href=\"#-astro\"\u003eAstro\u003c/a\u003e\u003c/b\u003e\u003c/p\u003e\n            \u003ca href=\"https://stackblitz.com/edit/x-satori-astro?file=package.json\"\u003e\n                \u003cimg alt=\"Open in StackBlitz\" src=\"https://developer.stackblitz.com/img/open_in_stackblitz.svg\"\u003e\n            \u003c/a\u003e\n        \u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd align=\"center\" width=\"50%\"\u003e\n            \u003ca href=\"https://youtu.be/8HkJg1a_Zew\"\u003e\n                \u003cimg alt=\"youtube guide demo\" src=\"./demo-vue.gif\"\u003e\n            \u003c/a\u003e\n            \u003cbr\u003e\n            \u003cbr\u003e\n            \u003ca href=\"https://x.com/zhengqbbb/status/1637849646075908096\"\u003e\n                \u003cimg alt=\"View on Twitter post\" src=\"https://cdn.jsdelivr.net/gh/Zhengqbbb/Zhengqbbb@v1.1.1/icons/view-twitter-post.svg\"\u003e\n            \u003c/a\u003e\n        \u003c/td\u003e\n        \u003ctd align=\"center\" width=\"50%\"\u003e\n            \u003ca href=\"https://youtu.be/LG8PDLZHEts\"\u003e\n                \u003cimg alt=\"youtube guide demo\" src=\"./demo-astro.gif\"\u003e\n            \u003c/a\u003e\n            \u003cbr\u003e\n            \u003cbr\u003e\n            \u003ca href=\"https://x.com/zhengqbbb/status/1817191553217241130\"\u003e\n                \u003cimg alt=\"View on Twitter post\" src=\"https://cdn.jsdelivr.net/gh/Zhengqbbb/Zhengqbbb@v1.1.1/icons/view-twitter-post.svg\"\u003e\n            \u003c/a\u003e\n        \u003c/td\u003e\n    \u003c/tr\u003e\n\u003c/table\u003e\n\n---\n\n\u003e Local running example demo\n\n```sh\nnpx degit Zhengqbbb/x-satori/playground/vue   \u003cfile_name\u003e     # Vue\nnpx degit Zhengqbbb/x-satori/playground/astro \u003cfile_name\u003e     # Astro\n\ncd \u003cfile_name\u003e\npnpm install\n\n# Development Model\npnpm dev:og\n\n# [Generate] SVG\npnpm gen:svg\n\n# [Generate] PNG\npnpm gen:png\n```\n\n## Usage\n\n```sh\nnpm install -D x-satori\n```\n\n### ⭐ Vue\n\n\u003cdetails\u003e\n\u003csummary\u003eUsing Vitepress \u003ca href=\"https://vitepress.dev/reference/site-config#buildend\"\u003ebuildEnd hook\u003c/a\u003e\u003c/summary\u003e\u003cbr\u003e\n\n- **Example**: [examples/vue-vitepress](./examples/vue-vitepress/) ⭐⭐⭐\n\n\u003c/details\u003e\n\n\n\u003cdetails\u003e\n\u003csummary\u003eUsing CLI\u003c/summary\u003e\u003cbr\u003e\n\n**Example**: [playground/vue](./playground/vue/)\n\n- Dependency: **Vue | Vite**\n\n```sh\n$ npx x-satori --help\n\nSYNOPSIS:\n    x-satori --template \u003ctemplate_file_path\u003e --config \u003csatori_config_path\u003e [--props \u003cJSON\u003e]\n    x-satori --template \u003ctemplate_file_path\u003e --config \u003csatori_config_path\u003e [--props \u003cJSON\u003e] --output \u003csvg_path\u003e\n    x-satori --template \u003ctemplate_file_path\u003e --config \u003csatori_config_path\u003e [--props \u003cJSON\u003e] --dev [--host --port \u003cnum\u003e]\n\nOPTIONS:\n    -d|--dev                   Turn on Dev mode\n       --host                  Expose  host in Dev mode\n       --port     \u003cnum\u003e        Specify port in Dev mode\n    -t|--template \u003cpath\u003e       The Vue or Astro template file path\n    -c|--config   \u003cpath\u003e       The export satori configure file path\n    -o|--output   \u003cpath\u003e       Target output SVG path\n    --props       \u003cJSON_str\u003e   Overwrite and use props in config\n\nEXAMPLES:\n    x-satori --config \"./satori.ts\" --template \"./Template.vue\" --dev --host\n    x-satori --config \"./satori.ts\" --template \"./Template.vue\"\n    x-satori --config \"./satori.js\" --template \"./Template.vue\" --props '{\"title\": \"Hello World\"}'\n    x-satori --config \"./satori.js\" --template \"./Template.vue\" -o image.svg\n```\n\n#### Configure\n\n- Extends Satori options and add Vue file props option\n\n```mjs\nimport { defineSatoriConfig } from 'x-satori/vue'\n\nexport default defineSatoriConfig({\n    // ... Satori options\n    props: {\n        // ...Vue SFC props options\n        // title: \"Hello world\"\n    },\n})\n```\n\n#### Vue template file\n\n- **Only the template syntax is used**, and props are only used for hint completion\n- [→ Satori supports common CSS features](https://github.com/vercel/satori#css)\n- [→ Tailwindcss documentation](https://tailwindcss.com/docs/customizing-colors)\n\n```html\n\u003cscript setup lang=\"ts\"\u003e\nconst props = defineProps({\n  title: String,\n})\n\u003c/script\u003e\n\u003ctemplate\u003e\n  \u003cdiv class=\"w-full h-full flex text-white bg-blue-500 items-center justify-center\"\u003e\n    \u003ch1 :style=\"{ fontSize: '70px' }\"\u003e\n      {{ title }} 👋\n    \u003c/h1\u003e\n  \u003c/div\u003e\n\u003c/template\u003e\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eUsing ESM script\u003c/summary\u003e\u003cbr\u003e\n\n- Dependency: **Vue**\n\n```mjs\nimport { defineSatoriConfig, satoriVue } from 'x-satori/vue'\n\nfunction main() {\n    const _DIRNAME = typeof __dirname !== 'undefined'\n        ? __dirname\n        : dirname(fileURLToPath(import.meta.url))\n    const _OUTPUT = resolve(_DIRNAME, './image/og.png')\n\n    const templateStr = await readFile(resolve(_DIRNAME, './Template.vue'), 'utf8')\n    const opt = defineSatoriConfig({\n    // ... Satori options\n        props: {\n        // ...Vue SFC props options\n        // title: \"Hello world\"\n        },\n    })\n    const strSVG = await satoriVue(opt, templateStr)\n    console.log(strSVG)\n}\nmain()\n```\n\n- **Example**: [examples/vue-run-esm-script](./examples/vue-run-esm-script/)\n\n    ```sh\n    npm run gen:svg\n    npm run gen:png\n    ```\n\n\u003c/details\u003e\n\n### ⭐ Astro\n\n\u003cdetails\u003e\n    \u003csummary\u003eUsing Astro \u003ca href=\"https://docs.astro.build/en/guides/endpoints/\"\u003efile-endpoints\u003c/a\u003e\u003c/summary\u003e\u003cbr\u003e\n\n- **Example**: [examples/astro-file-endpoint](./examples/astro-file-endpoint/) ⭐⭐⭐\n- **Example**: [Repo - Zhengqbbb/qbb.sh](https://github.com/Zhengqbbb/qbb.sh/blob/astro/src/pages/og/%5Bslug%5D.png.ts)\n\n\n\n---\n\n#### 1. Install Dependencies\n\n```sh\nnpm install -D x-satori @resvg/resvg-js # Convert SVG to PNG\n```\n\n#### 2. Create Astro [file-endpoints](https://docs.astro.build/en/guides/endpoints/)\n\n\u003e If target is generate `dist/og/*.png`.\u003cbr\u003e\n\u003e So that touch a file `src/pages/og/[slug].png.ts`\n\n```ts\nimport { readFile } from 'node:fs/promises'\nimport { type SatoriOptions, satoriAstro } from 'x-satori/astro'\nimport { Resvg } from '@resvg/resvg-js'\nimport type { APIRoute } from 'astro'\nimport { type CollectionEntry, getCollection } from 'astro:content';\n\nexport async function getStaticPaths() {\n  const posts = await getCollection('blog');\n\n    return posts\n        .map(post =\u003e ({\n            params: { slug: post.slug },\n            props: { ...post },\n        }));\n}\n\nasync function getPostImageBuffer(props) {\n        const template = await readFile(/** .astro template file */, 'utf-8')\n        const config: SatoriOptions = {\n            //... satori options,\n            props: {\n                //...astro template file props\n                ...props.data,\n            }\n        }\n        const svg = await satoriAstro(config, template)\n        const resvg = new Resvg(svg)\n        const pngData = resvg.render()\n        return pngData.asPng()\n}\n\nexport const GET: APIRoute = async ({ props }) =\u003e\n    new Response(\n        await getPostImageBuffer(props as CollectionEntry\u003c'blog'\u003e),\n        {\n            headers: { 'Content-Type': 'image/png' },\n        },\n    )\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eUsing ESM script\u003c/summary\u003e\u003cbr\u003e\n\n- Dependency: **Astro**\n\n```mjs\nimport { defineSatoriConfig, satoriAstro } from 'x-satori/astro'\n\nfunction main() {\n    const _DIRNAME = typeof __dirname !== 'undefined'\n        ? __dirname\n        : dirname(fileURLToPath(import.meta.url))\n    const _OUTPUT = resolve(_DIRNAME, './image/og.png')\n\n    const templateStr = await readFile(resolve(_DIRNAME, './Template.vue'), 'utf8')\n    const opt = defineSatoriConfig({\n    // ... Satori options\n        props: {\n        // ...Vue SFC props options\n        // title: \"Hello world\"\n        },\n    })\n    const strSVG = await satoriAstro(opt, templateStr)\n    console.log(strSVG)\n}\nmain()\n```\n\n- **Example**: [examples/astro-run-esm-script](./examples/astro-run-esm-script/) ⭐⭐⭐\n\n    ```sh\n    npm run gen:svg\n    npm run gen:png\n    ```\n\n- **Example**: [Repo - Zhengqbbb/qbb.sh@v2.1.1/.x-cmd/og/main.ts](https://github.com/Zhengqbbb/qbb.sh/blob/v2.1.1/.x-cmd/og/main.ts)\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eUsing CLI\u003c/summary\u003e\u003cbr\u003e\n\n- Dependency: **Astro** | **Vite** (for dev mode)\n\n```sh\n$ npx x-satori --help\n\nSYNOPSIS:\n    x-satori --template \u003ctemplate_file_path\u003e --config \u003csatori_config_path\u003e [--props \u003cJSON\u003e]\n    x-satori --template \u003ctemplate_file_path\u003e --config \u003csatori_config_path\u003e [--props \u003cJSON\u003e] --output \u003csvg_path\u003e\n    x-satori --template \u003ctemplate_file_path\u003e --config \u003csatori_config_path\u003e [--props \u003cJSON\u003e] --dev [--host --port \u003cnum\u003e]\n\nOPTIONS:\n    -d|--dev                   Turn on Dev mode\n       --host                  Expose  host in Dev mode\n       --port     \u003cnum\u003e        Specify port in Dev mode\n    -t|--template \u003cpath\u003e       The Vue or Astro template file path\n    -c|--config   \u003cpath\u003e       The export satori configure file path\n    -o|--output   \u003cpath\u003e       Target output SVG path\n    --props       \u003cJSON_str\u003e   Overwrite and use props in config\n\nEXAMPLES:\n    x-satori --config \"./satori.ts\" --template \"./Template.astro\" --dev --host\n    x-satori --config \"./satori.ts\" --template \"./Template.astro\"\n    x-satori --config \"./satori.js\" --template \"./Template.astro\" --props '{\"title\": \"Hello World\"}'\n    x-satori --config \"./satori.js\" --template \"./Template.astro\" -o image.svg\n```\n\n#### Configure\n\n- Extends Satori options and add Vue file props option\n\n```mjs\nimport { defineSatoriConfig } from 'x-satori/astro'\n\nexport default defineSatoriConfig({\n    // ... Satori options\n    props: {\n        // ...astro file props options\n        // title: \"Hello world\"\n    },\n})\n```\n\n#### Astro template file\n\n- **Only the template syntax is used**, and props are only used for hint completion\n- [→ Satori supports common CSS features](https://github.com/vercel/satori#css)\n- [→ Tailwindcss documentation](https://tailwindcss.com/docs/customizing-colors)\n\n```astro\n---\ninterface Props {\n    title: string\n};\n\nconst { title = Hello world } = Astro.props;\n---\n\u003cdiv class=\"w-full h-full text-1.4rem text-white flex flex-col items-center justify-between\"\u003e\n    \u003ch2 \u003e\n        {title}\n    \u003c/h2\u003e\n\u003c/div\u003e\n\n```\n\n- **Example**: [playground/astro](./playground/astro/) ⭐⭐⭐\n- **Example (Advanced)** - Using `Shell Scripts` to batch image generation with `resvg-cli`:\u003cbr\u003e\n    [Repo - Zhengqbbb/qbb.sh/.x-cmd/og](https://github.com/Zhengqbbb/qbb.sh/blob/6fe03b051c1468417682da6e329be0e0b77c6468/.x-cmd/og#L37-L45)\n\n\u003c/details\u003e\n\n### 🎼 Command-line Advanced Usage\n\n\u003cdetails\u003e\n    \u003csummary\u003epipeline generate \u003cb\u003epng\u003c/b\u003e with \u003ccode\u003eresvg-cli\u003c/code\u003e\u003c/summary\u003e\u003cbr\u003e\n\n\u003e TIP: You can install it globally or use `bunx` for replacement startup\n\n```sh\nnpx x-satori --config \"./satori.ts\" --template \"./Template.vue\" --props '{\"title\": \"Hello World\"}' | \\\n    npx resvg-cli - image.png\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n    \u003csummary\u003epipeline generate \u003cb\u003ewebp\u003c/b\u003e or more edit with \u003ccode\u003eresvg-cli\u003c/code\u003e and \u003ccode\u003eimagemagick\u003c/code\u003e \u003c/summary\u003e\u003cbr\u003e\n\n\u003e TIP: You can install it globally or use `bunx` for replacement startup\n\n```sh\nnpx x-satori --config \"./satori.ts\" --template \"./Template.vue\" --props '{\"title\": \"Hello World\"}' | \\\n    npx resvg-cli - | \\\n    magick - webp:image.webp\n```\n\n\u003c/details\u003e\n\n## How it works\n1. ▲ [Satori](https://github.com/vercel/satori) is an amazing library for generating SVG strings from pure HTML and CSS.\n2. Unfortunately, it is built on top of React's JSX and expects [\"React-elements-like objects\"](https://github.com/vercel/satori#use-without-jsx).\n3. Thanks an library [natemoo-re/satori-html](https://github.com/natemoo-re/satori-html) can to generate the necessary VDOM object from a string of HTML.\n4. So the key is to **convert the Vue SFC file to an HTML string**, and here I used transform so that I could generate it via script (Only the template syntax is used)\n    - `@vue/compiler-sfc`: to parse Vue SFC file\n    - `vue - createSSRApp`  and `vue/server-renderer`: transform HTML string\n5. Astro: a similar method:\n    - `@astrojs/compiler`: to transform `.astro` to `ts`\n    - `AstroContainer`: renderToString to obtain HTML string\n\n## Why developed\n\n\u003e My Weekend Pilot Project\n\n1. This processing logic, **initially used in my Vite-SSG person website** [qbb.sh](https://github.com/Zhengqbbb/qbb.sh/blob/790c47026cb1baac34dee8642150ec1729fb0f39/package.json#L18), I prefer to run the script to generate e.g `tsx gen-og.mts` at my building time rather than the edge Fn\n2. And personally, I think Vue SFC File would be better in expressing this SVG structure, but I only use the template syntax and props, and the css would use tailwindcss.\n3. I did a experiment this weekend, using Vite HRM to improve DX, and developed a CLI so that I could run command and generated the SVG directly.\n\nI'm happy that I finally finished this series of experiments and results this weekend. \u003cbr\u003e\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\" width=\"50%\"\u003e\n        \u003cimg alt=\"demo-img-1\"src=\"https://user-images.githubusercontent.com/40693636/226387222-e2de688d-bbb6-41a2-9454-d10d8fd7784d.png\"\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\" width=\"50%\"\u003e\n        \u003cimg alt=\"demo-img-2\"src=\"https://cdn.jsdelivr.net/gh/Zhengqbbb/qbb.sh@v2.1.1/public/og/posts.png\"\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\" width=\"50%\"\u003e\n        \u003cimg alt=\"demo-img-3\"src=\"https://user-images.githubusercontent.com/40693636/226387925-57b58c6a-6677-44d4-a7a0-6939193704b3.png\"\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\" width=\"50%\"\u003e\n        \u003cimg alt=\"demo-img-4\"src=\"https://cdn.jsdelivr.net/gh/Zhengqbbb/qbb.sh@v2.1.1/public/og/2022-12-17-new-homepage.png\"\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\" width=\"50%\"\u003e\n        \u003cb\u003eVue\u003c/b\u003e\n        \u003cbr\u003e\n        Vitepress buildEnd example:\n        \u003cbr\u003e\n        \u003ca href=\"./examples/vue-vitepress/\"\u003eexamples/vue-vitepress/\u003c/a\u003e\n        \u003cbr\u003e\n        ESM script code example:\n        \u003cbr\u003e\n        \u003ca href=\"https://github.com/Zhengqbbb/qbb.sh/tree/vitesse/build/node/og/main.mts\"\u003eqbb.sh@vitesse/node/og/main.mts\u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\" width=\"50%\"\u003e\n        \u003cb\u003eAstro\u003c/b\u003e\n        \u003cbr\u003e\n        File endpoints example:\n        \u003cbr\u003e\n        \u003ca href=\"https://satori-astro.vercel.app/blog/\"\u003ehttps://satori-astro.vercel.app\u003c/a\u003e\n        \u003cbr\u003e\n        ESM script code example:\n        \u003cbr\u003e\n        \u003ca href=\"https://github.com/Zhengqbbb/qbb.sh/blob/v2.1.1/.x-cmd/og/main.ts\"\u003eqbb.sh@astro/.x-cmd/og/main.ts\u003c/a\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n## Related Links\n\n- [nuxt-modules/og-image](https://github.com/nuxt-modules/og-image) - Nuxt or want to use edge Fn\n- [Vercel / Open Graph (OG) Image Generation](https://vercel.com/docs/functions/og-image-generation)\n\n## FAQ\n\n\u003cdetails\u003e\n\u003csummary\u003eCJS support ?\u003c/summary\u003e\u003cbr\u003e\n\n**Not supported**, waiting for upstream library [natemoo-re/ultrahtml](https://github.com/natemoo-re/ultrahtml/tree/main)\n\n\u003c/details\u003e\n\n## Contributing\n\n\u003e I did it step by step according to the documentation of Astro, Vue and Vite, if you are interested, PR welcome 🤗\n\n```sh\npnpm install\npnpm dev        # dev mode\npnpm x --help   # start up the CLI and development\n```\n\n## LICENSE\n\nMIT\nCopyright (c) 2023-2024 [Q.Ben Zheng](https://github.com/Zhengqbbb)\n\n\u003cp align=\"center\"\u003e\n    \u003ctable\u003e\n        \u003ctbody\u003e\n        \u003ctd align=\"center\"\u003e\n            \u003cbr\u003e\n            I just try my best to make thing well.\u003cbr\u003e\n            Could you give a star ⭐ to encourage me 🤗\n            \u003cbr\u003e\n            If possible, can to be my \u003ca href=\"https://github.com/sponsors/Zhengqbbb\"\u003e💖 Sponsor 💖\u003c/a\u003e to support my work\n            \u003cimg width=\"800\" height=\"0\" /\u003e\n        \u003c/td\u003e\n        \u003c/tbody\u003e\n    \u003c/table\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzhengqbbb%2Fx-satori","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzhengqbbb%2Fx-satori","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzhengqbbb%2Fx-satori/lists"}