OhMyGame
OhMyGame is the open-source studio for making games with AI. Design, build, playtest, and publish games in one app, with your own model keys.
4-lane rhythm game synced to a music video
Translation pending
GamesTypeScript · PythonGitHub @Alfira0526OnlineOwner 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
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗4-lane web rhythm game. Music and video come from an official YouTube music video embed (YouTube IFrame API). The project never hosts or ships audio files: an audio file is used only on your own machine to generate a first-draft chart, and is git-ignored.
lib/youtube.ts)app/api/scores) on Postgres, with an in-memory fallback for local dev@vercel/analytics) mounted in the root layout#F7CAC9 + Serenity #92A8D1 on a dark serenity-tinted basetools/generate_chart.py, librosa) and an in-browser chart editor (/editor)npm install
npm run dev # http://localhost:3000
Keyboard: D F J K = lanes 1–4, Esc = pause. On phones, tap the lanes.
Set DATABASE_URL (Neon, Supabase, Vercel Postgres, any Postgres). STORAGE_URL,
POSTGRES_URL and NEON_DATABASE_URL are accepted too, so the Vercel Neon integration
works with its default prefix. The scores table is
created automatically. Without it, scores live in process memory and vanish on restart;
the UI shows a warning in that case.
DATABASE_URL env var.lib/songs.ts gives every song a status. live songs are public. test songs, the
chart editor (/editor) and their leaderboards are served only to IPs listed in
EDITOR_ALLOWED_IPS (comma-separated; a trailing . or : allows a prefix). Open
/api/access on the deployed site to read the IP Vercel sees for you. With the variable
unset nothing is privileged in production; next dev allows everything.
Workflow for a new song: add it as test, calibrate its videoOffset in the editor,
overwrite the chart JSON, then flip status to live and deploy.
pip install librosa soundfile
python3 tools/generate_chart.py path/to/song.mp3 \
--id my-song --title "Title" --artist "Artist" --video-id YOUTUBE_ID \
--video-duration 155 \
--out public/charts/my-song.json
Pass --video-duration (seconds) when the YouTube video is longer than the audio file
(intro/outro). The chart's videoOffset then has to be set in the editor:
play the video, press 첫 노트 맞추기 the moment the first note is heard, then fine-tune
with Space taps, download, and overwrite the JSON.
Then add the song to lib/songs.ts. The generator writes four difficulties
(easy / normal / hard / extreme) on the detected beat grid; expect to hand-edit the result.
EASY, NORMAL and HARD are open. EXTREME unlocks per song after a HARD full combo (stored in the browser). The ranking API also refuses an EXTREME score unless that player already has a HARD full-combo row on the leaderboard, so the unlock cannot be faked just by editing localStorage.
Charts are meant to be played with two thumbs (left = lanes 1–2, right = lanes 3–4).
tools/check_chart.py enforces that: at most two simultaneous notes, chords split across
hands, nothing on a hand that is holding, and minimum same-hand / any-hand gaps per
difficulty. The generator runs it automatically; run it on edited charts with
python3 tools/check_chart.py public/charts/*.json # report
python3 tools/check_chart.py public/charts/*.json --fix # rewrite in place
Open /editor. Click an empty cell to add a note on the beat grid, click a note to delete it.
While the video plays, tap Space on the beat at least 8 times to measure the
video offset (the difference between the analysed audio and the YouTube video), apply it,
then download the JSON and overwrite public/charts/<id>.json.
| judgement | window | points |
|---|---|---|
| PERFECT | ±65 ms | 100 |
| GREAT | ±115 ms | 80 |
| GOOD | ±170 ms | 50 |
| MISS | — | 0 |
Score = points / max points × 1,000,000. HP starts at 100; MISS costs 4 / 6 / 8 / 10
(easy / normal / hard / extreme), PERFECT heals 1.0 / 0.7 / 0.5 / 0.4; HP 0 = game over.
Notes fall 15 % slower on EASY and 10 % / 20 % faster on HARD / EXTREME than the
player's setting. Every per-difficulty number lives in lib/difficulty.ts; chart density
rules live in DIFFICULTY_PARAMS at the top of tools/generate_chart.py and can be
overridden per run with --tune level.key=value.
Hold notes are judged at the head and again at the tail (release too early = MISS).
Windows are deliberately wide because the clock comes from a YouTube embed.
Settings → 타이밍 보정 → 보정 시작. No song or video is used: sixteen click notes play at 120 BPM from the Web Audio clock. The first four are practice (lower tone), the remaining twelve are measured (higher tone). The median hit offset of those twelve becomes the new 판정 오프셋, shown for you to apply, re-measure or cancel. Because this measures touch and audio latency rather than the YouTube clock, use 노트 위치 보정 if notes still look early or late against a specific video.
Note speed is a 1–10 level (설정 → 노트 속도): level 1 = 2.4 s from the top of the lane to the hit line, each level 0.2 s faster, level 10 = 0.6 s. Difficulty scales it further (EASY ×1.15, HARD ×0.9, EXTREME ×0.8).
lib/songs.ts gives every song a status. live songs are public. test songs, the
chart editor (/editor) and their leaderboards are served only to IPs listed in
EDITOR_ALLOWED_IPS (comma-separated; a trailing . or : allows a prefix). Open
/api/access on the deployed site to read the IP Vercel sees for you. With the variable
unset nothing is privileged in production; next dev allows everything.
Workflow for a new song: add it as test, calibrate its videoOffset in the editor,
overwrite the chart JSON, then flip status to live and deploy.
pip install librosa soundfile
python3 tools/generate_chart.py path/to/song.mp3 \
--id my-song --title "Title" --artist "Artist" --video-id YOUTUBE_ID \
--video-duration 155 \
--out public/charts/my-song.json
Pass --video-duration (seconds) when the YouTube video is longer than the audio file
(intro/outro). The chart's videoOffset then has to be set in the editor:
play the video, press 첫 노트 맞추기 the moment the first note is heard, then fine-tune
with Space taps, download, and overwrite the JSON.
Then add the song to lib/songs.ts. The generator writes four difficulties
(easy / normal / hard / extreme) on the detected beat grid; expect to hand-edit the result.
EASY, NORMAL and HARD are open. EXTREME unlocks per song after a HARD full combo (stored in the browser). The ranking API also refuses an EXTREME score unless that player already has a HARD full-combo row on the leaderboard, so the unlock cannot be faked just by editing localStorage.
Charts are meant to be played with two thumbs (left = lanes 1–2, right = lanes 3–4).
tools/check_chart.py enforces that: at most two simultaneous notes, chords split across
hands, nothing on a hand that is holding, and minimum same-hand / any-hand gaps per
difficulty. The generator runs it automatically; run it on edited charts with
python3 tools/check_chart.py public/charts/*.json # report
python3 tools/check_chart.py public/charts/*.json --fix # rewrite in place
Open /editor. Click an empty cell to add a note on the beat grid, click a note to delete it.
While the video plays, tap Space on the beat at least 8 times to measure the
video offset (the difference between the analysed audio and the YouTube video), apply it,
then download the JSON and overwrite public/charts/<id>.json.
| judgement | window | points |
|---|---|---|
| PERFECT | ±65 ms | 100 |
| GREAT | ±115 ms | 80 |
| GOOD | ±170 ms | 50 |
| MISS | — | 0 |
Score = points / max points × 1,000,000. HP starts at 100; MISS costs 4 / 6 / 8 / 10
(easy / normal / hard / extreme), PERFECT heals 1.0 / 0.7 / 0.5 / 0.4; HP 0 = game over.
Notes fall 15 % slower on EASY and 10 % / 20 % faster on HARD / EXTREME than the
player's setting. Every per-difficulty number lives in lib/difficulty.ts; chart density
rules live in DIFFICULTY_PARAMS at the top of tools/generate_chart.py and can be
overridden per run with --tune level.key=value.
Hold notes are judged at the head and again at the tail (release too early = MISS).
Windows are deliberately wide because the clock comes from a YouTube embed.
Settings → 타이밍 보정. Enter how many notes the run should collect (8–64, default 16)
and press 보정 시작. The game plays the EASY chart against the video with a wide capture
window and no HP loss; once that many notes are hit it shows the median hit offset and the
new judgement offset (판정 오프셋) for you to apply, re-measure or cancel.
노트 위치 보정 shifts where notes are drawn when they look early/late against the video.
All UI text lives in lib/strings.ts.