The internet's visual snack. Upload, share, and discover images and short clips.
SocialTypeScript · JavaScriptGitHub @RASvibirOnlineOwner 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
imbrgr.website design repo
Translation pending
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
imbrgr.website — images, served hot. Community image and short-video hosting.
Built by ChloReform Studios (Irie Pharm · Victor Birkle). Visual identity: BRANDING.md.
Disclaimer: imbrgr is not affiliated with, endorsed by, or connected to Imgur. This project does not use Imgur’s name, logos, trademarks, or visual identity.
Plain-language mechanics for operators and contributors. End users see friendly labels in the app, not this section.Read the full README ↗imbrgr.website — images, served hot. Community image and short-video hosting.
Built by ChloReform Studios (Irie Pharm · Victor Birkle). Visual identity: BRANDING.md.
Disclaimer: imbrgr is not affiliated with, endorsed by, or connected to Imgur. This project does not use Imgur’s name, logos, trademarks, or visual identity.
Plain-language mechanics for operators and contributors. End users see friendly labels in the app, not this section.
Post.viewCount), not page reloads.voterKey: signed-in users use a stable user-based key; guests use the imbrgr_vid cookie (a:… prefix).voterKey on media) do not increment cook count when they view their own post.PostView row and increments cook count; later visits from the same key update hitCount but do not increment cook count again.recordPostView in src/lib/post-views.ts): excess requests within the window are ignored without error.spiceScore is kitchen-themed engagement heat on a post (separate from the unique cook counter).spiceDeltaForView: +1 for a guest’s first unique cook, +1 on repeat visits from the same key, +0 on a signed-in user’s first unique cook (repeat signed-in visits still add +1).src/lib/cheese-spice.ts); levels are derived from score bands, not separate counters.hotScore on the post.The /hot feed sorts public, non–admin-hidden posts by hotScore (desc), then createdAt.
hotScore is recomputed when views/spice change:
engagement = viewCount × 3 + spiceScore × 2 + 1
ageHours = max(0.25, hours since createdAt)
hotScore = engagement / (ageHours + 2)^1.35
(see src/lib/hot-score.ts).
Gallery “Most viral” uses a separate Reddit-style hotScore on votes (src/lib/ranking.ts), not the Hot page formula.
| Level | Meaning | Typical surfacing |
|---|---|---|
| PUBLIC | Listed for everyone | Home/Hot feeds (if not hidden), search, tags, public profiles |
| UNLISTED | Link-only | Direct /p / /i URLs; not promoted in public feeds/search |
| PRIVATE | Owner-only | Hidden from others; file route returns 404 to non-owners |
Admin-hidden (hiddenByAdmin) | Moderation hold | Treated like hidden from the public; owners may still see their post depending on route |
Uploads and studio creations default to public on the gallery (Home / Hot). Signed-in users can choose unlisted or private before or after upload; their default post visibility in settings applies when they do not pick one (migration 20261007200000_default_post_visibility_public sets existing UNLISTED defaults to PUBLIC; users who chose PRIVATE are unchanged). Guests are always public (server-enforced); private and unlisted controls are hidden until they sign in.
src/lib/thumbnails.ts) and stored via putObject (local disk or Vercel Blob when STORAGE_DRIVER=blob).warmFeedThumbnails after the response (after() from next/server) to generate missing thumbs for a capped number of cards—best-effort, deduped per media id./api/media/file/* with the same access checks as originals; going private or admin-hidden purges thumb blobs and clears thumb columns; deletes remove storageKey and both thumb keys.Cache-Control: private, no-store; other gated gallery media avoids long immutable public cache (see src/lib/serve-media-file.ts).LibrarySave rows with label __studio_auto__). Off: auto-save tracks only the latest version in that family (no duplicate original in the auto cache). Manual saves from the image menu always work for whichever version is on screen. Preference: User.studioKeepOriginal or guest localStorage (imbrgr_studio_keep_original). Sync runs after AI generate, studio import, and versioned edits (src/lib/library-auto-save.ts).Media.rootMediaId); manual and AI edits always create new versions; Revert to original uses the version strip. This is separate from the auto-library toggle above.POST /api/library/save records the current media version in LibrarySave (signed-in userId or guest voterKey). Visibility on save respects the studio visibility control (AI gens default public unless the user chose otherwise).LibraryFolder per owner; create/rename/delete via /api/library/folders. Saves can target a folder by id or new folder name from the studio menu./library and the My images tab on your own profile list folders and saves (GET /api/library). Guest library rows are claimed on sign-in with posts/media ().remixedFromPostId from a public source post; studio can open with ?remixFrom=.voterKey and optional delete tokens; on sign-in, POST /api/auth/claim-guest reassigns guest posts/media to the new user when the cookie matches.POST /api/reports) accept targets POST, MEDIA, COLLECTION, USER with resolved canonical ids; admins triage in the console.src/lib/ai/prompt-enhance.ts); skipped for very short prompts.gen.pollinations.ai); optional POLLINATIONS_API_KEY; mock path when AI_MOCK=true (E2E).src/lib/prompt-safety.ts rejects disallowed patterns before generate/edit.AiGenerationUsage (limit AI_DAILY_LIMIT or per-user override); guests use AiAnonymousUsage keyed by IP hash with ANON_AI_DAILY_LIMIT / admin site setting.UPLOAD_RATE_LIMIT_PER_HOUR and AI_RATE_LIMIT_PER_HOUR.SUPERADMIN role + SUPERADMIN_USERNAMES) get /admin: dashboard stats, user/post/media moderation, reports, site settings (e.g. guest AI limit), thumbnail backfill batches, audit log.See the table below for descriptions. Never commit values. Common names: DATABASE_URL, DATABASE_URL_UNPOOLED, AUTH_SECRET, STORAGE_DRIVER, BLOB_READ_WRITE_TOKEN, NEXT_PUBLIC_SITE_URL, USER_STORAGE_QUOTA_BYTES, ANON_STORAGE_QUOTA_BYTES, AI_DAILY_LIMIT, ANON_AI_DAILY_LIMIT, POLLINATIONS_API_KEY, OLLAMA_HOST, OLLAMA_MODEL, OLLAMA_API_KEY, GROQ_API_KEY, GEMINI_API_KEY, GEMINI_MODEL, GEMINI_IMAGE_MODEL, UPLOAD_RATE_LIMIT_PER_HOUR, AI_RATE_LIMIT_PER_HOUR, SUPERADMIN_USERNAMES, AI_MOCK, AI_ENHANCE_TIMEOUT_MS.
/p/{id} links, direct /i/{id} pages, embed HTML/u/{username}): posts, favorites (if public), comments, statsUSER_STORAGE_QUOTA_BYTES) and smaller anonymous cap; server-enforced on every upload/studio): import (upload / paste / URL), convert (PNG/JPEG/WebP/AVIF + resize), manual editor, AI Flux generation, Gemini natural-language edits, share/embed links/studio?tab=media): local browser image/video/GIF/audio import, reorder + trim controls, side-by-side/stacked/grid/overlay/picture-in-picture/collage layouts, WebM export fallback, and pacNcap-inspired eco filter previewAiPromptCache)| Layer | Technology |
|---|---|
| App | Next.js 16 App Router, React 19, TypeScript, Tailwind CSS 4 |
| Auth | Auth.js (next-auth) credentials + JWT sessions |
| Database | Prisma 7 + PostgreSQL (Neon in production) |
| Neon config | @neon/config + root neon.ts (owner runs neon link / neon deploy on their machine) |
| Storage | Local disk (data/uploads) or Vercel Blob (STORAGE_DRIVER=blob) |
Copy .env.example to .env, or after linking Neon run neon env pull (never commit .env).
| Variable | Required | Description |
|---|---|---|
DATABASE_URL | Yes | Pooled Postgres URL — app runtime (@prisma/adapter-pg) |
DATABASE_URL_UNPOOLED | Yes for migrations | Direct URL — Prisma migrate / db execute |
NEON_BRANCH | No | Branch name from Neon CLI (informational) |
AUTH_SECRET | Yes | Session signing (openssl rand -base64 32) |
STORAGE_DRIVER | No | local (default) or blob |
BLOB_READ_WRITE_TOKEN | If blob | Vercel Blob token |
NEXT_PUBLIC_SITE_URL | No | Canonical URL for share links |
USER_STORAGE_QUOTA_BYTES | No | Per-account storage cap (default 1 GiB) |
ANON_STORAGE_QUOTA_BYTES | No | Guest upload cap (default 50 MiB) |
AI_DAILY_LIMIT | No | AI generations per user per UTC day (default 20) |
OLLAMA_HOST, OLLAMA_MODEL, OLLAMA_API_KEY | No | First tier for prompt enhance |
GROQ_API_KEY | No | Second tier (Llama 3.3) |
GEMINI_API_KEY, GEMINI_MODEL | No | Gemini for complex prompt enhance + image edits |
GEMINI_IMAGE_MODEL | No | Gemini model for natural-language image edits (studio) |
POLLINATIONS_API_KEY | No | Optional key for gen.pollinations.ai Flux renders |
ANON_AI_DAILY_LIMIT | No | Guest AI generations per UTC day (default 5) |
UPLOAD_RATE_LIMIT_PER_HOUR | No | Per-IP/user upload throttle (default 60) |
Global setup seeds users via tsx scripts/e2e-seed.ts (avoids loading the Prisma ESM client from Playwright’s CJS global-setup).
docker compose up -d # or local Postgres
npm run db:migrate:deploy
export DATABASE_URL=postgresql://imbrgr:imbrgr@localhost:5432/imbrgr?schema=public
npm run build
STORAGE_DRIVER=local AI_MOCK=true npm run test:e2e
npm run test:e2e:artifacts # optional screenshots → /opt/cursor/artifacts
See docs/testing.md for CI, environment gotchas and the guest-cookie rule.
The AR Camera (/tools/ar) uses @mediapipe/tasks-vision for client-side face landmarking. Run:
npm run ar:assets
This copies the MediaPipe WASM runtime into public/mediapipe/wasm/ and downloads face_landmarker.task into public/mediapipe/models/. These binaries are git-ignored.
Production builds must run ar:assets before next build (e.g. npm run ar:assets && npm run build) so that /mediapipe/ static assets are included in the deployment artifact. Otherwise, the AR tool will 404 on local asset routes.
Offline & CI Caveat: Downloading
face_landmarker.taskrequires outbound HTTPS network access tostorage.googleapis.comat build/sync time. In offline or air-gapped CI pipelines, the model file must be pre-cached or supplied via pipeline cache to prevent build failures.
For deployment options, CDN hosting alternatives, and Content Security Policy (CSP) requirements, see docs/ar-deployment.md.
On Vercel set STORAGE_DRIVER=blob and BLOB_READ_WRITE_TOKEN (required for uploads and for /api/media/file/* streaming). Without them, production defaults to local disk and files 404.
Image bytes are served at /api/media/file/<storageKey> (e.g. /api/media/file/uuid.jpg?mime=image%2Fjpeg). JSON metadata stays at /api/media/<shortId>.
Production uses a public Blob store (imbrgr13-media). Private files are never listed in feeds/search and the file route returns 404 to non-owners, with Cache-Control: private, no-store. Direct Blob CDN URLs are not exposed in the UI; however, anyone who obtained a raw Blob URL could still fetch the object. For stricter isolation, use a private Blob store or proxy-only delivery and rotate storage keys when visibility changes from public to private.
Do not commit .env, .neon, or connection strings.
docker compose up -d
cp .env.example .env
# DATABASE_URL and DATABASE_URL_UNPOOLED can be the same local URL
npm run db:migrate:deploy
npm run db:seed
On a machine with the Neon CLI linked to project purple-sea-37945850 (branch production):
neon env pull # writes DATABASE_URL + DATABASE_URL_UNPOOLED (+ NEON_BRANCH) to .env
Apply migrations against the unpooled URL (Prisma config reads DATABASE_URL_UNPOOLED automatically):
export $(grep -v '^#' .env | xargs) # or use dotenv
npm run db:migrate:deploy
For a new migration during development:
npm run db:migrate
Deploy app env to Vercel with at least DATABASE_URL (pooled) and DATABASE_URL_UNPOOLED (for build-time migrate if you run it in CI).
npm install
cp .env.example .env
docker compose up -d
npm run db:migrate:deploy
npm run db:seed
npm run brand:assets
npm run dev
Open http://localhost:3000.
Demo login: [email protected] / password123 (after seed).
| Command | Description |
|---|---|
npm run dev | Development server |
npm run build | Production build |
npm run start | Run production server |
npm run lint | ESLint |
npm run typecheck | tsc --noEmit |
npm run test | Vitest (ranking, validation, storage quota, AI usage & prompt failover) |
npm run db:migrate | Create/apply migrations in dev (migrate dev) |
npm run db:migrate:deploy | Apply migrations (migrate deploy) — use on Neon/production |
npm run db:seed | Seed demo data |
npm run brand:assets | Export PNG/ICO brand assets |
DATABASE_URL (pooled), DATABASE_URL_UNPOOLED, AUTH_SECRET, and blob vars as needed.npm run db:migrate:deploy against production (CI step or once manually).npm run build (runs prisma generate via postinstall).Proprietary — ChloReform Studios / Irie Pharm unless otherwise noted.
claim-guest.tsAI_RATE_LIMIT_PER_HOUR |
| No |
| Per-IP/user AI throttle (default 30) |
SUPERADMIN_USERNAMES | No | Comma-separated usernames allowed as super admin (default vibir; must also have SUPERADMIN role in DB) |