Public
HTTP (deprecated)
Val Town is a social website to write and deploy JavaScript.
Build APIs and schedule functions from your browser.
Readme

Minimal val.town Farcaster Frame example. It supports dynamic image generation with Satori and ReSVG, and it's compatible with the Open Frames standard.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/** @jsxImportSource npm:hono@3/jsx */
import { render } from "https://deno.land/x/resvg_wasm/mod.ts";
import { Hono } from "npm:hono@3";
import satori from "npm:satori";
const app = new Hono();
async function renderImage(s: string, color: string) {
const fontArrayBuf = await fetch(
"https://cdn.jsdelivr.net/npm/roboto-font@0.1.0/fonts/Roboto/roboto-regular-webfont.ttf",
).then((res) => res.arrayBuffer());
const svg = await satori(
{
type: "div",
props: {
children: s,
style: {
display: "flex",
height: "100%",
width: "100%",
fontSize: "100px",
backgroundColor: "white",
color,
justifyContent: "center",
paddingTop: "120px",
},
},
},
{
width: 600,
height: 400,
fonts: [
{
name: "Roboto",
data: fontArrayBuf,
weight: 400,
style: "normal",
},
],
},
);
return await render(svg);
}
app.get("/satori", async (c) => {
const query = c.req.query("button");
let text = "Hello world!";
let color = "blue";
switch (query) {
case "1": {
text = "one!";
color = "red";
break;
}
case "2": {
text = "two";
color = "green";
break;
}
case "3": {
text = "three";
color = "chocolate";
break;
}
case "4": {
text = "four";
color = "purple";
break;
}
}
return c.body(await renderImage(text, color), 200, { "Content-Type": "image/png" });
});
app.get("/", (c) => {
return c.html(
<head>
<meta property="fc:frame" content="vNext" />
<meta
property="fc:frame:image"
content="https://nlnw-frame.web.val.run/satori"
/>
<meta property="fc:frame:button:1" content="Door 1" />
<meta property="fc:frame:button:2" content="Door 2" />
<meta property="fc:frame:button:3" content="Door 3" />
<meta property="fc:frame:button:4" content="Door 4" />
<meta property="of:accepts:xmtp" content="2024-02-01" />
</head>,
);
});
app.post("/", async (c) => {
const body = await c.req.json();
const buttonIndex = body.untrustedData.buttonIndex;
return c.html(
<head>
<meta property="fc:frame" content="vNext" />
<meta
property="fc:frame:image"
content={`https://nlnw-frame.web.val.run/satori?button=${buttonIndex}`}
nlnw-frame.web.val.run
March 24, 2024