Files
Tiago Valente d091a59cbe CheatSpecter 0.4.0
- Find: text search, grouped search, undo, went up/down by, where to search, before/after compare
- Debug tab: breakpoints, stepping, registers, stack, threads, what code touches, structure compare, pointer re-check
- Engine tab: Unreal, Unity, Godot, GameMaker and C++ class names; hidden settings and switches
- Code cheats with labels, variables, references and shared code; rule builder; script commands
- Cheats kept on by the PS5 without the browser
- Learn section with twelve lessons and an in-page practice game
- Section (master code) community cheats; SHN and MC4 export
- Groups, dropdowns, hotkeys, first-cheat guide, re-find after update, restore everything
- MCP server: 25 tools
- Quick start, wiki, contributor and security guides, changelog
2026-10-10 12:06:50 -07:00
..
2026-10-10 12:06:50 -07:00
2026-10-10 12:06:50 -07:00
2026-10-10 12:06:50 -07:00

Lessons for CheatSpecter's Learn section

This folder is what the Learn page in CheatSpecter shows. The app does not ship with lessons: when someone opens Learn and presses "Load lessons", their browser downloads index.json and then each lesson from this folder on GitHub. Change a file here and everyone gets the new version the next time they open the page.

Lessons are data, never code. A lesson cannot contain HTML, scripts, links or images. The app checks every file it downloads against the format below and refuses the whole file if anything is off, so a typo here means a lesson that will not open. Run the checker before you commit:

node scripts/check-lessons.mjs

It prints what is wrong and where (lessons/find-a-number.json: lesson.steps[2].goal.field: …), or 12 lessons, 74 steps: all fine. The test suite (test/learn.test.mjs) runs the same check, and then has a scripted learner complete every practice step, so a goal that cannot be reached fails the tests.

To try your lessons in the app before they are on GitHub, run npm run demo (or npm run dev): with the demo console running, the app loads this folder from your computer instead.

Files

learn/index.json              the courses, and which lessons are in them, in order
learn/lessons/<id>.json       one lesson; <id> is the lesson's id

index.json

{
  "format": "cheatspecter-lessons",
  "version": 1,
  "edition": "2026-10",
  "courses": [
    {
      "id": "values",
      "title": "Finding and changing values",
      "summary": "One or two sentences shown under the course title.",
      "lessons": [
        { "id": "find-a-number", "title": "Find a number you can see", "summary": "…", "minutes": 8, "practice": true }
      ]
    }
  ]
}

title, summary and minutes must be the same as in the lesson's own file (the list of lessons is drawn from the index alone). practice is true when the lesson has at least one practice step. edition is shown at the bottom of the list; change it when you publish. Ids are lower-case letters, digits and dashes.

A lesson

{
  "format": "cheatspecter-lesson",
  "version": 1,
  "id": "find-a-number",
  "title": "Find a number you can see",
  "summary": "Search for your ammo, change it in the game, search again, and edit what is left.",
  "minutes": 8,
  "games": { "range": { … }, "shop": { … } },
  "steps": [ … ]
}

games holds the practice games the lesson's steps use, by a name of your choosing. steps are shown one at a time, in order.

Text

Wherever a step has text (and in done and explain), this small markup works. Anything else is shown as the characters you typed.

You write You get
a blank line a new paragraph
# Heading on its own a heading
lines starting with - a bulleted list
lines starting with 1. , 2. a numbered list
> note: …, > tip: …, > warning: … a callout
**bold** bold, for the names of buttons and for new words
`code` code, for instructions, addresses and file names

Write for someone who has never done this. Name buttons exactly as the app shows them, and say what the learner will see after each action.

Steps

Every step has a kind and a title.

read: something to read. text.

choice: a multiple-choice question. question, options (2 to 6 strings), answer (the position of the right one, counting from 0), explain (shown once they get it right), and optionally text above the question.

answer: a question answered by typing. question, accept (the answers that count; capitals, spacing and a final period are ignored), explain, optionally text.

practice: the learner does something in a practice game with the real tools.

{
  "kind": "practice",
  "title": "Fire, then narrow down",
  "text": "What to do, step by step.",
  "game": "range",
  "tool": "find",
  "goal": { "check": "narrowed", "label": "Narrow the list down to one match", "field": "player.ammo", "atMost": 1 },
  "hints": ["A nudge.", "A stronger nudge.", "Nearly the answer."],
  "done": "Shown when the goal is reached: what just happened, and why it matters."
}
  • game: which of the lesson's games. Steps that follow each other in the same game carry on in it (the learner's search and cheats are still there), unless a step has "fresh": true, which starts a new game with no cheats.
  • tool: the tab shown when the step opens: find, memory, code or cheats.
  • hints: one to six, revealed one at a time, weakest first.
  • "challenge": true marks a step the learner does alone. Give the goal and no steps. Every practical lesson should end with one, in a game with different numbers from the guided part.

