Git Product home page Git Product logo

migo's Introduction

Click here for example OpenGraph Images



Generate dynamic OpenGraph images on Deno's Edge Network


Deploy with Deno


Schema

migo.deno.dev/:title.(png|svg)?:params
migo.deno.dev/:title/:subtitle.(png|svg)?:params
migo.deno.dev/:params/:title.(png|svg)
migo.deno.dev/:params/:title/:subtitle.(png|svg)

Features

  • Just-in-time rendered, globally deployed via Deno Deploy
  • Cached as immutable assets via Cloudflare for fast loads.
  • Rendered as .svg, rasterized to .png via resvg
  • Integrated with 100,000 icons via Iconify + icns.ml
  • Parameters for fine-grained control of image colors, dimensions, icon, and text.
  • TODO create a friendly GUI for image creation (see vercel)

Formats

Every image is initially sculpted as an SVG (Scalable Vector Graphics), and you can optionally add the extension .svg to force that format in the response.

Unfortunately most social media platforms don't support social images in SVG format yet, so requests without an .{svg,png} extension are redirected to .png prior to rendering.


Icons

Icons are embedded from icns, another Deno-powered project of mine. This means direct access to over 100,000 icons, and millions of color combinations. A great tool to browse the available icons and make a selection is icones by Anthony Fu.

To add an icon to an OG image, use the slug (in Iconify format) for the icon param, like so:

icon={collection}:{icon} (e.g. ?icon=tabler:brand-github).

You can also use an override iconUrl parameter, with an encoded URI you'd like to embed, e.g.:

icon=https%3A%2F%2Fcdn.jsdelivr.net%2Fgh%2Fremojansen%2Flogo.ts%40master%2Fts.svg


Parameters

There are numerous parameters you can use to control the look and feel of the generated images. Parameters can be provided in either the first part of the path or in the query string of the URL.


Path (recommended)

For the best caching potential, I recommend only using the path-style parameters on your images. Some CDN providers have unexpected caching behavior when assets have query string parameters in their URI.

migo.deno.dev/bgColor=white&titleColor=black&icon=typescript/Title.png

Note: Allowed delimiters are & (ampersand), ; (semi-colon), or ::.


Query String

migo.deno.dev/title.png?bgColor=white&titleColor=black&icon=typescript

Note: Query string params must use the & (ampersand) delimiter.


Default Values

All available parameters and their default value (or formula used to calculate it):

// base props
width = 1280, 
height = 640, 
viewBox = "0 0 1280 640", 
pxRatio = 1.5, // set to 1 for low-res
bgColor = "white", 
borderRadius = 0, // rounded image corners

// icon
icon = "noto:t-rex", // set to false to disable icon
iconUrl = "https://icns.ml/{icon}.svg", 
iconW = 240, 
iconH = 240, // +iconW
iconX = 520, // ((width - iconW) / 2)
iconY = 60, // (iconH / 4)
iconColor = "black", // fill color
iconStroke = "none", // stroke color
iconStrokeWidth = 0, // stroke width

// title (first line of text)
titleX = 640, // (width / 2)
titleY = 450, // (iconH + iconY + (titleFontSize * 2.5))
titleFontSize = 64, 
titleFontFamily = "sans-serif", // "Inter"
titleFontWeight = "bold", 
titleColor = "#112233", // text color
titleStroke = "none", // stroke color
titleStrokeWidth = 0, // stroke width
titleTextAnchor = "middle", // text-anchor

// subtitle (second line of text)
subtitleX = 640, // (width / 2)
subtitleY = 530, // (titleY + (subtitleFontSize * 2.5))
subtitleFontSize = 32, 
// "serif" | "sans-serif" | "monospace"
subtitleFontFamily = "monospace",
subtitleFontWeight = "normal", 
subtitleColor = "#334455", // text color
subtitleStroke = "none", // stroke color
subtitleStrokeWidth = 0, // stroke width
subtitleTextAnchor = "middle" // text-anchor

Performance

The only lag you might encounter is the very first time an image is requested (this is unavoidable due to the render/raster steps). Thankfully, your users should essentially never be the ones encountering that lag time; they get a cache hit from their nearest edge datacenter.


Examples

Deno Module Starter

Nuxt Content Wind Starter

Creating Dynamic Social Cover Images


migo's People

Contributors

deno-deploy[bot] avatar nberlette avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

clipbibot

migo's Issues

[feat] intelligent word-wrap for title + subtitle text

Currently there is no word-wrap functionality baked into the SVG rendering step, which is just shameful ☹️. This issue is mostly a place for me to store some thoughts, notes, and log my results throughout the process of implementing a "smart" wrapper function for migo.

Can we get away with using SVGTextElement.getComputedTextLength()? Does it produce accurate and dependable results...? On that note, what about SVGTextElement.getBoundingClientRect? Or SVGTextElement.getBBox? It sure would save me a lot of time to just be able to use a built-in interface for 90% of the logic in this scenario.

