---
title: "Can a game creature's AI be a paragraph of English?"
description: "Eight meadow creatures whose brains are a paragraph of text. Edit a sentence and a simulated System One model changes what each one does next."
published: 2026-10-21
updated: 2026-10-21
canonical: https://protrailblazer.com/posts/jev-plain-english-creature-brains/
tags: [typesafe, jev, system-one, game-design, game-ai, behavior-trees, demo, developer-tools]
---

# Can a game creature's AI be a paragraph of English?

**Answer:** With a System One model, the creature's brain is a short personality text that travels inside the state on every decision tick. The model reads that text alongside hunger, fear and what is nearby, then answers a Choice question over a fixed list of behaviors and a Choice over which nearby thing to target. Editing one sentence changes how the creature lives, with no behavior tree to rewire.

The interactive below is a small meadow with eight creatures in it: four grazers, three scouts and a predator. Each one's brain is the paragraph of English in the personality box, and nothing else about it is scripted. Tap a creature (or use the buttons under the meadow) to select it, then edit its text or tap a snippet chip and watch its next decisions change. The decision log, the inspector and the cost meter update as each answer lands.

*Interactive demo: [open the jev plain english creature brains demo](https://protrailblazer.com/demos/jev-plain-english-creature-brains/)*

## What you're seeing

Grazers are white circles, scouts are triangles, and the predator is the black diamond. The map is fixed: two grass patches, a pond, a thicket, a rocky ridge, a berry bush and a shiny object. A 60 second clock runs dawn, day, dusk and night, and the meadow darkens at night. A small red dot over a creature means its request is in flight. A red ring flashes when an answer lands, and the selected creature wears a dashed red ring with a line to whatever it is targeting.

The personality editor shows the selected creature's brain text. Under it, **What the mock picked up** lists the words this demo can actually read, grayed when their clause is switched off right now. A dashed token is a condition such as "at dusk", and a black token is a negation such as "avoids". The decision log keeps the last eight decisions across the whole meadow in the form `id: action -> target (p, conf)`. The inspector shows the selected creature's last request and its three answers: the action bars, the target bars with a live option count, and the urgency dial, then a line saying what code did with them.

A few things to try:

- **Wait for dusk with g1 selected.** Its text says "Loves the pond at dusk", and the grazers walk to the pond together. Outside dusk the same clause is grayed out and they graze.
- **Tap the obsessed with water chip on a grazer.** In a 40 second test run, a grazer with that sentence appended chose drink on 99 of 100 decisions.
- **Make one grazer social and another a loner.** With the social chip, a grazer followed a friend on 52 of 99 decisions. With the loner chip, it never followed at all.
- **Tap cowardly on a scout.** The default scout never hid in a 40 second run. With the cowardly sentence added, it hid on 20 of 100 decisions.
- **Turn on Stress: 200 ids.** Every target question jumps to 201 options, each request roughly 2.5 times larger, and the hourly cost doubles.
- **Watch for a question mark over a creature.** That is a decision whose confidence fell under 0.3, so the creature pauses and looks around instead of committing.

## What goes into each call?

Jev is a System One model: it reads state and answers typed questions instead of writing text. The [game director sim](https://protrailblazer.com/posts/jev-game-director/) sends numeric telemetry. This one puts prose inside the state as well. Every 400 ms each creature sends its needs, what it can see, and its personality text in one JSON object. This is a real state captured from g1 at dusk:

```
{
  "self": {
    "id": "g1",
    "species": "grazer",
    "hunger": 0.32,
    "energy": 0.78,
    "fear": 0,
    "zone": "grass",
    "time_of_day": "dusk",
    "weather": "clear"
  },
  "nearby": [
    {
      "id": "grass_a",
      "kind": "grass",
      "distance": 0,
      "heading": "SW",
      "last_seen_action": null
    },
    {
      "id": "g2",
      "kind": "grazer",
      "distance": 23,
      "heading": "S",
      "last_seen_action": "drink"
    },
    {
      "id": "s3",
      "kind": "scout",
      "distance": 108,
      "heading": "S",
      "last_seen_action": "wander"
    },
    {
      "id": "pond",
      "kind": "pond",
      "distance": 170,
      "heading": "S",
      "last_seen_action": null
    },
    {
      "id": "bush_1",
      "kind": "berry_bush",
      "distance": 177,
      "heading": "E",
      "last_seen_action": null
    },
    {
      "id": "s1",
      "kind": "scout",
      "distance": 188,
      "heading": "E",
      "last_seen_action": "wander"
    },
    {
      "id": "ridge",
      "kind": "ridge",
      "distance": 192,
      "heading": "SE",
      "last_seen_action": null
    },
    {
      "id": "thicket",
      "kind": "thicket",
      "distance": 294,
      "heading": "E",
      "last_seen_action": null
    },
    {
      "id": "grass_b",
      "kind": "grass",
      "distance": 305,
      "heading": "SE",
      "last_seen_action": null
    }
  ],
  "personality": "Calm herbivore. Loves the pond at dusk. Panics near the predator but calms fast. Follows the nearest friend when unsure."
}
```

The `nearby` list is built by code from whatever the creature can perceive, sorted by distance and capped at 12. Three questions go with it. The action question is a Choice over ten behaviors the designer wrote, the target question is a Choice over the ids in `nearby` plus `none` (10 options on this tick), and urgency is a three-level Score. Trimmed, they look like this:

```
{
  "action": {
    "type": "choice",
    "instructions": "What should this creature do next?",
    "criteria": {
      "graze": "Eat. Grass for grazers, grass or berries for scouts. When hungry and food is close.",
      "drink": "Walk to the pond edge and drink. Restores a little energy.",
      "flee": "Run directly away from a threat. When a predator or a challenger is close.",
      "...": "seven more behaviors"
    }
  },
  "target": {
    "type": "choice",
    "instructions": "Which nearby thing is the action about?",
    "criteria": {
      "grass_a": null,
      "g2": null,
      "pond": null,
      "...": "one entry per nearby id",
      "none": "Nothing nearby, or the action needs no target."
    }
  },
  "urgency": {
    "type": "score",
    "instructions": "How urgently should it act?",
    "criteria": [
      "no rush, can be interrupted",
      "soon",
      "right now, survival"
    ]
  }
}
```

On that tick g1 was not very hungry (0.32), afraid of nothing, and standing in grass, and its text says it loves the pond at dusk. The answer put 0.66 on drink and 0.19 on graze, with a confidence of 0.53, and 0.89 on the pond as the target. Urgency came back at 0.14 of 2, so it walked there slowly. The request was 598 input tokens.

## How does the creature act on the answer?

The model never moves anything. It names a behavior and a target, and hand-written code does the rest. This is the loop the demo runs:

```
every 400 ms, per creature, staggered:                 // never blocks the frame loop
    state = { self: needs_and_zone(), nearby: visible(12), personality: text }
    send({ state, model: "jev-latest", questions: { action, target, urgency } })

on answer(a):                                          // lands 70 to 500 ms later
    if a.action.confidence < 0.3:
        pause_and_look_around()                        // too flat to commit
        log("unsure, looks around")
    else:
        routine = ROUTINES[a.action.choice]            // hand-written steering code
        target  = resolve(a.target.choice, routine)    // code checks the target fits
        speed   = 0.6 + 0.4 * a.urgency.score          // 0.6x to 1.4x
        routine.run(target, speed)
```

`resolve` is the quiet safety net. Drink needs the pond, hide needs the thicket, and graze needs grass or the berry bush. If the target answer does not fit the routine, code swaps in the nearest thing that does, and the log says so ("code swapped shiny_1"). Each creature has at most one decision in flight: if the previous answer has not landed when the next tick is due, the tick waits.

## Behavior trees versus a paragraph of English

A behavior tree is a hand-built flowchart of conditions and actions. A grazer's tree checks "predator within 80 px" before "hunger above 0.6" before "a friend nearby", and every quirk of personality is another branch, another threshold, and another chance for two branches to fight over the same tick. Giving one grazer a love of the pond at dusk means finding the right node and wiring a new one.

Here the quirk is a sentence. The model weighs it against the numbers in the same call, so "Loves the pond at dusk" competes with hunger, fear and distance instead of overriding them. A grazer that is starving at dusk still grazes, and one that sees the predator still runs. That weighing is the part a tree makes you write by hand. The cost is that a sentence is less exact than a branch: you shape a tendency, not a rule. Anything that must always happen belongs in code, which is why the confidence floor and the target check are not in the text.

## Why the designer still owns the behavior list

The personality text can only shift which of the ten behaviors happens and toward what. It cannot invent an eleventh. Each behavior id maps to a routine somebody wrote: a steering vector, a speed, an exit condition. Drink walks to the edge of the pond and never into it, because the routine says so. Hide heads for the thicket, and the predator cannot see a creature inside it because the code that builds the predator's state leaves it out. The answer is structured output by construction, so there is nothing to parse and nothing off the list to catch. [Constrained decoding](https://protrailblazer.com/posts/constrained-decoding-json/) gets an LLM to a similar guarantee by masking tokens; a closed Choice gets there by never generating text at all.

That line is what makes prose brains safe to hand to players or modders. Text controls the choice, code controls the consequences, and a typo in a personality can at worst produce an odd but legal creature. The [gate guard sim](https://protrailblazer.com/posts/jev-npc-gate-guard/) applies the same closed-list idea to dialogue, where the output surface is 40 scripted lines.

## What does cardinality mean, and where does 255 bite?

Cardinality is the number of options a Choice question carries. The action question always has ten. The target question is rebuilt every tick from what the creature can see, so its count moves as creatures wander: the inspector shows it live, and it never goes above 13 (twelve ids plus none) in the normal meadow. TypeSafe's docs put the Choice limit at 255 options, with a slower two-stage path above that.

The stress toggle pads every target question to 201 options with fake pebble ids. That still fits under the ceiling, but each request grows from about 600 to about 1,470 tokens, the mock answers at the slow end of the latency range (420 to 500 ms), and the measured call rate slips from about 20 to about 17.5 calls a second because more ticks wait on a request still in flight. A real game hits this with crowds, inventories and item catalogs. The fix is the same as in the demo: filter in code first, and send the model the dozen things that matter.

## What do eight creatures at 2.5 decisions a second cost?

Eight creatures deciding every 400 ms is 20 calls a second, or 72,000 an hour. In test runs the meadow measured 19 to 20 calls a second at about 600 input tokens each, most of it the ten behavior descriptions. Output is free, so at $0.042 per million input tokens the meter reads about $1.70 to $1.95 per hour for one meadow. With stress on, it reads about $3.90.

That is fine for one player and a real line item for a thousand, which is the number the meter's last row shows. Per-entity calls scale with entities times players, so the levers matter: tick idle or distant creatures less often, send shorter behavior descriptions, and cap the nearby list. Staggering the ticks does not change the bill, but it spreads the calls evenly instead of firing eight at once.

> **info:** Nothing in the demo calls Jev, which is in early access. Every answer comes from a local mock. Action logits start from the numbers in the state: hunger raises graze, fear raises flee and hide, low energy raises rest, and a predator within 80 px raises flee for grazers and approach or challenge for the predator. The personality text then adds or subtracts per action and per target kind, using a fixed vocabulary of about 50 words and phrases read clause by clause. Text outside that vocabulary has no effect. That is a limit of this mock, not of a System One model, which reads the whole sentence. Everything goes through a softmax at temperature 0.8 with jitter. Confidence is 1 minus normalized entropy, an approximation of TypeSafe's unpublished formula. Latency is drawn uniformly from 70 to 500 ms, and token counts are the JSON length divided by 4. The request and response shapes, the 255 option limit, the latency range and the price come from the TypeSafe docs.

## Frequently asked questions

### How does AI work in simulation games?

Each simulated character runs a loop: sense the world, decide, act. Classic games write the decide step as state machines, behavior trees or utility scores. The pattern in this demo keeps sensing and acting in code and hands the decision to a model: the character's needs, surroundings and personality go out as state, and a behavior and a target come back as probabilities. Hand-written routines then do the moving.

### What is a behavior tree in games?

A behavior tree is a hierarchy of conditions and actions that a game walks every tick to pick what a character does, such as "if a predator is close, flee, otherwise if hungry, graze". It is predictable and easy to debug, but every new quirk is a new branch, and personality ends up spread across thresholds in many nodes.

### Can you write game AI in natural language?

You can write the personality in natural language and keep the behaviors in code. A System One model reads the text together with the numeric state and answers a closed Choice over behaviors the designer wrote, so the English changes which behavior wins without ever producing one that doesn't exist. The routines, the safety checks and the confidence floor stay in code.

### Why not let a chat model control the creatures?

A chat model writes free text, takes seconds to stream it, and the game still has to parse that text into an action. At 20 decisions a second that is too slow and too loose. A typed Choice answer comes back as a probability over known ids in 70 to 500 ms, with nothing to parse and only input billed.

### What happens when the model is unsure what a creature should do?

The confidence value says so. In the demo, an action confidence under 0.3 makes the creature pause and look around for one tick instead of committing, and the log records it. Contradictory text (a lazy creature that is also a hunter) tends to flatten the distribution and trigger it more often, which is useful feedback for whoever wrote the text.

## Key takeaways

- A personality can live in the state as prose. The model weighs that sentence against hunger, fear and distance in the same call, so text shapes tendencies instead of overriding the numbers.
- Keep the behavior list and the routines in code. Text can only change which of the designer's behaviors wins and toward what, so a bad sentence produces an odd creature, never an illegal one.
- Build Choice options at runtime from what the entity can see, and filter before you send. Cardinality drives request size, latency and cost long before the 255 option limit.
- Per-entity calls multiply fast. Twenty calls a second at about 600 tokens is about $1.90 an hour for one meadow, so tick rates and description length are cost decisions.
- Use confidence as a floor. A flat distribution is the model saying it can't choose, and pausing for one tick is honest behavior for a creature that is unsure.
