74- 'name': The race name.
75- 'description': 1-2 sentences max.
76- 'styleHint': 3-5 descriptive keywords for image generation.
77- 'effectColor': A hex color code (#RRGGBB format) associated with the race.
78- 'borderAnimationHint': OPTIONAL. A single keyword suggesting a subtle border animation style for the active card. Choose from 'shimmer', 'pulse', or 'none'. If unsure, use 'none'.
273/* --- Animated Border Styles --- */
274@keyframes border-shimmer { /* Gradient sweep */
2750% { border-image-source: linear-gradient(90deg, transparent 0%, var(--effect-color) 50%, transparent 100%); }
27625% { border-image-source: linear-gradient(90deg, transparent 25%, var(--effect-color) 75%, transparent 100%); }
27750% { border-image-source: linear-gradient(90deg, transparent 50%, var(--effect-color) 100%); }
27875% { border-image-source: linear-gradient(90deg, var(--effect-color) 0%, transparent 25%); }
279100% { border-image-source: linear-gradient(90deg, var(--effect-color) 50%, transparent 100%); }
280}
281@keyframes border-pulse { /* Simple fade in/out */
288border-width: 2px;
289border-style: solid;
290border-image-slice: 1;
291border-image-source: linear-gradient(90deg, transparent 0%, var(--effect-color) 50%, transparent 100%); /* Initial state */
292animation: border-shimmer var(--border-anim-duration) linear infinite;
293}
298299300/* --- Other Styles (Images, Content, Effects - mostly unchanged) --- */
301.race-card img { pointer-events: none; height: 60%; border-radius: 16px 16px 0 0; width: 100%; object-fit: cover; display: block; background-color: #333;}
302.race-card .card-content { pointer-events: none; padding: 20px; display: flex; flex-direction: column; gap: 12px; flex-grow: 1; position: relative; z-index: 2; background: inherit; border-radius: 0 0 16px 16px;} /* Ensure content bg matches card */
448449const prompt = encodeURIComponent(\`disney fantasy character portrait, \${safeStyleHint}, \${safeName}, detailed illustration, cinematic lighting, high fantasy art style\`);
450const imageUrl = \`http://maxm-imggenurl.web.val.run//\${prompt}.jpg\`; // Using Pollinations.ai as example
451const fallbackColor = safeEffectColor.substring(1);
452const fallbackUrl = \`https://placehold.co/400x400/\${fallbackColor}/1A1A1E?text=\${encodeURIComponent(safeName)}\`;
453454card.innerHTML = \`
455<img src="\${imageUrl}" alt="Image of \${safeName}" loading="lazy" onerror="this.onerror=null; this.src='\${fallbackUrl}'; console.warn('Image failed for \${safeName}. Using fallback.');">
456<div class="\${EFFECT_CONTAINER_CLASS}"><div class="energy-surge"></div></div>
457<div class="card-content">
139body::before {
140content: ""; position: fixed; top: 0; left: 0; width: 100%; height: 100%;
141background-image:
142linear-gradient(to right, rgba(255, 255, 255, 0.05) 1px, transparent 1px),
143linear-gradient(to bottom, rgba(255, 255, 255, 0.05) 1px, transparent 1px);
386/* Gallery & Contact Placeholders */
387.gallery-grid { display: flex; flex-wrap: wrap; gap: 1rem; justify-content: center; padding: 1rem; }
388.gallery-grid .image-container {
389width: 150px; height: 150px; border-radius: 15px; overflow: hidden;
390border: 1px solid var(--color-border); background: var(--color-bg);
391box-shadow: 0 4px 15px var(--shadow-color);
392}
393.gallery-grid .image-container img { width: 100%; height: 100%; object-fit: cover; }
394395/* Crystal Container for static info page (if used) */
515<h2 class="tab-title" data-translate="galleryTitle">Gallery</h2>
516<div class="gallery-grid">
517<div class="image-container"><img src="https://images.unsplash.com/photo-1677756119517-756a188d2d94?ixlib=rb-4.0.3&q=85&fm=jpg&crop=entropy&cs=srgb&w=600" alt="AI 1"></div>
518<div class="image-container"><img src="https://images.unsplash.com/photo-1696258680260-492036cd6559?ixlib=rb-4.0.3&q=85&fm=jpg&crop=entropy&cs=srgb&w=600" alt="AI 2"></div>
519<div class="image-container"><img src="https://images.unsplash.com/photo-1684495809981-394107651435?ixlib=rb-4.0.3&q=85&fm=jpg&crop=entropy&cs=srgb&w=600" alt="AI 3"></div>
520</div>
521</div>
43}
4445// Set temporary image on "Yes" click
46setCurrentImg(tempYesImg);
4748// Revert back to the default image after 1 second
49setTimeout(() => {
50setCurrentImg(yesImg);
55setIsNoClicked(true);
56setIsYesClicked(false);
57setCurrentImg(noImg); // Keep no image as long as "No" is clicked
58};
59
130width: 100%;
131height: 100%;
132background-image:
133linear-gradient(to right, rgba(200, 200, 200, 0.1) 1px, transparent 1px), /* Slightly darker grid */
134linear-gradient(to bottom, rgba(200, 200, 200, 0.1) 1px, transparent 1px);
67- 'name': The name of the race (string).
68- 'description': A brief description (string, 1-2 sentences maximum).
69- 'styleHint': 3-5 descriptive keywords for generating an image (string).
70- 'effectColor': A valid CSS hexadecimal color code string (e.g., "#RRGGBB").
71
MiniAppStarterindex.tsx3 matches
5import * as db from "./db.ts";
6import { embedMetadata, handleFarcasterEndpoints, name } from "./farcaster.ts";
7import { handleImageEndpoints } from "./image.tsx";
89const app = new Hono();
1011handleImageEndpoints(app);
12handleFarcasterEndpoints(app);
1344<meta name="fc:frame" content={JSON.stringify(embedMetadata(baseUrl, path))} />
45<link rel="icon" href={baseUrl + "/icon"} />
46<meta property="og:image" content={baseUrl + "/image"} />
47</head>
48<body class="bg-white text-black dark:bg-black dark:text-white">
MiniAppStarterimage.tsx12 matches
5import satori from "npm:satori";
67export function handleImageEndpoints(app: Hono) {
8const headers = {
9"Content-Type": "image/png",
10"cache-control": "public, max-age=86400",
11};
12app.get("/image", async (c) => {
13return c.body(await homeImage(), 200, headers);
14});
15app.get("/icon", async (c) => {
16return c.body(await iconImage(), 200, headers);
17});
18}
1920export async function homeImage() {
21return await ogImage(
22<div tw="w-full h-full flex justify-start items-end text-[100px] bg-black text-white p-[50px]">
23<div tw="flex flex-col items-start gap-[10px]">
31}
3233export async function iconImage() {
34return await ogImage(
35<div tw="w-full h-full flex justify-center items-center text-[100px] bg-black text-white p-[50px]">
36<img tw="w-[350px] h-[350px]" src={base64Icon(SquareDashed)} />
45//////////
4647export async function ogImage(body, options = {}) {
48const svg = await satori(
49body,
57if (code === "emoji") {
58const unicode = segment.codePointAt(0).toString(16).toUpperCase();
59return `data:image/svg+xml;base64,` + btoa(await loadEmoji(unicode));
60}
61return "";
94const base64 = Buffer.from(svg).toString("base64");
95// console.log('getIconDataUrl', name, svg, base64)
96return `data:image/svg+xml;base64,${base64}`;
97};
MiniAppStarterfarcaster.ts4 matches
5export const name = "Mini App Starter";
6// export const iconUrl = "https://imgur.com/TrJLlwp.png";
7// export const ogImageUrl = "https://imgur.com/xKVOVUE.png";
89export function embedMetadata(baseUrl: string, path: string = "/") {
10return {
11version: "next",
12imageUrl: baseUrl + "/image",
13button: {
14title: name,
17name: name,
18url: baseUrl + path,
19splashImageUrl: baseUrl + "/icon",
20splashBackgroundColor: "#111111",
21},
55"iconUrl": baseUrl + "/icon",
56"homeUrl": baseUrl,
57"splashImageUrl": baseUrl + "/icon",
58"splashBackgroundColor": "#111111",
59"primaryCategory": "developer-tools",
amusingTealKangarooREADME.md1 match
3Protect your vals behind a password. Use session cookies to persist authentication.
45
67## Usage
3View and interact with your Val Town SQLite data. It's based off Steve's excellent [SQLite Admin](https://www.val.town/v/stevekrouse/sqlite_admin?v=46) val, adding the ability to run SQLite queries directly in the interface. This new version has a revised UI and that's heavily inspired by [LibSQL Studio](https://github.com/invisal/libsql-studio) by [invisal](https://github.com/invisal). This is now more an SPA, with tables, queries and results showing up on the same page.
45
67## Install