“Generate a large cave with 8 rooms, hard difficulty” sounds like a natural-language request. But a text box does not make a tool an AI system. In Unity Level Generator, the request is handled by a deterministic parser: normalize the string, search for known phrases, and copy the extracted fields into a generation profile.

I traced that path in the public Unity-Level-Generator repository at commit 0cbef24. The distinction matters. A small rule-based parser can be predictable and easy to inspect, but it does not understand arbitrary instructions the way a language model might.

COMMAND TRACE / UNITY EDITOR PATTERN-BASED INPUT
01 / PROMPT“Generate a large cave with 8 rooms, hard difficulty”
  1. 02 / NORMALIZELowercase and trimgenerate a large cave with 8 rooms, hard difficulty

    Repeated whitespace is collapsed before matching.

  2. 03 / EXTRACTMatch known fields
    ROOMS 8THEME CaveDIFFICULTY HardSIZE 1.5×

    Regex for counts; phrase tables for the other values.

  3. 04 / PROFILEApply defaults and scaleGenerationProfile.FromIntent(...)

    “Large” scales the requested count and X/Z area.

  4. 05 / GENERATEPass profile to WFCGenerateAsync(profile)

    The generated scene still needs its own validation.

COUNT TRANSFORM8 × 1.5 = 12

The profile target is 12 rooms.

DEFAULT AREA TRANSFORM10 × 1 × 10 → 15 × 1 × 15

Only the X and Z dimensions are scaled.

EVIDENCE BOUNDARYProfile values ≠ rendered result

This diagram traces source mapping; it is not a Unity capture.

The command parser maps a fixed vocabulary to fields. No language-model request is made in this path; the example values are derived from the reviewed source.

A prompt becomes a handful of fields

CommandParser.Parse first lowercases the input and collapses repeated whitespace. It then checks several independent catalogs: a set of action words, a regular expression for room counts, and dictionaries for themes, difficulty, and size. For overlapping phrases, the dictionary keys are tried longest-first. That lets “very hard” win before “hard” and “dark dungeon” before “dark”.

For the example above, the parser can extract a room count of 8, the Cave theme, Hard difficulty, and a size modifier of 1.5 for “large”. It does not build a semantic representation of the sentence. It looks for familiar text patterns and fills optional fields when they match.

The explicit room-count path is deliberately small: after a number and recognized room word match, it clamps the result with Mathf.Clamp(count, 1, 200).

This rule is easy to explain from the source. It also makes the supported grammar visible in code. The room-count expression recognizes a finite set of English and Polish words after the number; a different phrasing may not be interpreted as intended.

Defaults and modifiers change the profile

GenerationProfile.FromIntent supplies defaults for fields the prompt omits: 10 rooms, Medium difficulty, and a Dark Dungeon theme. It then applies a size modifier. In this implementation, “large” scales both the room count and the X/Z dimensions of the generation area.

That means the example’s explicit count of 8 becomes a profile target of 12 rooms, while the default 10 × 1 × 10 area becomes 15 × 1 × 15. Those are values in the requested profile, not a promise that the generator will render exactly 12 compatible rooms in a scene. The mapping is easy to miss from the prompt alone: a user can ask for eight rooms and receive a profile that asks for twelve because “large” is also present.

I would make that relationship explicit in the interface or separate “area size” from “room count”. If an explicit count is intended to be authoritative, the profile conversion should preserve it and let size affect only the layout dimensions. The right choice is a product decision; the important part is making it legible and testing it.

“Confidence” is a heuristic, not model certainty

The parser adds fixed weights when it finds an action, count, difficulty, theme, or size phrase, then averages those weights over the matched categories. The result is stored in a field named Confidence. It is not calibrated against examples or measured as a probability that the interpretation is correct.

Validity has another rule: finding a room count or a theme is enough to mark an intent valid, even when the confidence value is below its threshold. So the number should be read as an internal heuristic, not as an assurance that the request was understood. A useful next step would be table-driven tests that assert both the extracted fields and the validity decision for English and Polish examples.

The matching code also uses substring checks for many keywords rather than word boundaries. That keeps the implementation compact, but can make a fragment inside a longer word count as a match. I have not reproduced a user-visible failure from that edge case; it is a source-derived behavior to include in parser tests.

The editor and generator stay separate

The editor window uses the parser for suggestions and sends the entered command to the facade’s GenerateAsync method. The facade parses it, builds a GenerationProfile, and passes that profile to the configured level generator, which is initialized as the Wave Function Collapse implementation. The parser is therefore one small boundary in a larger pipeline, not the generator itself.

There is no language-model call in this command-to-profile path. The README describes the package as AI-powered and multilingual; the implementation I reviewed supports a finite set of bilingual keywords and maps them to enums and numbers. Calling that a pattern-based command parser gives a reader a more accurate idea of what the tool can accept.

What the repository lets me verify

The repository is configured for Unity editor version 6000.4.6f1 and includes the Unity Test Framework package. I did not find a project test suite or a GitHub Actions workflow in the reviewed tree, so I cannot claim that parser cases or generated layouts pass automated tests. The documentation describes an editor preview and scene-instantiation workflow, but I did not run the project in Unity for this source review.

Before relying on the interface, I would add parser tests for whitespace and case normalization, English and Polish phrases, count limits, missing-field defaults, overlapping keywords, and the interaction between an explicit room count and “large”. Then I would test profile conversion separately from generation. A scene-level test should check connectivity and template compatibility across several seeds; a parser test alone cannot establish that a generated dungeon is playable.

One prompt can silently request a different profile

In this parser, “8 rooms, large” is not an eight-room request by the time it reaches the generator: the size modifier scales the explicit count to 12 and expands the default area to 15 × 1 × 15. That is the key behavior to expose in the editor and lock down with a table-driven test. The interface should show the generated profile before execution, while the parser’s supported English and Polish vocabulary remains documented as a finite grammar—not open-ended AI.

Read the command parser source, the profile conversion and facade, and the editor command path. For another example of making a system’s real boundaries visible, read how the spatial hash’s lookup differs from its build cost.

← All notes