If not, heres a basic outline of the steps involved:

  1. calculate glyph width from font size + weight
  • (like @nicktaras/getFontCharWidth, or digging into the SVG font interfaces)
  1. estimate required width for a given string in the desired font/size/weight
  • (e.g. textLength * (glyphWidthFromStep1 + letterSpacing))
  1. subtract a small percentage of the window width to determine a "safe-zone"; ensuring
    any breakable-words will be wrapped before it reaches the edge of the canvas or screen.
  • e.g. width - (width * 0.05) ~> 950px / 1000px total (25px margin)
  1. diff the required text width with the image safe-zone width.
let d = Math.ceil(requiredWidthFromStep2 - safeWidthFromStep3);
if (d > 0) {
  wrapLine();
  // if a line is reeeeeally long and requires 2+ screen breaks to fit
  // this re-wrap the text until all lines fit within the canvas.
  repeatStartingFromStep2ForEveryLine();
}
  1. if all lines don't fit within the canvas size, attempt to scale the font size
    down until they do. Truncating the text should only be used as THE last resort.

[bug] remote icons do not load in rasterized `.png` images

Describe the Bug

The custom iconUrl parameter appears to be broken. In actuality, it functions fine when rendering an .svg, but displays nothing when requesting the same image as a .png. This is a major problem is PNG is by far the most popular file type.

There's a high likelihood of this being a problem with resvg_wasm rendering foreign objects / external image URLs. Maybe we can bypass this by encoding the image as a base64 datauri?

PR's welcome.

Expected Behavior

Instead of using the standard icon parameter, which is limited to the Iconify syntax of {collection-name}:{icon-identifier}, users are supposed to be able to provide a fully-resolved URL with the iconUrl parameter, overriding the former to display their custom icon instead.

Reproduction

These are the same exact image URL's, except for the extensions - .svg and .png. Notice the .svg renders fine, with the Apple Emoji T-Rex icon displaying as intended.

SVG: https://migo.deno.dev/image.svg?title=deno911%E2%81%84+kit&subtitle=deno+module+starter+template&titleFontFamily=serif&titleFontSize=72&titleFontWeight=900&titleTextAnchor=left&titleX=160&titleY=110&subtitleFontSize=36&subtitleFontWeight=900&subtitleFontFamily=monospace&subtitleTextAnchor=left&subtitleX=40&subtitleY=250&pxRatio=1.5&width=1000&height=300&bgColor=111827&titleColor=fff&subtitleColor=ddd&iconW=100&iconH=100&iconX=40&iconY=30&borderRadius=10&iconUrl=https://emoji.aranja.com/static/emoji-data/img-apple-160/1f996.png

The png, however.... no dice.

PNG: https://migo.deno.dev/image.png?title=deno911%E2%81%84+kit&subtitle=deno+module+starter+template&titleFontFamily=serif&titleFontSize=72&titleFontWeight=900&titleTextAnchor=left&titleX=160&titleY=110&subtitleFontSize=36&subtitleFontWeight=900&subtitleFontFamily=monospace&subtitleTextAnchor=left&subtitleX=40&subtitleY=250&pxRatio=1.5&width=1000&height=300&bgColor=111827&titleColor=fff&subtitleColor=ddd&iconW=100&iconH=100&iconX=40&iconY=30&borderRadius=10&iconUrl=https://emoji.aranja.com/static/emoji-data/img-apple-160/1f996.png

Screenshots

SVG

Screen Shot 2022-09-12 at 1 52 38 PM

PNG

Screen Shot 2022-09-12 at 1 53 00 PM

[feat] reusable "presets" for shorter URLs + user analytics

I've been meaning to tackle this for a while. Truth be told, it really should have been a primary feature from day one.

I'll be frank with you, I really dislike how long the image URL's become after just a few customizations. It's also a pain in the ass to try to remember exactly which dimensions / colors / font combinations I used, when trying to produce more images in the same style.

As a solution for this, I propose a "presets" or "themes" system: at a minimum it would be a hard-coded collection of some sensible default color-schemes and design presets (lazy option. yuck), but ideally I envision it as something integrated with a user-authentication system. The latter option would allow users to create/save style presets in their own personal accounts, then easily reference them with a unique URL identifier.

I picture it as a really basic feature at its core - instead of manually applying a bunch of params like ?titleFontSize=64&titleColor=000&subtitleFontSize=32&..., you could simply use ?p=f7f34fc5b71a4ffe4fbe&title=Title+Text&subtitle=Subtitle+Text. This would also enable things like user analytics, such as measuring traffic across different image presets to see which designs are most effective.

I'm starting to ramble now, but this seems like something that could possibly result in the need for monetization. If the service grows in size and userbase and we're providing traffic analytics and other extensive features, it's going to be burning a hole in my pocket if it isn't generating some form of revenue on its own. I really like the idea of keeping it 100% free though.

Please feel free to chime in with your thoughts, I'd really like to hear a voice other than my own in the echo chamber here 😅

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.