inviterender

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 17, 2026 License: MIT Imports: 24 Imported by: 0

README

go-invite-render

Go Reference Go Report Card


Server-side event invitation card generator for Go.

Input: background image + zone definitions + guest fields.
Output: PNG bytes.

No login, no database, no external services. Fonts are bundled. Think of it as Photoshop automation — you define where text, images, and QR codes go; the library composites them.

Install

go get github.com/godopetza/go-invite-render

Quick start

import inviterender "github.com/godopetza/go-invite-render"

bg, _ := os.ReadFile("template.png")

zones := []inviterender.Zone{
    {
        ID:         "guest_name",
        Type:       "text",
        Text:       "{{guest_name}}",
        XPct:       50, YPct: 42,
        WidthPct:   80,
        FontFamily: "Cormorant Garamond",
        FontSize:   48,
        Color:      "#ffffff",
        Bold:       true,
        Align:      "center",
    },
    {
        ID:         "event_date",
        Type:       "text",
        Text:       "{{event_date}}",
        XPct:       50, YPct: 55,
        WidthPct:   60,
        FontFamily: "Montserrat",
        FontSize:   24,
        Color:      "#f0e6c8",
        Align:      "center",
    },
    inviterender.DefaultQRZone(), // bottom-right, auto-renders {{__checkin_token__}}
}

png, err := inviterender.RenderCard(bg, zones, map[string]string{
    "guest_name":       "Amina & Baraka",
    "event_date":       "Saturday, 14 June 2025",
    "__checkin_token__": "EVT1-GUEST42-ABC123",
})

Zone types

text

Renders a text string with HarfBuzz OpenType shaping (ligatures, kerning). Supports word-wrap within WidthPct.

Field Type Description
Text string Content, supports {{token}} substitution
FontFamily string One of the bundled families (see below)
FontSize float64 Points
Color string #rrggbb or #rrggbbaa
Bold, Italic, Underline bool Style flags
Align string left, center, right
Opacity float64 0.0–1.0, default 1.0

image

Composites a source image (URL or data URI) into a shaped frame, cover-fit with optional pan/zoom.

Field Type Description
ImageSrc string HTTP URL or data:image/...;base64,...
FrameShape string circle, oval, heart, arch, diamond, hexagon, none
FrameColor string Decorative ring color, #rrggbb
ImageOffsetX, ImageOffsetY float64 Pan offset in pixels
ImageScale float64 Zoom multiplier (1.0 = fit, >1 = zoom in)

qr

Renders a QR code for the value of {{__checkin_token__}} in the fields map.

Use inviterender.DefaultQRZone() for a standard bottom-right placement, or configure your own:

Zone{
    ID:        "checkin_qr",
    Type:      "qr",
    XPct:      85, YPct: 88,
    WidthPct:  18, HeightPct: 18,
}

Zone positioning

All positions and sizes are percentage of card width/height, so the output resolution doesn't affect layout.

The internal render height is fixed at 1100px; width scales proportionally from the background image's aspect ratio.

XPct/YPct is the center of the zone.

Token substitution

Any zone's Text field can contain {{token}} placeholders. Pass the values in the fields map:

fields := map[string]string{
    "guest_name":        "Amina & Baraka",
    "event_title":       "Our Wedding",
    "__checkin_token__": "EVT1-GUEST42-ABC123",
}

__checkin_token__ is special — if present and non-empty, any qr zone renders it as a QR code.

Bundled fonts

Family Styles
Cormorant Garamond Regular, Bold, Italic, Bold Italic
Playfair Display Regular, Bold, Italic
Montserrat Regular, Bold, Italic
Great Vibes Regular

Pass the family name exactly as shown above to FontFamily.

Use as a microservice

You don't have to import go-invite-render directly into your app. The included HTTP server wraps it behind a single endpoint — deploy it once, call it from any language or service over HTTP.

API

POST /render — multipart form

Field Type Description
background file Background image (PNG or JPEG)
zones JSON string Array of Zone objects
fields JSON string Token values to substitute

Returns: image/png binary

GET /health — returns {"ok":true}

Example call

curl -X POST https://your-render-service.up.railway.app/render \
  -F "background=@wedding_template.png" \
  -F 'zones=[
    {"type":"text","text":"{{guest_name}}","xPct":50,"yPct":42,
     "fontSize":48,"color":"#ffffff","fontFamily":"Cormorant Garamond",
     "bold":true,"align":"center","widthPct":80},
    {"type":"qr","xPct":85,"yPct":88,"widthPct":18,"heightPct":18}
  ]' \
  -F 'fields={"guest_name":"Amina & Baraka","__checkin_token__":"EVT1-GUEST42"}' \
  --output amina_card.png

From Go:

resp, err := http.Post(os.Getenv("RENDER_SERVICE_URL")+"/render", "multipart/form-data", body)
// read resp.Body as PNG bytes

From Node.js / Python / any HTTP client — same multipart call, same PNG response.

Run locally

cd examples/server
cp .env.example .env
go run main.go
# listening on :8080

Deploy to Railway

