Files
fool-cardgame/docs/TECHNICAL.md
T
ftcandClaude Opus 5 c980440856 M0: план разработки, техническая структура, каркас проекта
- docs/PLAN.md — план по этапам, обновляется по мере работы
- docs/TECHNICAL.md — слои, карта папок, контракты, рабочие процессы
- docs/DECISIONS.md — журнал решений, принятых самостоятельно
- разрешение 1080x1920, fit-width (портрет, 4:3..21:9)
- каркас assets/scripts (core / modules / app / ui)
- headless-тесты на vitest + strict typecheck + защита чистоты core
- Rng: детерминированный генератор и перемешивание

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 10:28:49 +03:00

5.1 KiB

Technical structure

How this project is laid out, what each layer is allowed to do, and how to work on it. Companion to ARCHITECTURE.md, which states the intent; this file states the implementation.

  • Engine: Cocos Creator 3.8.8, TypeScript.
  • Targets: Web (mobile browser), Android, iOS. Portrait only.
  • Editor automation: the cocos-code-mode extension — see CODE_MODE_SETUP.md.

Layering

Four layers, with dependencies pointing strictly downward. A layer may import from the layers below it and never from the ones above.

  ui/        Cocos components: scenes, prefabs, views, input, animation
   ↓
  app/       bootstrap, service locator, scene transitions
   ↓
  modules/   engine-aware services: savegame, (later) audio, analytics
   ↓
  core/      pure rules and bots — no `cc` import anywhere

The rule enforced by review and by the test harness: nothing under assets/scripts/core/ may import from cc. It is plain TypeScript, runnable under Node, and that is what makes the rules testable without the engine.

Folder map

assets/
  scenes/
    loader.scene              module init, then → lobby
    lobby.scene               main menu; hosts the match UI
  prefabs/
    card.prefab               one playing card, face or back
    ...
  art/
    cards/                    36 faces + back, atlased
    ui/                       panels, buttons, table surface
  scripts/
    core/                     PURE TS — no engine imports
      cards/                  Suit, Rank, Card, Deck
      rules/                  GameState, actions, events, the reducer
      bot/                    PlayerView projection, BasicBot
      util/                   seeded RNG, shuffle, assertions
    modules/
      save/                   SaveManager, ISaveSection, StatsSection, storage
    app/                      Bootstrap, ServiceLocator, SceneRouter
    ui/
      lobby/                  lobby screen controller
      game/                   match screen: hand, table, deck, animations
      common/                 reusable widgets, safe-area root
tests/                        vitest specs against assets/scripts/core
docs/                         specs, this file, plan, decisions
local/                        scratch art storage; contents get consumed
extensions/cocos-code-mode/   editor tool server

The rules core

A deterministic state machine. The only entry point is a pure reducer:

apply(state: GameState, action: Action): { state: GameState; events: GameEvent[] }
  • GameState is plain data: hands, deck, trump card, table slots, discard, phase, whose turn it is, and the RNG state. It is serialisable, which makes every test a fixture and every bug reproducible from a seed.
  • Action is what a participant wants to do — Attack, Defend, Take, Pass. Legality is decided by the core, never by the caller; legalActions() exists so the UI can grey out impossible taps, not as the source of truth.
  • GameEvent is what happened — CardDealt, CardPlayed, CardBeaten, TableTaken, TableDiscarded, TurnPassed, PlayerOut, GameOver. The view layer animates the event stream; it never inspects GameState directly for anything it is not allowed to see.
  • Randomness comes from a seeded PRNG carried inside the state. Same seed plus same action sequence always reproduces the same match.

Bots

A bot is a function (view: PlayerView) => Action. PlayerView is a projection of GameState containing only legitimately visible information. BasicBot implements the policy in GAMEPLAY.md verbatim.

Savegame

Per ARCHITECTURE.md: SaveManager keeps a registry of ISaveSection implementations. save() enumerates them and builds { [section.key]: section.save() }; load() parses and dispatches each payload back to the matching section. A missing or unparsable section is skipped with a warning rather than failing the whole load, so a bad release cannot brick a save.

Keys are explicit string constants, not class names — release builds minify.

Conventions

  • TypeScript, 4-space indent, PascalCase for types, camelCase for members, _private for backing fields (matching Cocos's own style).
  • One exported class per file, file named after it.
  • Cocos components live only in ui/; they are thin and hold no rules logic.
  • No any in core/. strict is off in the Cocos tsconfig for engine-side convenience, but the test harness type-checks core/ in strict mode.

Workflows

Tests

npm test

Runs vitest over tests/ against assets/scripts/core. No editor required.

Driving the editor

Cocos Creator must be running with this project open. See CODE_MODE_SETUP.md; the port changes on every editor restart, so always read ~/.utcp_config.json.

Scripts and other text assets are written to disk directly and picked up by the editor's asset watcher. Scenes and prefabs are authored through the tools — never by hand-editing the .scene/.prefab JSON.

Builds

Web: web-mobile template. Mobile: ASTC textures per ART.md, PNG for web.