尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗A minigolf puzzle where you don't aim. You build the geometry that makes every shot go in.
Built for phones first (touch controls, portrait layout) but it also runs on desktop. You can install it as a PWA, and it works offline after the first visit.
Most minigolf games are about aiming and luck. GeoGolf is closer to Euclidea: a construction puzzle.
You get a ball, a hole and a few mirrors shaped like conic sections (ellipses, arcs, parabolas, hyperbolas). You change their shape by dragging touch handles such as foci, vertices, size and arc ends. When you press Sprawdź ("Check"), the game fires 8 balls at once, each in a different direction (from stage 1 on; the warm-up stage uses a single ball). The level counts only if all eight reach the hole.
One lucky shot can't pass that test, but a correct construction always does. To solve a level you have to use the reflective properties of conics. An ellipse with one focus on the ball and the other on the hole sends every ball into the hole. A parabola turns a fan of shots into a parallel beam. A hyperbola redirects rays aimed at one focus toward the other. Later levels chain these into cascades, where one mirror's focus is the next mirror's source.
Every path from one focus of an ellipse to the other via the curve has the same length (2a), and balls move at a constant speed. So the eight balls also arrive at the same instant. Nothing is faked: the convergence in the animation is the geometry itself.
27 levels in 4 stages, each stage adding one mechanic:
| Stage | Levels | What you learn |
|---|---|---|
| 0 | 3 | Billiards with a flat mirror (one ball, one direction) |
| 1 | 8 | Ellipses: foci, size invariance, obstacles that narrow the valid sizes |
| 2 | 8 | Elliptical arcs and cascades: one mirror's focus feeds the next |
| 3 | 8 | Parabolas and hyperbolas in two-mirror "optical systems" |
The first level of each new mechanic opens with a one-sentence rule card. Its small diagrams are traced by the real engine. The card states the rule, and the levels make you work out how to apply it.
Open the menu, switch to Community („Społeczność") and tap + New level („+ Nowy poziom"). Place mirrors and obstacles, lock the handles the player must not grab, pick the shot direction, then tap Play („Zagraj") and solve your own level. Only then does Share („Udostępnij") appear: the whole level, including your winning setup as proof, is packed into the link itself (…/GeoGolf/#poziom=…), so no server is involved. Whoever opens the link gets the level only if that proof still holds — the solution must win and the starting position must not.
Adding a level to the community catalog (maintainers): paste the code after #poziom= into src/levels/community.ts together with the author's name and run npm test. The catalog test decodes every entry and replays the proof; CI runs the same tests before every deploy, so a broken entry never reaches the site.
The game is a small exact ray tracer for conic sections. There is no physics engine.
Ax² + Bxy + Cy² + Dx + Ey + F = 0. The type is never stored as a field. It is computed from the discriminant B² − 4AC, and a line is simply the case A = B = C = 0. So walls, mirrors and obstacles all go through the same code path: src/core/conic.ts.P + t·d into the form gives a quadratic in t. It is solved with the numerically stable form q = −½(b + sign(b)·√Δ), t₁ = q/a, t₂ = c/q, which avoids cancellation on very thin ellipses. There is a separate linear branch for a ≈ 0 (degenerate curves, or rays parallel to an asymptote), and an ε-threshold so a ball sitting on a mirror after a bounce doesn't hit it again at t ≈ 0: src/core/intersect.ts.(2Ax + By + D, Bx + 2Cy + E), and the reflection is d′ = d − 2(d·n̂)n̂. Three lines of code work for every curve type: src/core/reflect.ts.src/core/piece.ts, src/core/frame.ts.Why no game engine? A physics engine simulates rigid bodies within tolerances, but this game needs the exact intersection of a ray with a curve. A focus that is slightly off must make balls miss, or the puzzle teaches something false. Most of the work with an engine would go into fighting it. The entire geometric core is about 400 lines of TypeScript with no dependencies.
2a, and the reflected ray must aim at the other focus;src/core imports nothing outside itself, and another test bans shadowBlur, which is slow on phones (the glow is drawn as two strokes instead).core/ (pure geometry, runs in Node) → levels/ (levels are data, not code) → render/ → ui/. Beside them, share/ (the link format and its proof) and editor/ (the editor model, built on share/) sit on core/ and levels/ and also use the pure handle math from ui/handles.ts (the editor also reuses the pure curve polyline from render/shapes.ts); neither touches the DOM./ and at /GeoGolf/.master (.github/workflows/deploy.yml).I (Michał Plata) built GeoGolf with an AI-agent workflow in Claude Code. I designed the game, the progression and every level, and made the architecture calls: the single quadratic form, no engine, levels as data. For each stage I wrote or approved a design spec and an implementation plan. Agents then implemented them test-first and kept decision logs of every choice they made on their own, so I could review it and overrule it if needed. Those documents are all in docs/superpowers/ (in Polish): 8 specs, 8 plans and 5 decision logs.
Requires Node.js 20.19+ or 22.12+ (CI uses 22).
npm install
npm run dev # dev server with hot reload
npm test # full test suite (also builds the bundle for the size-budget test)
npm run build # type-check + production build into dist/
npx vite preview # serve the production build
To check one level's stored solution from the command line: npx vite-node scripts/sprawdz-poziom.ts <level-id>.
From the design spec, not yet implemented:
The game's interface is in Polish. Code comments and design documents are in Polish too.
src/core/trace.ts, src/core/verify.ts.