Animated Sign 4u is a small Next.js app and HTTP API for generating animated signature SVGs and static PNG/GIF images.
You can:
-
Apply themes (backgrounds, textures, glow/shadow)
-
Use per-character colors or gradients
-
Enable Hanzi stroke-by-stroke animation
-
Export SVG / PNG / GIF or copy an API URL
-
Share the current configuration as a short URL for the builder UI
- Framework: Next.js 16 (App Router)
- Language: TypeScript + React 19
- UI: Tailwind CSS 4, Radix UI,
lucide-react - SVG & Fonts:
opentype.js,svg-path-properties - Raster Export:
sharp(server-side PNG/GIF) - Tests: Vitest
app/
layout.tsx – Root layout (theme + i18n providers)
page.tsx – Landing page (quick mode)
editor/page.tsx – Advanced editor UI (desktop + mobile)
[text]/route.ts – Short share URL redirect (landing/editor)
api/sign/route.ts – Signature generation API
components/
i18n-provider.tsx – locale + translate helper
theme-provider.tsx – dark/light theme
signature-builder/
sidebar-*.tsx – content, params, themes, style panels
preview-area.tsx – live SVG preview with zoom
mobile-drawer-sidebar.tsx– mobile sidebar drawer
code-panel.tsx – code snippets & API URL
lib/
types.ts – `SignatureState` and enums
constants.ts – `INITIAL_STATE`, themes, fonts
svg-generator.tsx – pure SVG generator from state + paths
hanzi-data.ts – Hanzi stroke data helpers
state-from-query.ts – parse URLSearchParams into `SignatureState` (shared by API + UI)
api-url.ts – build `/api/sign` and short share URLs from state
code-generators.tsx– React/Vue/JS component generators
High-level data flow:
UI (landing: app/page.tsx) --SignatureState--> buildSignApiUrl --> <img src="/api/sign?...">
UI (editor: app/editor/page.tsx) --SignatureState--> PreviewArea
^ |
| v
+----------- CodePanel <--- buildSignApiUrl
HTTP client --> /api/sign --> buildStateFromQuery
loadFont + buildPaths
generateSVG
(optional sharp PNG/GIF)
All visual options are stored in a single SignatureState (see lib/types.ts),
including:
- Text & font:
text,font,fontSize,speed,charSpacing - Background:
bg,bg2,bgMode,bgTransparent,bgSizeMode,bgWidth,bgHeight,borderRadius,cardPadding - Fill:
fillMode,fill1,fill2,charColors[] - Stroke:
strokeEnabled,strokeMode,stroke,stroke2,strokeCharColors[],linkFillStroke - Texture:
texture,texColor,texSize,texThickness,texOpacity - Effects:
useGlow,useShadow - Modes:
useHanziData
The UI mutates this state via updateState(partial) and passes it to:
PreviewAreafor live renderingCodePanelfor generating example code and API URLs
Simplified flow in preview-area.tsx:
const glyphs = font.stringToGlyphs(state.text || "Demo");
const { paths, viewBox } = buildPathsInBrowser(glyphs, state);
const svg = generateSVG(state, paths, viewBox, { idPrefix: "desktop-" });- For Latin text, glyph paths come from
opentype.js. - For Chinese text with
useHanziData=true, stroke data is fetched viahanzi-data.tsand each stroke becomes its own path. buildPathscomputes a paddedviewBoxaround all glyphs.generateSVGthen:- Adds background rect (solid or gradient) and optional texture pattern
- Computes per-character animation timing (speed is a factor: larger = faster)
- Emits one
<path>per glyph/stroke, with stroke-dash animations - Applies filters for glow/shadow when enabled
The API uses the same concepts but runs fully on the server:
const state = buildStateFromQuery(searchParams);
const font = await loadFont(state.font);
const { paths, viewBox } = await buildPaths(font, state);
switch (format) {
case "json":
return { paths, viewBox };
case "png":
return sharp(staticSvg).png();
case "gif":
return generateAnimatedGIF(state, paths, viewBox);
default:
return animatedSvg;
}buildStateFromQuerymergesINITIAL_STATE, optionaltheme, and query parameters.buildPathsusessvg-path-propertiesfor path lengths.generateSVGis called withstaticRender=truefor PNG (single-frame snapshot).generateAnimatedGIFsamples the animation timeline at 30fps and creates a multi-frame animated GIF with stroke-by-stroke animation.
The HTTP API is exposed via a single endpoint:
| Method | Path | Description |
|---|---|---|
| GET | /api/sign |
Generate signature (SVG / PNG / GIF / JSON) via query parameters |
In addition, the app supports short share URLs of the form /{text} (for
example, http://domain.com/Signature?font=sacramento). These always redirect
to the main builder page /, using the same query parameters to initialize the
UI state. They are ideal for sharing configurations with other people, but they
are not HTTP API endpoints themselves.
The table below is auto-generated from
lib/api-params.tsby runningpnpm generate:api-docs. Do not edit it by hand; instead, update the mapping definitions and re-run the script.
| Name | Short | Group | Description |
|---|---|---|---|
text |
t |
core | Signature text |
font |
f |
core | Font id from FONTS |
theme |
- |
core | Optional theme key from THEMES |
repeat |
r |
core | Whether the animation should loop |
eraseOnComplete |
eo |
core | Erase the signature after drawing (carousel mode) |
fontSize |
fs |
layout | Font size (px) |
speed |
sp |
layout | Animation speed factor (larger = faster) |
charSpacing |
cs |
layout | Base character spacing |
borderRadius |
br |
layout | Card border radius |
cardPadding |
cp |
layout | Inner padding used by texture overlay |
bgSizeMode |
bgs |
layout | Background sizing mode (auto/custom) |
bgWidth |
bw |
layout | Custom background/card width |
bgHeight |
bh |
layout | Custom background/card height |
bg |
- |
background | Background color or 'transparent' |
bgMode |
bm |
background | Background mode (solid/gradient) |
bg2 |
- |
background | Secondary background color for gradients |
fill |
fm |
fill | Fill mode (single/gradient/multi) |
fill1 |
f1 |
fill | Primary fill color |
fill2 |
f2 |
fill | Secondary fill color |
colors |
cl |
fill | Per-character fill colors (enables multi mode) |
stroke |
st |
stroke | Primary stroke color |
stroke2 |
st2 |
stroke | Secondary stroke color |
strokeMode |
sm |
stroke | Stroke mode (single/gradient/multi) |
strokeEnabled |
se |
stroke | Toggle stroke on/off |
linkFillStroke |
lfs |
stroke | Link stroke behavior to fill mode/colors |
texture |
tx |
texture | Texture overlay type |
texColor |
txc |
texture | Texture color |
texSize |
txs |
texture | Texture scale |
texThickness |
txt |
texture | Texture line thickness |
texOpacity |
txo |
texture | Texture opacity (0..1) |
useGlow |
gl |
effects | Enable glow effect |
useShadow |
sh |
effects | Enable shadow effect |
useHanziData |
hz |
hanzi | Use Hanzi stroke data for Chinese characters |
gifFps |
gf |
gif | GIF frame rate (fps) |
gifQuality |
gq |
gif | GIF quality (1-20, higher is better) |
ui |
u |
meta | UI hint for short-share redirects (landing/editor) |
format |
fmt |
meta | Output format (svg/png/gif/json) |
static |
sta |
meta | Request a static snapshot when using SVG output |
Two core flags control the animation timeline when using animated SVG output:
- repeat (
r)- When
true, the animation timeline loops indefinitely. - When
false, the timeline runs once and then stops.
- When
- eraseOnComplete (
eo)- Enables a carousel-style cycle for each loop:
- Draw the signature (stroke animation)
- Hold the fully drawn frame
- Erase the signature back to the beginning
- Enables a carousel-style cycle for each loop:
When both repeat=true and eraseOnComplete=true:
- Animated SVGs continuously run a draw → hold → erase carousel.
Notes:
- Static SVG (
format=svg&static=1) and PNG snapshots ignore these flags because they are single-frame outputs. - Animated GIF exports sample the same logical timeline (draw → hold → erase →
blank) but always loop regardless of
repeat; the GIF encoder is configured to repeat forever for better UX in typical chat and browser viewers.
-
Simple SVG (HTTP API)
/api/sign?text=Alice&font=great-vibes -
Short share URL (opens the web builder)
/Alice?font=great-vibesThis URL redirects to
/(landing / quick mode) and initializes the UI with the same configuration. If the query containsui=editor, it redirects to/editorinstead.Use the
/api/signform above when you need a pure HTTP API response. Inside the advanced editor, the top-right Share button generates a short URL and setsui=editorso the recipient opens the advanced editor directly. -
JSON (paths and viewBox)
/api/sign?text=Alice&theme=laser&format=json -
Custom background size and texture (HTTP API)
/api/sign?text=Demo&bgSizeMode=custom&bgWidth=800&bgHeight=400&texture=grid&texColor=ffffff&texSize=40&texOpacity=0.4 -
Chinese characters with Hanzi stroke mode (HTTP API)
/api/sign?text=你好世界&font=ma-shan-zheng&useHanziData=1&fontSize=150
# install deps
pnpm install # or npm install / yarn
# dev server (http://localhost:3000)
pnpm dev
# production build
pnpm build
pnpm start
# tests
pnpm testThis README is intentionally concise and GitHub-oriented. For deeper internals, refer to:
lib/svg-generator.tsxfor SVG structure and animation timingapp/api/sign/route.tsfor query parsing and response formatstests/api/*.test.tsandtests/lib/*.test.tsfor executable examples of expected behavior.