# SilkWard

> SilkWard is an offline puzzle game that resolves 36 levels plus 6 hidden levels on a node-and-edge board through entirely deterministic moves. A single TypeScript core feeds the web (PWA) and mobile (Expo) clients at once; level difficulty is measured by the minimum move count the solver-cli tool finds via BFS. It is playable today at silkward.com.

- Role: Designer & Developer
- Class: Older / Hobby Projects
- Status: Ongoing
- Started: 2026-09-23
- Technologies: TypeScript, Next.js, React, Expo, React Native, Vitest
- Skills: Game Design, Puzzle Design, Deterministic Systems, Offline-First Architecture, Monorepo Architecture, TypeScript
- Website: https://silkward.com
- Source: https://muhammetsafak.com/portfolio/silkward/
- Language: en-US
- Author: Muhammet Şafak

---
SilkWard fills a gap I'd long felt in turn-based puzzles: few rules, zero chance, the feeling of producing the outcome by thinking it through. On a node-and-edge graph, every step the player takes triggers the enemies to advance by the same deterministic rule; if a level is lost, the cause is never a bad roll of the dice but the move itself. The 36 levels plus 6 hidden levels span three acts.

The rules engine is written in pure TypeScript with zero dependencies; it knows neither the DOM nor React Native. That purity lets the web client (a Next.js-based PWA) and the mobile client (Expo) share the same behavior without writing it twice — the rules engine and the solver live in a shared core package, while level data lives in a separate data package. Level difficulty rests on measurement, not guesswork: the solver-cli tool finds each level's minimum move count via BFS, and a verification command re-checks that number on every change. Determinism is protected not by a comment but by a constraint in the build chain: the core package is forbidden from accessing a random number generator or the system clock.

The first load caches the game's shell; from that point on, gameplay makes no network requests. The only exception is sound: each sound file is downloaded once, the first time it plays, and written to persistent cache. This constraint is enforced in code: `fetch` usage is blocked by lint rules, and `XMLHttpRequest` usage by a separate source-scanning test. SilkWard is playable today at silkward.com; it receives no new development, only security and compatibility fixes.
