Files
tis/src/app/create/[template]/manual/page.tsx
T
ogrechkoandClaude Sonnet 5 a61ef772db Add a 4th template: classic Snake
New templateType "snake" alongside quiz/clicker/maze — additive, not a
redesign, so it's wired through every existing per-template
enumeration point (schema, types unions, scene factory, builder
dispatch on create/edit/AI-review pages, template icon maps) following
the pattern each already established.

games.templateType is a plain SQLite text column with a TypeScript-
only enum (no SQL DDL behind it) — confirmed via drizzle-kit generate
that adding "snake" produces zero migration, same as every in-place
template redesign this session.

Bounded arena (no maze-style wall authoring — keeps the builder trivial:
width/height/startLength/targetLength/wrapAround, nothing else).
Movement is a self-rescheduling delayedCall loop rather than a fixed
interval, since the step interval itself shrinks as the snake grows;
speed curve sanity-checked standalone before wiring it in. Discrete
per-cell snapping (not tweened, unlike the maze's glide) — that's the
authentic blocky Snake feel, not a shortcut. Standard collision rule:
the tail cell is excluded from the self-collision check unless this
step eats food, since the tail is vacating that cell.

Progress resumes the exact live state (body/direction/food/score) —
Snake has no natural level-boundary checkpoint the way the other three
templates do, so unlike their coarse-grained resume this restores
precisely.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QcXH24ky6zjk2UyK5oZUPH
2026-08-01 03:49:26 +00:00

31 lines
1.5 KiB
TypeScript

import { redirect, notFound } from "next/navigation";
import { getCurrentSession } from "@/lib/auth/session";
import { TEMPLATE_TYPES, TEMPLATE_LABELS, type TemplateType } from "@/lib/games/types";
import { QuizBuilder } from "@/components/builders/quiz-builder";
import { ClickerBuilder } from "@/components/builders/clicker-builder";
import { MazeBuilder } from "@/components/builders/maze-builder";
import { SnakeBuilder } from "@/components/builders/snake-builder";
export default async function ManualCreatePage({ params }: { params: Promise<{ template: string }> }) {
const { template } = await params;
if (!TEMPLATE_TYPES.includes(template as TemplateType)) notFound();
const templateType = template as TemplateType;
const session = await getCurrentSession();
if (!session) redirect("/login");
return (
<div className="mx-auto w-full max-w-2xl flex-1 px-4 py-8 sm:px-6">
<h1 className="mb-1 font-display text-2xl font-bold tracking-tight">
Новая игра — {TEMPLATE_LABELS[templateType]}
</h1>
<p className="mb-6 text-sm text-text-muted">Сохранится как черновик — опубликуете, когда будете готовы.</p>
{templateType === "quiz" && <QuizBuilder mode="create" />}
{templateType === "clicker" && <ClickerBuilder mode="create" />}
{templateType === "maze" && <MazeBuilder mode="create" />}
{templateType === "snake" && <SnakeBuilder mode="create" />}
</div>
);
}