CoOp:Anything
게임을 검색해 협동 플레이 가능한 모드·단계·품질·커뮤니티 평점을 확인합니다
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기A small project using mostly AI where you have to guess a car each day.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Juego diario de adivinar un coche, al estilo Wordle. Cinco intentos: la foto empieza muy ampliada sobre un detalle y se va alejando con cada fallo. Cada día, un coche nuevo para todo el mundo.
SPA en React servida por Vercel, con funciones serverless/edge y Supabase detrás. Se publica también como app Android (Capacitor) empaquetando el mismo build web.
CLAUDE.md — convenciones,
reglas estrictas y las decisiones que conviene no re-litigar.PRODUCT.md · Diseño: DESIGN.md| Capa | Tecnología |
|---|---|
| Frontend | React 18, JSX puro (no TypeScript, no Next.js) |
| Bundler | Vite 8 — outDir: build por compatibilidad con el deploy histórico de CRA |
| Estilos | Tailwind CSS 3 + tema propio «Prensa del motor» (día/noche), PostCSS |
| Animación | framer-motion + keyframes propias en tailwind.config.js |
| Backend | Vercel Functions (Node) y Edge Functions en api/, Edge Middleware |
| Datos / Auth | Supabase (Postgres con RLS, Google OAuth) |
| Imágenes | sharp en servidor, proxy propio /api/daily-image, LQIP/blur-data |
| Infra extra | Vercel Edge Config (preload), Vercel Cron, Upstash Redis (rate-limit) |
| Observabilidad | Sentry (solo errores) · Web Vitals → Umami |
| App móvil | Capacitor 8 (Android) |
| Tests | Vitest + scripts propios de seguridad, RLS y estética |
src/ Frontend React (entry: src/index.jsx)
App.jsx Ruta principal (el juego). El resto son lazy-loaded.
components/ UI reutilizable (configurator/ es la pantalla de juego)
admin/ Panel interno /admin-tools
hooks/ Estado y lógica (useGame, useStats, useCountdown…)
lib/ Utilidades de cliente, con sus *.test.js al lado
data/ Catálogos estáticos (countries, catalog)
i18n/ i18n propio + locales es.json / en.json
api/ Endpoints Vercel — cada archivo es una ruta
_lib/ Helpers de servidor (prefijo _ ⇒ Vercel no los cuenta
como funciones); _lib/edge/ son las variantes Edge-safe
admin/ cron/ repesca/ Catch-alls que agrupan rutas en una sola función
lib/admin-handlers/ Lógica de los handlers admin, separada de api/
scripts/ SQL de migraciones + scripts de test y diagnóstico
android/ Proyecto Capacitor
docs/ Runbooks, guía de release Android, specs y planes
middleware.js Edge Middleware (preload de la imagen hero solo en "/")
vercel.json Rewrites SPA, headers, crons, límites de funciones
build/ es output generado, está gitignorado y no se edita a mano.
Requiere Node ≥ 20.19 (o ≥ 22.12), que es lo que pide Vite 8.
npm install
cp .env.example .env # y rellena los valores (ver el propio fichero)
Para desarrollar usa vercel dev, no npm run dev. Vite solo levanta el
front: si tocas /api/* necesitas el runtime de Vercel o las funciones
sencillamente no existen.
vercel dev # front + funciones
npm run build # build de producción a build/
Variables de entorno mínimas para arrancar: VITE_SUPABASE_URL,
VITE_SUPABASE_ANON_KEY (cliente) y SUPABASE_URL,
SUPABASE_SERVICE_ROLE_KEY, REPESCA_TOKEN_SECRET (servidor). Sin las dos
primeras la app arranca en pantalla negra. El resto son opcionales y degradan
en silencio. Todo está documentado en .env.example.
| Script | Qué hace |
|---|---|
npm test | Suite completa: estética + unit + seguridad + ataques |
npm run test:unit | Vitest (src/**, api/**, lib/**) |
npm run test:estetica | Falla si aparece emoji en UI, paleta cruda de Tailwind, glows o hex sueltos |
npm run test:layout | Mide en Chromium las dos composiciones de la app: el pliego sin scroll (5 pantallas × 3 estados × 2 temas) y el modo escritura con el teclado abierto (5 pantallas × 2 alturas de teclado). Fuera de npm test: necesita un build fresco (lo hace solo si hace falta) y un Chromium instalado |
npm run test:security | Comprobaciones de superficie de los endpoints |
npm run test:attacks | Reproduce ataques conocidos (reveal token forjado, brute-force, spoof de sesión anónima) |
npm run test:rls | Verifica las policies de Supabase — necesita credenciales reales, por eso no entra en npm test |
npm run build | Build de producción |
npm run cap:sync | Build + chequeo de tamaño + cap sync android |
npm run check:size | Red de seguridad del tamaño del bundle que viaja al APK |
npm run og:build | Regenera la imagen Open Graph |
vercel.json fija buildCommand: vitest run && vite build, así que un test
unitario roto tumba el deploy.
test:layout usa playwright-core, que no descarga navegadores: reutiliza
el Chromium o el Chrome que ya tengas. Si no lo encuentra, apúntale a él con
CDD_CHROMIUM=/ruta/al/binario.
Cinco intentos. Cada coche tiene su propio zoom base (cars.zoom_base,
rango 3.2–6.0, por defecto 3.7), que es el zoom del primer intento; de ahí baja
por una curva logarítmica con easing hasta base − 2 en el quinto.
La foto nunca viaja entera mientras la partida sigue abierta:
pick_daily_car, lee la URL
real del CDN (columna privilegiada) y recorta la imagen al área del
intento 5 antes de devolver los bytes.transform: scale() CSS sobre esa
imagen ya recortada.?t=…) entrega la imagen completa.La fórmula del zoom está duplicada a propósito en api/_lib/zoom.js y
src/lib/zoom.js: son réplicas y hay que mantenerlas en sync (ver regla 7 de
CLAUDE.md). Los tests zoom.sync.test.js lo vigilan.
filter: blur de CSS.useT()).Cuatro ideas que sostienen el resto y conviene no romper por accidente:
id, ni la URL real
del CDN (el nombre del fichero llevaba marca-modelo-año), ni más imagen de la
que ve un jugador legítimo en el intento 5. Las descripciones solo aparecen
en victoria.createAuthClient(token) y respeta las policies; getSupabaseAdmin()
(service role, salta RLS) queda para lo estrictamente privilegiado. Toda
columna nueva de public.cars necesita su GRANT SELECT… salvo las
excepciones deliberadas que documenta CLAUDE.md.REPESCA_TOKEN_SECRET para el reveal de imagen, los
pseudo-ids de repesca, las cookies anónimas y los tokens de imagen del garaje
(estos últimos cifrados con AES-GCM, no solo firmados).npm run test:attacks reproduce los intentos de bypass que ya se cerraron; si
tocas esta zona, esos tests son el contrato.
| Ruta | Para qué |
|---|---|
GET /api/get-daily-car | Estado de la partida de hoy (edge) |
POST /api/validate-guess | Valida un intento y persiste |
GET /api/daily-image | Proxy + recorte de la foto del día |
GET /api/car-image | Portadas del garaje (nítidas o borrosas, por token) |
GET /api/list-cars | Catálogo público para el autocompletado |
GET /api/garage | Colección del usuario |
GET /api/daily-stats | Distribución de resultados del día |
POST /api/delete-account | Borrado de cuenta (requisito de Play) |
POST /api/push | Alta/baja de suscripciones web push |
/api/repesca/{start,validate,image} | Flujo de repesca |
/api/admin/* | Panel interno |
/api/cron/* | warm-daily (Vercel Cron) y send-push (GitHub Actions) |
Vercel, con la región fra1 fijada por latencia contra Supabase.
main despliega a Production.Para la app Android, la guía completa (firma, versionado, subida a Play y el
incidente del AAB de 400 MB que motivó check:size) está en
docs/android-build-release.md.
Desde el panel /admin-tools: alta del coche, subida de la foto, punto focal,
zoom_base y descripciones (es/en, con traducción asistida opcional). El
catálogo ya no vive en un array del repo — está en Supabase.