Railway is the fastest way to get the render service live with zero infrastructure setup.

Deploy on Railway

Manual deploy (5 minutes):

  1. Create a new Railway projectrailway.com

  2. Connect your GitHub repo (fork this repo or push it to your own GitHub account)

  3. Set the root directory to examples/server in Railway's deploy settings

  4. Set environment variables in Railway dashboard:

    PORT=8080   # Railway sets this automatically
    

    That's it — no other env vars needed. Fonts are bundled in the binary.

  5. Railway builds and deploys automatically. Your render endpoint will be at:

    https://your-project-name.up.railway.app/render
    
  6. Point your app at it:

    # In your app's environment
    RENDER_SERVICE_URL=https://your-project-name.up.railway.app
    

Scaling

The render service is stateless — every request is independent. Railway's horizontal scaling works out of the box. A single instance handles ~20–30 concurrent renders on a 512MB container; add more instances as your guest list grows.

Cost

Rendering a card typically takes 100–400ms. On Railway's hobby plan ($5/month) you get 500 hours of compute — enough for tens of thousands of cards per month.


Visual card editor (frontend/)

The frontend/ directory contains a Next.js visual editor for designing zone layouts — the same canvas used in production. Upload a background image, drag zones around, tweak fonts and colors, then click Render to see the actual PNG output from your go-invite-render server. Use Export JSON to copy the zone config straight into your Go code.

cd frontend
cp .env.example .env   # set NEXT_PUBLIC_RENDER_SERVER_URL
npm install
npm run dev
# open http://localhost:3000

The editor calls your running go-invite-render server (set the URL in the top bar or .env). Start the server first:

cd examples/server && go run main.go

Deploy the editor to Cloudflare Workers

cd frontend
npm install
npx @cloudflare/next-on-pages
npx wrangler pages deploy .vercel/output/static

Update NEXT_PUBLIC_RENDER_SERVER_URL in wrangler.toml to your Railway render server URL before deploying.


Used in production

Built and battle-tested at shereko.com — an event invitation and coordination platform for weddings and celebrations across East Africa. Shereko uses go-invite-render to generate personalized PNG invitation cards for every guest, delivered over WhatsApp.


License

MIT

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func RenderCard

func RenderCard(bgData []byte, zones []Zone, fields map[string]string) ([]byte, error)

RenderCard composites zones onto a background image and returns a PNG.

bgData — raw bytes of any image format Go's stdlib can decode (JPEG, PNG, GIF) zones — ordered list of layers (bottom to top) fields — token substitution map, e.g. {"guest_name": "Amina Hassan"}

Special field key: "__checkin_token__" — value is encoded into QR zones.

func SubstituteTokens

func SubstituteTokens(s string, fields map[string]string) string

SubstituteTokens replaces all {{key}} occurrences in s using fields.

Types

type TextAlign

type TextAlign int

TextAlign mirrors "left" | "center" | "right".

const (
	AlignLeft TextAlign = iota
	AlignCenter
	AlignRight
)

type Zone

type Zone struct {
	ID         string  `json:"id"`
	Type       string  `json:"type"`       // "text" | "image" | "qr"
	Text       string  `json:"text"`       // supports {{token}} substitution
	XPct       float64 `json:"xPct"`       // horizontal centre (0–100)
	YPct       float64 `json:"yPct"`       // vertical centre (0–100)
	FontSize   float64 `json:"fontSize"`   // editor-space px (scaled to output)
	Color      string  `json:"color"`      // "#RRGGBB" or "#RRGGBBAA"
	FontFamily string  `json:"fontFamily"` // see Fonts section in README
	Bold       bool    `json:"bold"`
	Italic     bool    `json:"italic"`
	Underline  bool    `json:"underline,omitempty"`
	Align      string  `json:"align"`   // "left" | "center" | "right"
	Opacity    float64 `json:"opacity"` // 0.0–1.0, defaults to 1.0
	// Image zone
	ImageSrc     string  `json:"imageSrc,omitempty"`   // URL or data URI
	FrameShape   string  `json:"frameShape,omitempty"` // circle|oval|heart|arch|diamond|hexagon|none
	FrameColor   string  `json:"frameColor,omitempty"`
	WidthPct     float64 `json:"widthPct,omitempty"`
	HeightPct    float64 `json:"heightPct,omitempty"`
	ImageOffsetX float64 `json:"imageOffsetX,omitempty"`
	ImageOffsetY float64 `json:"imageOffsetY,omitempty"`
	ImageScale   float64 `json:"imageScale,omitempty"`
}

Zone defines a single layer on the invitation card. Positions (XPct, YPct) and sizes (WidthPct, HeightPct) are expressed as percentages of the output canvas dimensions so zones scale correctly to any background image resolution.

func DefaultQRZone

func DefaultQRZone() Zone

DefaultQRZone returns a QR zone positioned at the bottom-left of the card.

Directories

Path Synopsis
examples
basic command
server command
Minimal HTTP wrapper around go-invite-render.
Minimal HTTP wrapper around go-invite-render.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL