Search
valTownLogo
@postpostscript
// let me know if this is an issue :)
Script
export const logo = {
white: html(svg2dataURL(
"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"600\" height=\"237\" fill=\"none\"><path d=\"M0 0h600v237H0z\"/><g fill=\"#fff\" clip-path=\"url(#a)\"><path d=\"M171.182 146.387c3.89 0 7.064-1.082 9.524-3.248 2.459-2.164 3.689-5.046 3.689-8.644v-1.101h-13.984c-2.57 0-4.589.551-6.056 1.652-1.47 1.101-2.202 2.642-2.202 4.624 0 1.982.771 3.598 2.312 4.845 1.542 1.249 3.78 1.872 6.717 1.872Zm-2.422 11.231c-3.893 0-7.378-.679-10.461-2.037-3.083-1.357-5.524-3.339-7.322-5.946-1.8-2.604-2.698-5.78-2.698-9.524 0-3.744.898-6.882 2.698-9.415 1.798-2.532 4.294-4.44 7.487-5.725 3.193-1.284 6.844-1.927 10.956-1.927h14.975v-3.083c0-2.569-.809-4.68-2.422-6.332-1.616-1.651-4.185-2.477-7.708-2.477-3.451 0-6.02.79-7.708 2.367-1.69 1.58-2.791 3.617-3.303 6.111l-12.773-4.294c.881-2.789 2.294-5.34 4.239-7.653 1.944-2.312 4.551-4.183 7.818-5.615 3.266-1.431 7.248-2.147 11.947-2.147 7.193 0 12.883 1.8 17.067 5.395 4.184 3.598 6.276 8.809 6.276 15.636v20.37c0 2.202 1.028 3.304 3.083 3.304h4.404v11.451h-9.248c-2.717 0-4.956-.661-6.717-1.982-1.762-1.322-2.643-3.083-2.643-5.286v-.109h-2.092c-.294.88-.954 2.037-1.982 3.468-1.029 1.431-2.642 2.698-4.845 3.799-2.202 1.101-5.213 1.651-9.028 1.651ZM228.217 78.999h-13.874v77.077h13.874V78.999ZM290.318 156.077c-3.597 0-6.516-1.119-8.754-3.358-2.24-2.238-3.358-5.231-3.358-8.974v-30.831h-13.654v-11.452h13.654V84.505h13.873v16.957h14.976v11.452h-14.976v28.408c0 2.202 1.028 3.304 3.084 3.304h10.57v11.451h-15.415ZM342.51 145.286c4.257 0 7.78-1.376 10.571-4.129 2.789-2.753 4.184-6.698 4.184-11.837v-1.101c0-5.137-1.377-9.084-4.13-11.837-2.752-2.753-6.295-4.129-10.625-4.129-4.258 0-7.781 1.376-10.571 4.129-2.79 2.753-4.184 6.7-4.184 11.837v1.101c0 5.139 1.394 9.084 4.184 11.837s6.313 4.129 10.571 4.129Zm0 12.332c-5.433 0-10.314-1.101-14.645-3.303-4.332-2.202-7.745-5.396-10.24-9.58-2.496-4.184-3.744-9.211-3.744-15.085v-1.762c0-5.871 1.248-10.9 3.744-15.085 2.495-4.184 5.908-7.377 10.24-9.579 4.331-2.202 9.212-3.303 14.645-3.303 5.432 0 10.313 1.101 14.645 3.303 4.33 2.202 7.743 5.395 10.24 9.579 2.495 4.185 3.744 9.214 3.744 15.085v1.762c0 5.874-1.249 10.901-3.744 15.085-2.497 4.184-5.91 7.378-10.24 9.58-4.332 2.202-9.213 3.303-14.645 3.303ZM385.901 148.327l-6.614-46.865h13.763l4.845 45.255h1.982l5.861-37.632a9.008 9.008 0 0 1 8.901-7.623h6.813a9.008 9.008 0 0 1 8.901 7.623l5.861 37.632h1.982l4.845-45.255h13.763l-6.614 46.865a9.008 9.008 0 0 1-8.92 7.75h-7.472a9.009 9.009 0 0 1-8.901-7.623l-5.86-37.633h-1.983l-5.86 37.633a9.009 9.009 0 0 1-8.901 7.623h-7.472a9.008 9.008 0 0 1-8.92-7.75ZM467.815 156.077v-54.615h13.654v7.158h1.982c.881-1.909 2.532-3.725 4.954-5.451 2.423-1.723 6.093-2.587 11.012-2.587 4.256 0 7.982.974 11.176 2.918 3.193 1.945 5.67 4.624 7.432 8.037 1.761 3.414 2.642 7.397 2.642 11.947v32.593h-13.873v-31.492c0-4.109-1.01-7.193-3.028-9.249-2.02-2.054-4.9-3.083-8.644-3.083-4.258 0-7.561 1.415-9.91 4.239-2.35 2.827-3.523 6.772-3.523 11.837v27.748h-13.874ZM134.934 101.463l-26.819 44.484h-1.982v-36.762a7.722 7.722 0 0 0-7.722-7.722H92.26v45.606a9.009 9.009 0 0 0 9.008 9.009h10.007c4.643 0 8.934-2.477 11.257-6.497l27.8-48.118h-15.398Z\"/><path d=\"M79 101.458h13.903v11.452H79v-11.452Z\"/></g><defs><clipPath id=\"a\"><path fill=\"#fff\" d=\"M79 79h442v79H79z\"/></clipPath></defs></svg>",
black: html(svg2dataURL(
"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"600\" height=\"237\" fill=\"none\"><path d=\"M0 0h600v237H0z\"/><g fill=\"#000\" clip-path=\"url(#a)\"><path d=\"M171.182 146.387c3.89 0 7.064-1.082 9.524-3.248 2.459-2.164 3.689-5.046 3.689-8.644v-1.101h-13.984c-2.57 0-4.589.551-6.056 1.652-1.47 1.101-2.202 2.642-2.202 4.624 0 1.982.771 3.598 2.312 4.845 1.542 1.249 3.78 1.872 6.717 1.872Zm-2.422 11.231c-3.893 0-7.378-.679-10.461-2.037-3.083-1.357-5.524-3.339-7.322-5.946-1.8-2.604-2.698-5.78-2.698-9.524 0-3.744.898-6.882 2.698-9.415 1.798-2.532 4.294-4.44 7.487-5.725 3.193-1.284 6.844-1.927 10.956-1.927h14.975v-3.083c0-2.569-.809-4.68-2.422-6.332-1.616-1.651-4.185-2.477-7.708-2.477-3.451 0-6.02.79-7.708 2.367-1.69 1.58-2.791 3.617-3.303 6.111l-12.773-4.294c.881-2.789 2.294-5.34 4.239-7.653 1.944-2.312 4.551-4.183 7.818-5.615 3.266-1.431 7.248-2.147 11.947-2.147 7.193 0 12.883 1.8 17.067 5.395 4.184 3.598 6.276 8.809 6.276 15.636v20.37c0 2.202 1.028 3.304 3.083 3.304h4.404v11.451h-9.248c-2.717 0-4.956-.661-6.717-1.982-1.762-1.322-2.643-3.083-2.643-5.286v-.109h-2.092c-.294.88-.954 2.037-1.982 3.468-1.029 1.431-2.642 2.698-4.845 3.799-2.202 1.101-5.213 1.651-9.028 1.651ZM228.217 78.999h-13.874v77.077h13.874V78.999ZM290.318 156.077c-3.597 0-6.516-1.119-8.754-3.358-2.24-2.238-3.358-5.231-3.358-8.974v-30.831h-13.654v-11.452h13.654V84.505h13.873v16.957h14.976v11.452h-14.976v28.408c0 2.202 1.028 3.304 3.084 3.304h10.57v11.451h-15.415ZM342.51 145.286c4.257 0 7.78-1.376 10.571-4.129 2.789-2.753 4.184-6.698 4.184-11.837v-1.101c0-5.137-1.377-9.084-4.13-11.837-2.752-2.753-6.295-4.129-10.625-4.129-4.258 0-7.781 1.376-10.571 4.129-2.79 2.753-4.184 6.7-4.184 11.837v1.101c0 5.139 1.394 9.084 4.184 11.837s6.313 4.129 10.571 4.129Zm0 12.332c-5.433 0-10.314-1.101-14.645-3.303-4.332-2.202-7.745-5.396-10.24-9.58-2.496-4.184-3.744-9.211-3.744-15.085v-1.762c0-5.871 1.248-10.9 3.744-15.085 2.495-4.184 5.908-7.377 10.24-9.579 4.331-2.202 9.212-3.303 14.645-3.303 5.432 0 10.313 1.101 14.645 3.303 4.33 2.202 7.743 5.395 10.24 9.579 2.495 4.185 3.744 9.214 3.744 15.085v1.762c0 5.874-1.249 10.901-3.744 15.085-2.497 4.184-5.91 7.378-10.24 9.58-4.332 2.202-9.213 3.303-14.645 3.303ZM385.901 148.327l-6.614-46.865h13.763l4.845 45.255h1.982l5.861-37.632a9.008 9.008 0 0 1 8.901-7.623h6.813a9.008 9.008 0 0 1 8.901 7.623l5.861 37.632h1.982l4.845-45.255h13.763l-6.614 46.865a9.008 9.008 0 0 1-8.92 7.75h-7.472a9.009 9.009 0 0 1-8.901-7.623l-5.86-37.633h-1.983l-5.86 37.633a9.009 9.009 0 0 1-8.901 7.623h-7.472a9.008 9.008 0 0 1-8.92-7.75ZM467.815 156.077v-54.615h13.654v7.158h1.982c.881-1.909 2.532-3.725 4.954-5.451 2.423-1.723 6.093-2.587 11.012-2.587 4.256 0 7.982.974 11.176 2.918 3.193 1.945 5.67 4.624 7.432 8.037 1.761 3.414 2.642 7.397 2.642 11.947v32.593h-13.873v-31.492c0-4.109-1.01-7.193-3.028-9.249-2.02-2.054-4.9-3.083-8.644-3.083-4.258 0-7.561 1.415-9.91 4.239-2.35 2.827-3.523 6.772-3.523 11.837v27.748h-13.874ZM134.934 101.463l-26.819 44.484h-1.982v-36.762a7.722 7.722 0 0 0-7.722-7.722H92.26v45.606a9.009 9.009 0 0 0 9.008 9.009h10.007c4.643 0 8.934-2.477 11.257-6.497l27.8-48.118h-15.398Z\"/><path d=\"M79 101.458h13.903v11.452H79v-11.452Z\"/></g><defs><clipPath id=\"a\"><path fill=\"#fff\" d=\"M79 79h442v79H79z\"/></clipPath></defs></svg>",
export const mark = {
white: html(svg2dataURL(
"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"400\" height=\"400\" fill=\"none\"><path d=\"M0 0h400v400H0z\"/><g fill=\"#fff\" clip-path=\"url(#a)\"><path d=\"M265.026 271.002c-7.196 0-13.032-2.235-17.508-6.709-4.48-4.472-6.716-10.452-6.716-17.93v-61.602h-14.438v-22.88h14.438V128h27.746v33.881H298.5v22.88h-29.952v56.76c0 4.4 2.056 6.602 6.168 6.602h21.14v22.879h-30.83Z\"/><path d=\"m204.362 174.325-46.132 76.443h-3.964v-72.167c0-9.231-7.49-16.714-16.73-16.714h-11.018v91.123c0 9.94 8.068 18 18.018 18h18.86c10 0 19.242-5.328 24.244-13.98l55.024-95.143h-16.26a25.745 25.745 0 0 0-22.042 12.438Z\"/><path d=\"M99.994 161.887H127.8v22.882H99.994v-22.882Z\"/></g><defs><clipPath id=\"a\"><path fill=\"#fff\" d=\"M100 128h200v143.86H100z\"/></clipPath></defs></svg>",
black: html(svg2dataURL(
"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"400\" height=\"400\" fill=\"none\"><path d=\"M0 0h400v400H0z\"/><g fill=\"#000\" clip-path=\"url(#a)\"><path d=\"M265.026 271.002c-7.196 0-13.032-2.235-17.508-6.709-4.48-4.472-6.716-10.452-6.716-17.93v-61.602h-14.438v-22.88h14.438V128h27.746v33.881H298.5v22.88h-29.952v56.76c0 4.4 2.056 6.602 6.168 6.602h21.14v22.879h-30.83Z\"/><path d=\"m204.362 174.325-46.132 76.443h-3.964v-72.167c0-9.231-7.49-16.714-16.73-16.714h-11.018v91.123c0 9.94 8.068 18 18.018 18h18.86c10 0 19.242-5.328 24.244-13.98l55.024-95.143h-16.26a25.745 25.745 0 0 0-22.042 12.438Z\"/><path d=\"M99.994 161.887H127.8v22.882H99.994v-22.882Z\"/></g><defs><clipPath id=\"a\"><path fill=\"#fff\" d=\"M100 128h200v143.86H100z\"/></clipPath></defs></svg>",
whatDoYouThinkOfItSoFar
@edgeeffect
What Do You Think of it so far? Rubbish! Our bin men (garbage men to you) come round every Friday morning.
But alternate weeks, they take either rubbish or recycling. This val extracts from our local council website which collection they're doing this week
and E. mails me the details every Thursday afternoon. I've hidden the URL in an environment variable (sorry) but the URL has details of our address
and I'm not sure how happy our local council would be to start getting loads of hits from all round the world.
But it's here as a sample of how easy it is to scrape a website and E. mail the details to yourself. And, on that subject, can I just say "hats off to val.town", I've been looking for a little
cloud host that will let me E. mail myself from a cron for absolutely ages.
Cron
# What Do You Think of it so far?
Rubbish!
Our bin men (garbage men to you) come round every Friday morning.
But alternate weeks, they take either rubbish or recycling.
This val extracts from our local council website which collection they're doing this week
and E. mails me the details every Thursday afternoon.
const extracted = (html: string) => {
const doc = new DOMParser().parseFromString(html, "text/html");
const newDoc = ["<div style=\"color: #000\">"];
doc.querySelectorAll(".bin-collection-container").forEach(
EnkakuAuthenticatedAPI
@paul_lecam
An interactive, runnable TypeScript val by paul_lecam
HTTP
await sqlite.execute(`create table if not exists kv(key text unique, value text)`);
async function getValue(key: string): Promise<string | null> {
const res = await sqlite.execute({ sql: `select value from kv where key = :key`, args: { key } });
return res.rows[0]?.[0] ?? null;
async function listEntries(): Promise<Array<[string, string | null]>> {
const res = await sqlite.execute("select key, value from kv");
return res.rows as Array<[string, string | null]>;
async function setValue(key: string, value: string | null): Promise<void> {
await sqlite.execute({ sql: `insert or replace into kv(key, value) values(:key, :value)`, args: { key, value } });
const transport = new ServerTransport();
val_dO1pTtU7X9
@dhvanil
An interactive, runnable TypeScript val by dhvanil
Script
export default async function handler(req) {
try {
const result = await (async () => {
function isPrime(num) {
if (num <= 1) return false;
for (let i = 2; i <= Math.sqrt(num); i++) {
if (num % i === 0) return false;
return true;
function findLowestThreeDigitPrime() {
for (let num = 100; num < 1000; num++) {
sqliteServer
@vladimyr
An interactive, runnable TypeScript val by vladimyr
Script
export type SQLiteDB = ReturnType<typeof createSqlite>;
export const createServer = (dbFactory: () => Promise<SQLiteDB>) => new SQLiteServer(dbFactory);
export class SQLiteServer {
constructor(
private dbFactory: () => Promise<SQLiteDB>,
handleExecute = async (req: Request) => {
const { statement } = await req.json<any>();
const sqlite = await this.dbFactory();
const res = await sqlite.execute(statement);
return Response.json(res);
emailAPI
@agmm
// https://username-valname.web.val.run?k=myKey&s=mySubject&m=myMessage
HTTP
// Usage exmaple:
// https://username-valname.web.val.run?k=myKey&s=mySubject&m=myMessage
const app = new Hono();
app.get("/", async (c) => {
const now = new Date();
let { to, s, m, k } = c.req.query();
s = s || "message from api";
m = m || "<empty>";
const checks = [
c.req.header("cf-ipcountry") === "US",
saveFormData
@rafter
// Forked from @vtdocs.saveFormData
Express (deprecated)
import { testFormData } from "https://esm.town/v/rafter/testFormData";
export const saveFormData = (req: express.Request, res: express.Response) => {
// Pick out the form data
const formData = req.body;
testFormData.push(formData);
return res.send(`Thanks you submitted ${Object.keys(req.body)}`);
// Forked from @vtdocs.saveFormData
embedBirdSound
@crsven
An interactive, runnable TypeScript val by crsven
HTTP
export let embedBirdSound = async (req, res) => {
const [title, file, image] = req.query.args.split(",");
res.send(
`<div style="text-align: center;"><h3 style="font-size: 5rem; margin: 5rem auto;">${title}</h3><img style="display: block; width: 50vw; margin: 0 auto;" src="${image}" /><audio controls src="${file}" style="width: 50vw; margin: 0 auto 5rem;"></audio></div>`
todepondLabLoginBanUser
@netux
An interactive, runnable TypeScript val by netux
HTTP
export default async function(req: Request): Promise<Response> {
const TABLE_NAME = "todepond_lab_login_users_with_times";
const body = await req.json();
const { username, password, type, target } = body;
const tpUserQuery = await sqlite.execute({
sql: `SELECT * FROM ${TABLE_NAME} WHERE username = ?`,
args: ["TodePond"],
if (tpUserQuery.rows.length === 0) {
return new Response(JSON.stringify({ error: "admin user not found" }), { status: 404 });
const tpUser = tpUserQuery.rows[0];
aqi
@zbeastly1
An interactive, runnable TypeScript val by zbeastly1
Script
export let aqi = async () => {
return await fetchJSON(
"https://api.openaq.org/v2/latest?" +
new URLSearchParams({
limit: "10",
page: "1",
location_id: "61498",
offset: "0",
sort: "desc",
radius: "100000",
vt_playground_demo
@pomdtr
An interactive, runnable TypeScript val by pomdtr
HTTP
const body = `<!doctype html>
<html>
<head>
<title>VT Playground</title>
<script
type="module"
src="https://raw.esm.sh/vt-playground@0.1.8/dist/vt-playground.js"
></script>
</head>
<body>
impressiveAzureJellyfish
@felixnordgren
An interactive, runnable TypeScript val by felixnordgren
HTTP
export default async function(req: Request): Promise<Response> {
// Setup CORS Headers
const headers = new Headers();
headers.set("Access-Control-Allow-Origin", "*");
headers.set("Access-Control-Allow-Methods", "GET, PUT, DELETE, OPTIONS");
headers.set("Access-Control-Allow-Headers", "Content-Type");
// List of image URLs
const images = [
"https://i.postimg.cc/QxpJhDB5/01.png",
"https://i.postimg.cc/9XwBgZCL/02.png",
tldraw_computer_example
@sparker
tldraw computer custom endpoint example This val is an example custom endpoint for tldraw computer 's data component. Usage To use this val with tldraw.computer, follow these steps: Fork this Val. Click the Copy endpoint button on your new Val. Open a project on tldraw.computer Create a Data component in your tldraw computer project In the Source dropdown, select Custom and the POST method Paste the endpoint into Data component's the HTTP Endpoint input. Run the component. To see the output, connect the Data component to a Text component. How it works In tldraw computer, you can configure a Data component to use a custom HTTP endpoint as its data source. You can also configure the request method, either GET or POST. If a Data component's request method is POST, then when the component next updates, it will send a POST request to the endpoint. The request's body will contain an array of the Data objects that the component had received as inputs. If the request method if GET, then the component will only make the request—its body will be empty. In both cases, the component will expect back a response that includes an array of Data objects these objects will be passed along as the data component's outputs. The endpoint (your forked version of this Val) can do whatever it likes between the request and response, but the response must include data in the correct format. If the format is wrong, the computer app will create a text data object instead that includes the response as plain text. Support If you're running into any difficulties, check out the #tldraw-computer channel on the tldraw discord.
HTTP
# tldraw computer custom endpoint example
This val is an example custom endpoint for [tldraw computer](tldraw.computer)'s data component.
### Usage
To use this val with tldraw.computer, follow these steps:
1. Fork this Val.
2. Click the **Copy endpoint** button on your new Val.
// This endpoint accepts and returns data.
type BooleanData = {
type: "boolean";
text: "true" | "false" | "maybe";
lucia_sqlite
@yawnxyz
An interactive, runnable TypeScript val by yawnxyz
Script
export async function createTables(userTable: string, sessionTable: string) {
return sqlite.batch([
`CREATE TABLE ${userTable} (
id TEXT NOT NULL PRIMARY KEY,
username TEXT NOT NULL UNIQUE,
hashed_password TEXT,
github_id INTEGER UNIQUE,
google_id TEXT UNIQUE
`CREATE TABLE ${sessionTable} (
id TEXT NOT NULL PRIMARY KEY,
htmlExample
@summerboys
HTML example This is an example of how to return an HTML response. You can also preview it at https://andreterron-htmlExample.web.val.run?name=Andre
HTTP
# HTML example
This is an example of how to return an HTML response.
You can also preview it at https://andreterron-htmlExample.web.val.run?name=Andre
// View at https://andreterron-htmlExample.web.val.run?name=Andre
export default async function(req: Request): Promise<Response> {
const query = new URL(req.url).searchParams;
// Read name from the querystring or body. Defaults to "you" if not present.
const name = query.get("name") || (await req.json().catch(() => ({}))).name || "you";
// Returns the HTML response
return new Response(`<h1>Hi summer ${name}!</h1>`, {