Easy-to-manage touch screens
Free, open-source touch screens. Guided USB setup, a drag-and-drop editor and local control. Made for Home Assistant.
A modern palm reading grounded in real palmistry. Upload or snap a photo of your palm and ask the reader anything.
LifestyleTypeScript · CSSGitHub @ranjithnairai-makerOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Palm reading app
Translation pending
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
A small, polished web app for AI palm readings grounded in real palmistry. Upload
or snap a photo of your palm, get a reading of your hand's element and the four
major lines, ask follow-up questions, and share the result via a permanent
unguessable link. No accounts.
• Next.js (App Router) + Tailwind CSS v4 — front end
• Next Route Handlers — API, deployed as Vercel Serverless Functions
• OpenRouter (OpenAI-compatible Chat Completions) — vision + chat, server-side only
• Supabase — Postgres for readings/messages, private Storage bucket for images
• Vercel — hostingRead the full README ↗A small, polished web app for AI palm readings grounded in real palmistry. Upload or snap a photo of your palm, get a reading of your hand's element and the four major lines, ask follow-up questions, and share the result via a permanent unguessable link. No accounts.
npm install
cp .env.example .env.local # then fill in the values below
npm run dev
Open http://localhost:3000.
| Variable | Where to get it |
|---|---|
OPENROUTER_API_KEY | https://openrouter.ai/keys |
OPENROUTER_MODEL | Any image-capable model id from https://openrouter.ai/models. Default inclusionai/ling-3.0-flash-vl:free (free, multimodal; reasons heavily before answering, so calls budget generous maxTokens). Swap to a paid vision model — e.g. google/gemini-2.0-flash-001 — with no code changes. |
SUPABASE_URL | Supabase → Project Settings → Data API → Project URL |
SUPABASE_SERVICE_ROLE_KEY | Supabase → Project Settings → API Keys → service_role. Server-side only. Never expose to the client. |
NEXT_PUBLIC_SITE_URL | Canonical origin for absolute share links and Open Graph images — set to https://palmistica.com in production (see Domain & Hosting below). Falls back to the Vercel URL, then the request host, if unset. |
RATE_LIMIT_SALT | Optional. Salts the IP hash used for rate limiting (lib/rateLimit.ts) so it can't be reversed even with DB read access. Any random string; has a safe built-in default if unset. |
CRON_SECRET | Optional but recommended. Vercel sends this as Authorization: Bearer <value> when it triggers the daily image-retention job; set it in Vercel too so the job can't be triggered by anyone who finds the URL. |
NEXT_PUBLIC_CONTACT_EMAIL | Optional. Shown in the footer as a fallback for anyone who lost the browser (and localStorage token) that created a reading and needs it removed manually. Omit to hide that line. |
NEXT_PUBLIC_TIP_LINK_1 / _3 / _5 | Optional. Stripe Payment Link URLs for the $1/$3/$5 support buttons (plain outbound links — no checkout code, no webhooks, no payment data ever touches this app). The tip strip only renders if at least one is set. |
Run supabase/schema.sql against your project (or use the Supabase SQL editor).
It creates the readings, reading_messages, rate_limit_hits, and
deleted_readings tables with RLS enabled and no policies — every
read/write goes through the service role key on the server. Also create a
private Storage bucket named palm-photos.
POST /api/readings — validates the compressed base64 image, uploads it to
the palm-photos bucket, inserts a readings row (status: 'processing'),
returns { id, ownerToken } immediately. ownerToken is returned exactly
once — the client stashes it in localStorage so it can delete the reading
later (see Manual delete, below).POST /api/readings/[id]/generate — fired by the client without blocking
navigation. Downloads the stored image and calls the OpenRouter vision model
once, parsing its reply into structured analysis_json (hand element,
and traits + a takeaway for each of the four major lines). A second,
text-only call then turns that JSON into the Quick Insights reading
(reading_text) the user sees first. Sets status: 'complete', or
'failed' on error. The model call is aborted at 55s so a slow reading
always resolves to a retryable failed state rather than hanging./reading/[id] — shows the palm photo, Quick Insights, and a "Reveal
Your Full Reading" button; polls while processing; hosts the follow-up chat.POST /api/readings/[id]/detailed — triggered by that button. A
third, text-only call (no image, no re-analysis) expands analysis_json
into the longer, themed Detailed Reading (detailed_text) — Vitality,
Love, Mind, and Path. Idempotent: generated once per reading, then just
returned.POST /api/readings/[id]/messages — answers follow-ups grounded in the
full analysis_json (and detailed_text, once generated) regardless of
which tier the viewer is currently looking at, plus recent chat turns./r/[id] — the same reading, read-only, for sharing. Also visible here
(and on /reading/[id]): a quiet, always-shown tip strip (Stripe Payment
Links, if configured), and — only in the browser that created the
reading — a "Delete this reading" control at the very bottom.DELETE /api/readings/[id] requires the owner_token
from step 1 in the request body and rejects with 403 on any mismatch. On
success it removes the stored photo, tombstones the id in
deleted_readings (so the link later shows a friendly "removed by its
owner" message instead of a bare 404), and deletes the readings row
(cascading to its messages).Palmistica has no accounts — see SECURITY.md for the full rules
this project follows and how "access control" is adapted for a no-login app
(short version: unguessable UUIDs, per-IP rate limiting on every endpoint
that costs money or storage, a timing-safe owner_token check as the one
real authorization boundary for deletion, private Storage bucket + signed
URLs, RLS with no policies on every table, security headers + CSP, and no
secrets or raw error detail ever reaching the client). Read it before adding
a new route or touching anything under lib/.
The initial reading route needs up to ~60s on the free model. Vercel Hobby caps serverless functions at 60s; a paid vision model returns in a few seconds and removes the risk entirely. On Pro you can raise
maxDurationin the route files.
vercel.json defines a daily Cron job for image retention — Vercel's Hobby
plan allows one run per day per cron, which matches the schedule here, so no
plan change is needed. Set CRON_SECRET (Production) so that endpoint isn't
publicly triggerable. To enable the tip strip, create three Stripe Payment
Links ($1/$3/$5) and set NEXT_PUBLIC_TIP_LINK_1/_3/_5.
palmistica.com is registered through Hostinger, but the app itself is
hosted on Vercel — Hostinger is only the registrar/DNS host here, it
never serves the app. These are dashboard steps in two different consoles;
none of it can be scripted from this repo, so it's documented here instead.
Do not switch the domain's nameservers to Vercel's. Add DNS records at Hostinger that point to Vercel instead, so Hostinger's DNS panel stays the single place to manage records for this domain (useful if email or anything else ever gets added on it later).
palmistica.com. Vercel will also offer to add
www.palmistica.com — add both. Set the apex palmistica.com as
canonical and have www redirect to it (simpler for share links and QR
codes than the reverse).@) — commonly 76.76.21.21, but
confirm against the dashboard.www — a value like
xxxxxxxxxxxxxxxx.vercel-dns-XXX.com, unique to your project.palmistica.com → DNS / Name Servers
→ DNS Zone Editor (keep Hostinger's default nameservers — do not switch
to Vercel's nameserver method here). Add the A and CNAME records from
step 2. Remove any pre-existing "parked domain" A/CNAME records
Hostinger auto-created for @ and www — conflicting records are the
most common cause of Vercel showing "Invalid Configuration."NEXT_PUBLIC_SITE_URL=https://palmistica.com in Vercel's
Environment Variables (Production) and redeploy. This is already wired
as metadataBase in app/layout.tsx's metadata export, so it affects
every absolute URL the app generates — canonical share links, and the
Open Graph/Twitter images described above.Nothing outstanding right now. (Rate limiting, image retention, and
per-reading suggested-question chips were all on this list originally —
all three are now built; see Security above, "How it works," and
lib/prompts.ts's ANALYSIS_SYSTEM for the chips.)
vercel.jsonGET /api/cron/prune-imagesimage_pathheadline into analysis_json (no extra API call). When
a /r/[id] link is shared, app/r/[id]/opengraph-image.tsx and
twitter-image.tsx (sharing render logic from lib/og-image.tsx)
generate a branded 1200×630 preview image from that headline using
next/og — never the user's actual photo, so it stays fast, private,
and unaffected by the 90-day photo prune. generateMetadata in
app/r/[id]/page.tsx sets the page title/description and Open Graph /
Twitter Card tags from the same data; /r/[id] stays noindex for
search engines throughout — that only affects search, not link previews.