The learner also gets a Show me button. It reaches the goal with the same tools and writes down what it did; you do not script it.

soon: text explaining practice that the app cannot offer yet.

Goals

A goal is what the app checks for. Each has a label: the sentence the learner sees with a circle or a check mark next to it. field means a value in the game, written object.field; action means one of the game's actions.

check Reached when Also needs
narrowed the learner's search results contain the value and are at most atMost long field, atMost
value the value is atLeast, atMost or exactly a number field, is, value
held the value is unchanged after each of times uses of an action in a row (frozen, or its code is switched off) field, action, times
steady a value the game changes by itself has not moved for seconds field, seconds
pressed an action has been used times times action, times
restarted the game has been restarted
updated the game's update has been installed (the game needs "update": true)
caught the debugger has reported the code that writes the value ("Find what writes to this") field
off the code behind the action's first effect is replaced with no-ops action
saved "Your cheats" has a cheat of type value (for a field) or patch (for an action). Add "named": true to require a name other than the automatic one, "grouped": true to require a group, "location": "pointer" to require a pointer path type, and field or action

To ask for several things, use { "check": "all", "of": [ … ] } with two to five goals. They count in order: a goal is only looked at once the ones before it are reached, and what it counts (restarts, uses of an action) is counted from that moment. So "restart, then switch the cheat on again" is restarted followed by off.

Practice games

A practice game is a description; the app builds a small pretend game from it, with real memory to search and real machine code behind every action.

{
  "name": "Specter Range",
  "objects": [
    { "id": "player", "fields": [
      { "id": "ammo", "type": "u32", "value": 30, "offset": 40 },
      { "id": "shots", "type": "u32", "value": 0, "offset": 64 }
    ] }
  ],
  "actions": [
    { "id": "fire", "label": "Fire", "effects": [
      { "field": "player.ammo", "op": "sub", "by": 1, "min": 0, "refill": 30 },
      { "field": "player.shots", "op": "add", "by": 1 }
    ] }
  ],
  "hud": [ { "label": "Ammo", "field": "player.ammo", "show": "number" } ],
  "decoys": [ { "type": "u32", "value": 30, "count": 12 } ],
  "copies": [ { "of": "player.ammo", "count": 3, "follow": "fade" } ],
  "drifting": 0,
  "update": false
}
  • objects (1 to 8) are the things the game keeps in memory. Each field has a type (u8, u16, u32, float, double, or pointer), a starting value, and optionally an offset from the start of the object (a multiple of the type's size; left out, fields follow each other from 16). A pointer has to (another object's id) instead of a value. Objects land somewhere new every time the game starts. One with "static": true lives in the game's own data, at the same place every time: give it a pointer to another object and there is a pointer path to find.
  • actions (up to 8) become buttons. Each effect adds to or subtracts from a u32, float or double field. A subtraction that would go below min sets the value to refill (or stops at min); an addition stops at max. An action with "every": 1000 runs by itself every that many milliseconds and has no button ("hidden": true hides one without a timer). Each effect is its own few bytes of code, which "Find what writes to this" finds and no-ops switch off. Effects that name the same "site" share one piece of code, as "take damage" for the player and for an enemy would; they must do the same thing to the same field of their objects.
  • hud (up to 6) is what the game shows: a number (with digits decimals), a bar (filled at max; the number is not shown, which is the point), or a time (seconds shown as m:ss).
  • decoys put the same number in unrelated places, so a first search finds more than one.
  • copies follow a value for a few changes and then stop, as a game's own copies of a number do; count 3 means narrowing down takes about four rounds.
  • drifting is how many values change on their own, which gives "stayed the same" a job in searches that start from "Unknown".
  • update true gives the game an "Install game update" button that moves its code.

If someone overwrites a game's code with anything other than whole instructions of no-ops, the game "crashes" the next time that code runs, and "Restart game" brings it back.

Changing the format

version is 1. The app refuses files with a higher version and tells the user to update, so new kinds of steps or goals mean a new version number and a new app release first. The types and the checker are in src/lib/learn.ts; the practice game is in src/lib/practice/.