[System] You are a coding assistant for the Ling programming language.

[User] What's the correct top-level structure of a standalone (non-web) Ling program, like a game or graphics demo?

[Assistant]
Real shipped Ling games (LingForFun, soul-symphony-ling) all follow the same three-part shape, top to bottom:

1. `use "relative/path"` imports, one per line, no braces or semicolons, no trailing comma-lists.
2. `fn` function definitions (helpers, entity logic, etc).
3. A single top-level `bind <name> = do { ... }` block that is the actual entry point.

```ling
use "models/ling-3d/index.ling"

fn clamp(v, lo, hi) {
    if v < lo { return lo }
    return v
}

bind _start = do {
    open_window(1280, 800)
    while window_is_open() {
        fill(24, 26, 36)
        present()
    }
}
```

The entry point's `do` body typically does one-time setup first (`open_window`, `set_ambient`, etc.), then drops into a `while window_is_open() { ... present() }` loop that runs once per frame. `use` imports only ever pull in your *own* other `.ling` files — graphics/audio/networking/AI builtins need no import at all (see below).


[System] You are a coding assistant for the Ling programming language.

[User] Where do `use` statements go in a Ling file, and what does the syntax look like?

[Assistant]
`use` statements are always at the very top of the file, before any `fn` definitions or `bind`s, one per line:

```ling
use "game/arena"
use "color"
```

There's no `{ ... }` grouping and no semicolons — just a bare string literal with a relative path (relative to the file doing the `use`, e.g. `"models/ling-3d/index.ling"` or `"ui/winkit"`). Each `use` only pulls in *your own* other `.ling` source files. It is never used to pull in graphics, audio, networking, or AI functionality — those are always-available global builtins, not modules you import.


[System] You are a coding assistant for the Ling programming language.

[User] Do I need a `use` import to call functions like `open_window`, `fill`, `audio_sfx`, or `net_host` in Ling?

[Assistant]
No. Graphics, audio, and networking functions in Ling are global builtins, always available with zero setup. Across both LingForFun and soul-symphony-ling, not a single `.ling` file anywhere writes `use "ling-graphics"` (or any equivalent `use "ling-audio"`, `use "ling-net"`) — the search comes up empty because there's nothing to import. You just call `open_window(...)`, `fill(...)`, `audio_sfx(...)`, `net_host(...)`, etc. directly, from the first line of `bind start = do { ... }` onward.

`use` is reserved entirely for pulling in *your own* other `.ling` files, with a relative path, e.g. `use "game/arena"` or `use "models/ling-3d/index.ling"`.


[System] You are a coding assistant for the Ling programming language.

[User] Show a minimal English-language Ling program that opens a window and runs a basic game loop.

[Assistant]
This is the real shape used in LingForFun's `viewer.ling`:

```ling
use "models/ling-3d/index.ling"

bind modelIdx = 0

fn clamp(v, lo, hi) {
    if v < lo { return lo }
    return v
}

bind _start = do {
    open_window(1280, 800)
    while window_is_open() {
        fill(24, 26, 36)
        present()
    }
}
```

Note the order: `use` import first, then top-level `bind`s / `fn` helpers, then the entry point `bind _start = do { ... }` last, containing setup (`open_window`) followed by the `while window_is_open() { ... present() }` per-frame loop.


[System] You are a coding assistant for the Ling programming language.

[User] Show a Korean-flavored Ling entry point — I've seen code using 바인드, 실행, 동안 instead of English keywords.

[Assistant]
Real example, LingForFun's `생성.灵`:

```ling
use "nuez"
use "ui/winkit"
바인드 start = 실행 {
    동안 창열림() {
        바인드 t = 현재시간()
        블렌드모드(0)
        표시()
    }
}
```

Keyword-for-keyword: `바인드`=`bind`, `실행`=`do`, `동안`=`while`, `창열림`=`window_is_open`, `현재시간`=`current_time`, `표시`=`present`, `블렌드모드`=`set_blend`. Note that `start` itself is kept as the literal English word even though the surrounding keywords are Korean — Ling lets you translate keywords/builtin names per-identifier, it doesn't force a file to be all-one-language. Structurally it's identical to the English version: `use` imports first, then a single `바인드 start = 실행 { ... }` entry point wrapping a `동안 창열림() { ... }` loop.


[System] You are a coding assistant for the Ling programming language.

[User] Show a Thai-flavored Ling entry point using ใช้ and ขณะที่.

[Assistant]
Real example, soul-symphony-ling's `game/main.ling`:

```ling
ใช้ "game/arena"
ใช้ "color"
bind ST_TITLE = 1
bind เริ่ม = do {
    bind args = รับอาร์กิวเมนต์()
    เปิดหน้าต่างเต็มจอ("Soul Symphony Ling")
    audio_volume(0.6)
    ขณะที่ หน้าต่างเปิดอยู่() && ออกเกม == 0 {
        bind t = เวลาปัจจุบัน()
    }
}
```

`ใช้`=`use`, `เริ่ม`= a custom entry-name choice (this file's own translated word for "start"), `รับอาร์กิวเมนต์`=`get_args`, `เปิดหน้าต่างเต็มจอ`=`open_fullscreen`, `ขณะที่`=`while`, `หน้าต่างเปิดอยู่`=`window_is_open`, `เวลาปัจจุบัน`=`current_time`. Note this file mixes English `bind`/`do` keywords with Thai builtin and identifier names in the *same file* — that's legal and is exactly what ships in the real game.


[System] You are a coding assistant for the Ling programming language.

[User] Can I mix English keywords with translated (e.g. Thai or Korean) builtin/identifier names in the same Ling file?

[Assistant] Yes — this is real, shipped behavior, not a hypothetical. `game/main.ling` in soul-symphony-ling keeps `bind` and `do` as literal English keywords while using Thai names for everything else: the entry binding is named `เริ่ม`, and it calls `รับอาร์กิวเมนต์()` (get_args), `เปิดหน้าต่างเต็มจอ(...)` (open_fullscreen), and loops with `ขณะที่ หน้าต่างเปิดอยู่() && ออกเกม == 0 { ... }` (while window_is_open() && exit-flag == 0). Likewise LingForFun's `생성.灵` keeps the identifier `start` as English inside an otherwise Korean-keyword file (`바인드 start = 실행 { ... }`). Translation in Ling is per-token, not an all-or-nothing file setting — you can pick and choose which names to localize.


[System] You are a coding assistant for the Ling programming language.

[User] What does the entry point's `do` body typically do, structurally, in a real Ling game?

[Assistant]
Two phases, in order:

1. **One-time setup** — window/audio initialization that only needs to run once: `open_window(...)` (or `open_fullscreen(...)`), `audio_volume(...)`, `set_ambient(...)`, reading `get_args()`, etc.
2. **The per-frame loop** — `while window_is_open() { ... }`, which reads input, updates game state, draws, and ends each iteration with `present()` to flip the frame buffer.

```ling
bind start = do {
    open_window(1280, 800)          # one-time setup
    audio_volume(0.6)
    while window_is_open() {        # per-frame loop
        bind t = current_time()
        # ...update + draw here...
        present()
    }
}
```

This matches all three real entry points seen across LingForFun and soul-symphony-ling (English `_start`, Korean `바인드 start`, Thai `bind เริ่ม`) — setup lines before the loop, `present()`/`표시()` as the last call inside each loop iteration.


[System] You are a coding assistant for the Ling programming language.

[User] Is the Ling program entry point always named `start`?

[Assistant]
Not literally, no — real shipped code uses a few different names for the top-level `bind ... = do { ... }` block that acts as the entry point:

- LingForFun's `생성.灵` uses `바인드 start = 실행 { ... }` — keeping `start` as a literal English word.
- LingForFun's `viewer.ling` uses `bind _start = do { ... }`.
- soul-symphony-ling's `game/main.ling` uses `bind เริ่ม = do { ... }` — a fully translated custom name.

What's load-bearing is the *shape* — a single top-level `bind NAME = do { ... }` coming after all `use` imports and `fn` definitions, whose body does one-time setup then runs `while window_is_open() { ... present() }` — not any one fixed identifier. In practice, which file (and which binding inside it) actually gets run is what the project's `Ling.toml` `entry` field points at.


[System] You are a coding assistant for the Ling programming language.

[User] What's the per-frame loop condition supposed to look like in a Ling game's entry point?

[Assistant]
The baseline real pattern is just `while window_is_open() { ... }` (Korean: `동안 창열림() { ... }`, Thai: `ขณะที่ หน้าต่างเปิดอยู่() { ... }`). soul-symphony-ling's `game/main.ling` extends that with an explicit exit flag ANDed in:

```ling
ขณะที่ หน้าต่างเปิดอยู่() && ออกเกม == 0 {
    bind t = เวลาปัจจุบัน()
}
```

i.e. `while window_is_open() && exitGame == 0 { ... }` — the loop keeps running as long as the OS window is open *and* nothing in-game has requested an exit yet. That's the idiomatic way to let game logic (e.g. a "quit to desktop" menu option) break out of the loop on its own terms rather than only relying on the OS window-close button.


[System] You are a coding assistant for the Ling programming language.

[User] Write a small standalone Ling graphics demo from scratch following the idiomatic structure.

[Assistant]
```ling
use "color"

fn clampByte(v) {
    if v < 0 { return 0 }
    if v > 255 { return 255 }
    return v
}

bind start = do {
    open_window(960, 540)
    while window_is_open() {
        bind t = current_time()
        fill(20, 20, 28)
        present()
    }
}
```

Order matches every real example: `use` import(s) first, then any helper `fn`s, then exactly one entry-point `bind ... = do { ... }` last, whose body is one-time setup (`open_window`) followed by `while window_is_open() { ...per-frame... present() }`. No import was needed for `open_window`, `fill`, `current_time`, or `present` — they're global graphics builtins.


[System] You are a coding assistant for the Ling programming language.

[User] In `viewer.ling`, why is `use "models/ling-3d/index.ling"` written that way instead of an absolute path or a package name?

[Assistant] Because `use` in Ling resolves *your own* source files by relative path from the file doing the importing — there's no separate package-name/module-registry syntax for local files. `"models/ling-3d/index.ling"` is a straightforward relative filesystem path from `viewer.ling`'s location down into the `models/ling-3d/` folder to its `index.ling`. Same pattern in soul-symphony-ling: `use "game/arena"` and `use "color"` are relative paths into that project's own folders, no braces, no semicolons, one per line at the top of the file. Only local `.ling` modules are referenced this way — builtins (graphics/audio/net/AI) are never `use`d at all.


[System] You are a coding assistant for the Ling programming language.

[User] What's the difference between the Korean example's `동안 창열림() { ... }` and just a fixed-iteration loop — why not a for-loop with a fixed count?

[Assistant] Because a game doesn't know in advance how many frames it will run — it runs until the player closes the window (or, per the Thai example, until an in-game exit flag flips). `동안 창열림() { ... }` is `while window_is_open() { ... }`: it polls the OS/window-system state every iteration and keeps looping exactly as long as that's true. This is the universal real pattern for a Ling game's main loop across all three language flavors seen in shipped code (English `while window_is_open()`, Korean `동안 창열림()`, Thai `ขณะที่ หน้าต่างเปิดอยู่()`) — always an open-ended condition-loop, never a fixed count.


[System] You are a coding assistant for the Ling programming language.

[User] Give the English-keyword equivalents for 바인드, 실행, 동안, 창열림, 현재시간, 표시, and 블렌드모드.

[Assistant]
From LingForFun's real `생성.灵`:

| Korean | English |
|---|---|
| `바인드` | `bind` |
| `실행` | `do` |
| `동안` | `while` |
| `창열림` | `window_is_open` |
| `현재시간` | `current_time` |
| `표시` | `present` |
| `블렌드모드` | `set_blend` |

So `바인드 start = 실행 { 동안 창열림() { 바인드 t = 현재시간() 블렌드모드(0) 표시() } }` reads in English as `bind start = do { while window_is_open() { bind t = current_time() set_blend(0) present() } }` — a one-time-nothing, straight-into-the-loop entry point that sets the blend mode and presents every frame.


[System] You are a coding assistant for the Ling programming language.

[User] Give the English-keyword equivalents for ใช้, เริ่ม, รับอาร์กิวเมนต์, เปิดหน้าต่างเต็มจอ, ขณะที่, หน้าต่างเปิดอยู่, and เวลาปัจจุบัน.

[Assistant]
From soul-symphony-ling's real `game/main.ling`:

| Thai | English |
|---|---|
| `ใช้` | `use` |
| `เริ่ม` | (custom entry-point binding name, this file's own word for "start") |
| `รับอาร์กิวเมนต์` | `get_args` |
| `เปิดหน้าต่างเต็มจอ` | `open_fullscreen` |
| `ขณะที่` | `while` |
| `หน้าต่างเปิดอยู่` | `window_is_open` |
| `เวลาปัจจุบัน` | `current_time` |

Note `bind` and `do` are *not* in this table because that file keeps them as literal English keywords even while translating everything else — confirming that keyword translation in Ling is per-token, not whole-file.


[System] You are a coding assistant for the Ling programming language.

[User] Why does a real Ling entry point call `open_window` or `open_fullscreen` before the `while` loop instead of inside it?

[Assistant] Because it's one-time setup, not per-frame work — creating the window (or audio volume, ambient light, etc.) should happen exactly once, before the loop starts polling `window_is_open()`. Calling it inside the loop would re-create the window (or reset the setting) every single frame, which is both wasteful and wrong. All three real entry points follow this order: setup calls first (`open_window(1280, 800)` in English `viewer.ling`; `เปิดหน้าต่างเต็มจอ("Soul Symphony Ling")` + `audio_volume(0.6)` in Thai `game/main.ling`), *then* `while window_is_open() { ... }` starts.


[System] You are a coding assistant for the Ling programming language.

[User] What's the general rule for ordering `use`, `fn`, and `bind` at the top level of a Ling file?

[Assistant]
`use` imports come first (one per line, relative paths, no braces/semicolons), then `fn` function definitions and any supporting top-level `bind`s (like constants: `bind ST_TITLE = 1`), and finally a single entry-point `bind <name> = do { ... }` block last, which is where execution actually starts. This ordering is consistent across every real entry file examined:

```ling
use "game/arena"          # 1. imports
use "color"

bind ST_TITLE = 1         # 2. constants / fn defs

bind เริ่ม = do {          # 3. entry point, last
    ...
}
```

Graphics/audio/networking builtins never appear in the `use` section since they need no import at all.


[System] You are a coding assistant for the Ling programming language.

[User] Can I store a function in a variable in Ling and then call it, like `bind fn = cardFn` followed by `fn(x)`?

[Assistant]
No — Ling doesn't have first-class function values. `ident(args)` is only resolved for statically-named functions and builtins at that call site; you can't hand a function around as a value and invoke it generically later. A real attempt at this in one of these codebases produced the runtime error `unknown function cardFn` — the interpreter doesn't chase a variable to find a function to call, it only recognizes a literal function name written directly before `(`.

If you need to pick between several behaviors at runtime, use an if/else chain checking a string/tag instead of trying to pass a callback around.


[System] You are a coding assistant for the Ling programming language.

[User] I tried passing a function reference as a callback in Ling and got `unknown function cardFn` — what happened?

[Assistant]
That error is the confirmed, real symptom of trying to use a function as a first-class value in Ling. Something like:

```ling
bind effect = cardFn        # trying to store a function reference
effect(target)               # -> unknown function cardFn
```

doesn't work because Ling only resolves `ident(args)` when `ident` is a function/builtin name written literally at the call site — it does not follow a variable to find a callable. There's no callback/function-pointer mechanism. The idiomatic fix isn't to work around this cleverly; it's to not need it — write a small dedicated function per case (e.g. `applyStrike(target)`, `applyHeal(target)`) and select between them with an if/else chain on a string or numeric tag instead of trying to dispatch through a stored function value.


[System] You are a coding assistant for the Ling programming language.

[User] How do I implement dynamic dispatch in Ling, since it has no function values?

[Assistant]
Use an if/else chain that checks a string or numeric tag and calls a specific, statically-named function in each branch:

```ling
fn applyCardEffect(kind, target) {
    if kind == "strike" { return applyStrike(target) }
    if kind == "heal" { return applyHeal(target) }
    if kind == "shield" { return applyShield(target) }
    return target
}
```

Each `applyStrike`, `applyHeal`, `applyShield` is a small dedicated function, not a value passed around. This is the real idiomatic pattern in both codebases — dispatch by name-checking, not by storing and invoking function references (which fails with `unknown function <name>` since Ling only resolves statically-named calls).


[System] You are a coding assistant for the Ling programming language.

[User] What's the idiomatic Ling replacement for a generic 'apply this callback to a list of items' helper?

[Assistant]
There isn't a generic higher-order helper in idiomatic Ling — because you can't pass the callback in as a value (attempting it fails with an `unknown function` error, since `ident(args)` only resolves statically-named functions). Instead, write one small dedicated function per concrete case, and call the specific one you need directly at each call site:

```ling
fn healAllInList(list) { ... }
fn poisonAllInList(list) { ... }
```

rather than:

```ling
fn applyToAllInList(list, effectFn) {   # will NOT work
    effectFn(list)                       # unknown function <whatever was passed>
}
```

More small, specific functions instead of one generic dispatcher is the real-world convention in both LingForFun and soul-symphony-ling.


[System] You are a coding assistant for the Ling programming language.

[User] Does Ling support passing functions as arguments the way JavaScript or Python does?

[Assistant] No. Ling resolves `ident(args)` only for statically-named functions and builtins right at that call site — there's no function-value type you can pass into another function and invoke generically. Trying to do so (e.g. passing a function reference as a callback parameter and then calling it through that parameter) is a confirmed real failure mode, producing an error like `unknown function cardFn`. Idiomatic Ling code sidesteps this entirely by writing one small dedicated function per case and selecting among them with an if/else chain on a tag/string, rather than by threading callables through parameters.


[System] You are a coding assistant for the Ling programming language.

[User] I want one `runEffect(effectFn, target)` helper that calls whatever function is passed in — is this possible in Ling?

[Assistant]
Not as written — Ling has no first-class function values, so `effectFn` inside `runEffect` would just be an ordinary value (or an unresolved name), and calling it as `effectFn(target)` fails with an `unknown function` error, the same failure mode confirmed in real code with `cardFn`. `ident(args)` only ever resolves a literal, statically-named function or builtin at that call site.

Replace the generic `runEffect(effectFn, target)` with either:

```ling
fn runEffect(kind, target) {
    if kind == "strike" { return runStrike(target) }
    if kind == "heal" { return runHeal(target) }
    return target
}
```

or, simpler and more idiomatic: skip the dispatcher entirely and call `runStrike(target)` / `runHeal(target)` directly wherever you already know which effect you need.


[System] You are a coding assistant for the Ling programming language.

[User] How should I structure card-effect logic in a card game written in Ling, given there's no way to pass functions as values?

[Assistant]
Write one small dedicated function per card effect, and dispatch on a tag with an if/else chain — do not try to store a per-card function reference (e.g. `cardFn`) and call it generically, since that's a confirmed real failure (`unknown function cardFn`):

```ling
fn applyCard(cardKind, target) {
    if cardKind == "fireball" { return applyFireball(target) }
    if cardKind == "heal" { return applyHeal(target) }
    if cardKind == "shield" { return applyShield(target) }
    return target
}

fn applyFireball(target) { ... }
fn applyHeal(target) { ... }
fn applyShield(target) { ... }
```

Each card's effect lives in its own small function; `applyCard` just routes by tag. This is the idiomatic real-world pattern in both game codebases — many small functions, not one generic higher-order dispatcher.


[System] You are a coding assistant for the Ling programming language.

[User] What exactly does 'statically-named function resolution' mean for how `ident(args)` works in Ling?

[Assistant] It means the interpreter decides what `ident(args)` calls purely from the literal text `ident` written at that call site — it looks up a function or builtin with exactly that name at parse/resolve time. It never treats `ident` as "whatever value some variable currently holds" — so even if you write `bind cardFn = someOtherName` and then call `cardFn(x)`, Ling doesn't dereference through the binding to find a function; it looks for a function literally named `cardFn`, and if none exists, you get `unknown function cardFn`. Practically: function names in call position must be real, fixed function/builtin names, not variables holding a function reference.


[System] You are a coding assistant for the Ling programming language.

[User] Is there a `call`-style builtin in Ling for invoking a function by name string, like `call("cardFn", args)`?

[Assistant] Neither LingForFun nor soul-symphony-ling's real code uses one — the confirmed idiomatic pattern in both is simpler: write a dedicated small function per case and select between them with an if/else chain checking a string/tag, rather than building a call-target name as a string and invoking it dynamically. If a project did have a dedicated `call`-style builtin for dynamic dispatch by name, that would be the fallback for truly dynamic cases — but in practice the real shipped code never needed it; one function per case was enough.


[System] You are a coding assistant for the Ling programming language.

[User] Refactor this pseudo-Ling code that tries to pass `cardFn` as a callback into idiomatic Ling: `fn playCard(cardFn, target) { cardFn(target) }`.

[Assistant]
That version fails at runtime with `unknown function cardFn` (or whatever name was actually passed) — Ling only resolves `ident(args)` for a literal, statically-named function at the call site, not a value flowing through a parameter. Idiomatic rewrite — drop the parameter entirely and dispatch by tag inside `playCard`:

```ling
fn playCard(cardKind, target) {
    if cardKind == "strike" { return strikeCard(target) }
    if cardKind == "heal" { return healCard(target) }
    return target
}

fn strikeCard(target) { ... }
fn healCard(target) { ... }
```

Now every function named in a call position (`strikeCard`, `healCard`) is a real, fixed name Ling can resolve — no function value ever needs to travel through a parameter.


[System] You are a coding assistant for the Ling programming language.

[User] Why do real Ling codebases favor many small dedicated functions over one generic higher-order dispatcher function?

[Assistant] Because Ling has no first-class function values — `ident(args)` only resolves statically-named functions and builtins, so there's no way to write a truly generic dispatcher that accepts "any function" and calls it (a real attempt at that produced `unknown function cardFn`). Given that constraint, the natural, idiomatic style that emerged in both LingForFun and soul-symphony-ling is: many small, specifically-named functions (one per case/effect/behavior), selected between with an ordinary if/else chain on a string or numeric tag. It reads more like a switch statement over named handlers than the callback-heavy style common in JS/Python, but it's the pattern that actually works given the language's call-resolution rules.


[System] You are a coding assistant for the Ling programming language.

[User] I set `bind health = 100` at the top level and decrease it inside a function called every frame, but it resets each frame — why?

[Assistant]
Because a function in Ling only sees top-level `bind` globals as a **read-only snapshot taken at load time** — any reassignment you do to a name *inside* a function body is local to that call and is discarded the moment the function returns. There's no shared mutable global state that persists across a function-call boundary. So `health = health - 10` inside a function changes a local copy for the duration of that call only; the outer `bind health` is untouched next frame.

To make it persist, thread it explicitly: pass the current value **in** as a parameter, return the updated value **out**, and let the caller (usually the top-level `bind start = do { ... }` loop) hold the real, persistent `bind` and reassign it each frame:

```ling
bind health = takeDamage(health, 10)
```


[System] You are a coding assistant for the Ling programming language.

[User] How does Ling handle top-level `bind` globals when a function reads them?

[Assistant] A function sees top-level `bind` globals as a read-only snapshot from load time — it can *read* them, but any reassignment made inside the function body is purely local to that single call and vanishes when the function returns. This has been confirmed independently, with the same wording, in both LingForFun and soul-symphony-ling: there is no shared mutable global state across a function-call boundary. Anything that must persist from one call to the next (position, velocity, health, a network connection's status) has to be threaded explicitly — passed in as a parameter and returned back out — rather than relied on as an ambient global that functions can silently update.


[System] You are a coding assistant for the Ling programming language.

[User] What happens if I reassign a `bind` global inside a function body in Ling?

[Assistant]
The reassignment is local to that function call — it does not propagate back out to the top-level binding. Ling functions only see globals as a read-only snapshot taken at load time; writing to that name inside the function body creates/changes a value scoped to the current call, which is discarded as soon as the function returns. So:

```ling
bind score = 0

fn addPoints(n) {
    bind score = score + n   # only changes the LOCAL copy inside addPoints
    return score
}

addPoints(10)
# the top-level `score` is still 0
```

To actually update the outer `score`, the caller must do the reassignment itself using the function's return value: `bind score = addPoints(score, 10)` (with `score` passed in as a parameter too, not read off the global).


[System] You are a coding assistant for the Ling programming language.

[User] How do I persist player position across frames in a Ling game loop?

[Assistant]
Thread it explicitly through the loop instead of relying on a function to mutate a global — Ling functions only see `bind` globals as a read-only snapshot from load time, and any reassignment inside a function body is discarded when that call returns. So position has to be passed in as parameters and returned back out as a value, with the top-level loop's `bind` holding the real, persistent state:

```ling
fn move_player(x, y, vx, vy) {
    bind newX = x + vx
    bind newY = y + vy
    return [newX, newY]
}

bind start = do {
    open_window(1280, 800)
    bind pos = [100, 100]
    bind vx = 2
    bind vy = 0
    while window_is_open() {
        bind pos = move_player(pos[0], pos[1], vx, vy)
        present()
    }
}
```

Every frame, the loop reads `pos[0]`/`pos[1]` out, calls `move_player`, and rebinds `pos` to the function's returned `[newX, newY]` — that's the only place the "real" persistent position lives.


[System] You are a coding assistant for the Ling programming language.

[User] Show the idiomatic Ling pattern for threading mutable state through function calls.

[Assistant]
Pass the current value in as a parameter, compute the new value, and return it out — then have the caller rebind its own `bind` to the result. The canonical real-world example is player movement:

```ling
fn move_player(x, y, vx, vy) {
    bind newX = x + vx
    bind newY = y + vy
    return [newX, newY]
}

bind pos = move_player(pos[0], pos[1], vx, vy)
```

The caller (typically the top-level `bind start = do { ... }` game loop) is where the *actual* persistent state lives, because that's the only place a `bind` reassignment sticks around between iterations. Functions themselves are effectively stateless from one call to the next — they can't rely on globals holding onto changes they make internally.


[System] You are a coding assistant for the Ling programming language.

[User] Why is there no shared mutable global state across function-call boundaries in Ling?

[Assistant] Because a Ling function only sees the program's `bind` globals as a read-only snapshot captured at load time. Any reassignment performed inside the function body is scoped to that single call and is thrown away once the function returns — it never writes back to the outer binding. This behavior has been independently confirmed with matching wording in two separate real codebases (LingForFun and soul-symphony-ling), so it's a core language characteristic to design around, not a bug. The practical consequence: anything that needs to persist frame-to-frame — position, velocity, health, a network connection's state — must be threaded explicitly as parameters in and return values out, with the actual persistent `bind` living at the call site that survives across iterations (usually the top-level game loop).


[System] You are a coding assistant for the Ling programming language.

[User] Write a `move_player` function in Ling that updates x/y position given velocity, in the idiomatic threaded-state style.

[Assistant]
```ling
fn move_player(x, y, vx, vy) {
    bind newX = x + vx
    bind newY = y + vy
    return [newX, newY]
}
```

Called from the loop that owns the actual persistent position:

```ling
bind pos = move_player(pos[0], pos[1], vx, vy)
```

`move_player` never touches a global — it takes the current `x`/`y`/`vx`/`vy` in as plain parameters and returns the new `[newX, newY]` pair. The caller is responsible for storing that result back into its own `bind pos`, since a reassignment inside `move_player` itself would only be local to that call and would be lost on return.


[System] You are a coding assistant for the Ling programming language.

[User] Where should the 'real' persistent `bind` for game state live — inside helper functions or at the top level?

[Assistant] At the top level, in the entry point's `do` block — usually the `bind start = do { ... }` (or equivalent) that runs the `while window_is_open() { ... }` loop. Helper functions like `move_player(x, y, vx, vy)` never hold real persistent state themselves: they only see globals as a read-only snapshot from load time, and any local reassignment inside them is discarded on return. So the pattern is: the loop's `bind pos = ...`, `bind health = ...`, etc. are the single source of truth, and every frame the loop calls out to helper functions passing the current values in and rebinding its own `bind`s to whatever comes back out. Helpers are pure computation, not stateful objects.


[System] You are a coding assistant for the Ling programming language.

[User] I'm networking a Ling game — how do I keep connection state alive between calls to my networking helper functions?

[Assistant] The same way you'd keep any other frame-to-frame state alive: thread it explicitly rather than relying on a helper function to remember it internally. A Ling function only sees `bind` globals as a read-only snapshot from load time, and any reassignment inside it (e.g. updating a `connectionStatus` variable) is local to that call and discarded when it returns — there's no shared mutable global state across a function-call boundary. So keep the actual connection state (status, buffered lines, etc.) in a `bind` owned by the top-level loop, pass the relevant piece into your networking helper as a parameter, and rebind the top-level `bind` to whatever the helper returns, exactly like `bind pos = move_player(pos[0], pos[1], vx, vy)` does for position.


[System] You are a coding assistant for the Ling programming language.

[User] What's wrong with this Ling snippet, assuming it's meant to persist a score increase: `fn addScore() { bind score = score + 10 }` called each frame from the loop?

[Assistant]
`bind score = score + 10` inside `addScore` only creates/updates a *local* binding named `score` scoped to that single call of `addScore` — it reads the outer `score` once (as a read-only snapshot from load time) but its reassignment never propagates back to the caller's `score`, and that local value is discarded the instant `addScore` returns. So calling `addScore()` every frame from the loop has literally no lasting effect; the outer score never changes.

Fix: have `addScore` take the current score in and return the new value, and let the loop do the actual persistent rebinding:

```ling
fn addScore(score, amount) {
    return score + amount
}

bind score = addScore(score, 10)
```


[System] You are a coding assistant for the Ling programming language.

[User] Explain what 'read-only snapshot from load time' means for Ling `bind` globals, and why it matters for game state.

[Assistant] It means that when a function body references a top-level `bind` name, it's seeing the value that name had when the program was loaded (or, practically, an immutable view of it for that call) — not a live, mutable reference it can update for future calls. The function can read that value, but any assignment it makes to that name is scoped to its own call and disappears once the call returns; nothing writes back to the actual top-level binding. This is why per-frame game state — position, velocity, health, a network connection's status — can't just live as a global that helper functions quietly update: it has to be threaded explicitly, passed in as a parameter and returned back out, with the real persistent `bind` staying at the top level (typically inside the entry point's `while window_is_open() { ... }` loop) where reassignment actually sticks.


[System] You are a coding assistant for the Ling programming language.

[User] How are game entities like monsters represented in idiomatic Ling, given the language has no classes?

[Assistant]
Not as objects/structs at all — in both real codebases, an entity is represented as a pure function of (index/seed, level, time) that *returns* a value-tuple (an ordinary list) describing its computed state. There's no persistent object instance; you call the function whenever you need that entity's current stats, and read fields back out of the returned list with `list_get`. For example, a monster-stats function might look like:

```ling
fn getMonsterStats(seed, level) {
    bind species = seed - (seed / 5) * 5
    bind hue = (seed * 37) - ((seed * 37) / 360) * 360
    bind speedMul = 1.0 + level * 0.05
    bind hpMul = 1.0 + level * 0.20
    return [species, hue, speedMul, hpMul]
}
```

Then `list_get(getMonsterStats(seed, level), 0)` gets you `species`, index `1` gets `hue`, and so on. No class, no struct, no object identity — just a deterministic function and a returned tuple.


[System] You are a coding assistant for the Ling programming language.

[User] Write a function that computes monster stats from a seed and level, in idiomatic Ling style, returning species/hue/speed/HP.

[Assistant]
```ling
fn getMonsterStats(seed, level) {
    bind species = seed - (seed / 5) * 5
    bind hue = (seed * 37) - ((seed * 37) / 360) * 360
    bind speedMul = 1.0 + level * 0.05
    bind hpMul = 1.0 + level * 0.20
    return [species, hue, speedMul, hpMul]
}
```

This is the idiomatic entity pattern: a pure function of `(seed, level)` returning a `[species, hue, speedMul, hpMul]` tuple rather than any kind of object/struct instance. Nothing about the monster is stored anywhere — call the function again whenever you need its stats, and pull individual fields back out with `list_get(stats, 0)`, `list_get(stats, 1)`, etc.


[System] You are a coding assistant for the Ling programming language.

[User] How do I read back individual fields from an entity tuple returned by a function in Ling?

[Assistant]
With `list_get`, indexing into the list the entity function returned:

```ling
bind stats = getMonsterStats(seed, level)
bind species = list_get(stats, 0)
bind hue = list_get(stats, 1)
bind speedMul = list_get(stats, 2)
bind hpMul = list_get(stats, 3)
```

Since entities in idiomatic Ling are represented as plain returned lists (not named-field objects), `list_get(list, index)` by position is how you unpack them. Keep the index order consistent with how the entity function builds and documents its return list.


[System] You are a coding assistant for the Ling programming language.

[User] What does it mean that 'entities are pure functions of index/seed/level/time' in Ling game code?

[Assistant] It means an entity — a monster, a projectile, an item — isn't a persistent object with mutable fields; it's computed on demand by a function whose only inputs are things like its spawn seed/index, the current game level, and (for anything animated) the current time. Call the function again with the same inputs and you get the same tuple back — deterministic, no hidden state. This replaces the class/struct-instance model entirely: instead of creating a `Monster` object once and mutating its `.hp` field over time, you call `getMonsterStats(seed, level)` fresh whenever you need current stats, and any time-varying behavior (bobbing, animation phase, etc.) is folded in by also passing `time` as a parameter and using it in the function's math, e.g. `bind bobY = sin(time * 2.0) * 4.0`.


[System] You are a coding assistant for the Ling programming language.

[User] Should I build an object with named fields (like `{species: ..., hue: ...}`) for a game character in Ling?

[Assistant]
No — that's not the idiomatic pattern in real Ling game code, and Ling has no class/struct-as-object convention for entities to begin with. Both LingForFun and soul-symphony-ling represent entities as plain functions returning a positional list (a value-tuple), read back with `list_get` by index, rather than any named-field record:

```ling
fn getMonsterStats(seed, level) {
    ...
    return [species, hue, speedMul, hpMul]   # positional tuple, not a named-field object
}
```

If you want field-like readability, wrap the indices in small accessor functions (e.g. `fn statSpecies(stats) { return list_get(stats, 0) }`) rather than reaching for an object/struct type Ling doesn't idiomatically use here.


[System] You are a coding assistant for the Ling programming language.

[User] Show how to compute a procedurally-generated NPC's attributes without storing any entity state, Ling-style.

[Assistant]
```ling
fn getNpcAttributes(seed, level, time) {
    bind archetype = seed - (seed / 4) * 4
    bind hue = (seed * 53) - ((seed * 53) / 360) * 360
    bind alertness = 0.5 + level * 0.03
    bind bobPhase = time * 1.5
    return [archetype, hue, alertness, bobPhase]
}
```

Nothing is stored — every value in the returned tuple is recomputed from `seed`, `level`, and `time` each time you call it. Read fields back with `list_get(attrs, 0)` for `archetype`, `list_get(attrs, 1)` for `hue`, and so on. This mirrors the real `getMonsterStats(seed, level)` shape but adds `time` as an input for anything that should vary as the game runs, like idle-animation phase.


[System] You are a coding assistant for the Ling programming language.

[User] Why might a Ling entity function take `time` as one of its parameters?

[Assistant] Because entities in idiomatic Ling have no persistent internal state to animate — they're recomputed fresh from their inputs every call. If some part of the entity's appearance or behavior should change continuously (a bob/float animation, a pulsing glow, an attack windup), the only way to express that without stored state is to make it a function of the current `time` value, passed in from the caller (e.g. `current_time()` read in the main loop). So an entity function's signature naturally grows from `(seed, level)` for static stats to `(seed, level, time)` once any part of it needs to move or change moment-to-moment, e.g. `bind bobY = sin(time * 2.0) * 4.0` computed fresh each frame from the current `time`.


[System] You are a coding assistant for the Ling programming language.

[User] What's the return-value convention for a function representing a game entity's computed stats in Ling?

[Assistant] Return an ordinary list (a value-tuple) whose positions carry a fixed, documented meaning — not a named-field object, since Ling has no class/struct-as-object convention for entities. For example `getMonsterStats(seed, level)` returns `[species, hue, speedMul, hpMul]`: index 0 is species, index 1 is hue, index 2 is the speed multiplier, index 3 is the HP multiplier. Callers unpack fields positionally with `list_get(stats, 0)`, `list_get(stats, 1)`, etc. Keep the index order stable and consistent everywhere the tuple is produced and consumed, since there's no field-name safety net.


[System] You are a coding assistant for the Ling programming language.

[User] How do idiomatic Ling games avoid needing structs/classes for hundreds of enemies on screen?

[Assistant] By never instantiating enemy objects at all — each enemy's stats/appearance are computed on the fly by calling a pure stats function with that enemy's `seed`/`index`, the current `level`, and (if animated) `time`, and reading the result back as a list via `list_get`. There's nothing to allocate, store, or garbage-collect per enemy beyond whatever minimal per-instance data (its seed, its current position) the loop is already threading through frame to frame per the state-threading pattern. Since `getMonsterStats(seed, level)` is deterministic and cheap, calling it fresh for every enemy every frame is the idiomatic approach rather than building and maintaining hundreds of persistent struct/object instances — which Ling's language design (no classes, no first-class function values, functions can't hold onto mutable state) doesn't really support anyway.


[System] You are a coding assistant for the Ling programming language.

[User] Extend the monster-stats example: write a similar function for generating a treasure chest's contents.

[Assistant]
```ling
fn getChestContents(seed, level) {
    bind itemType = seed - (seed / 6) * 6
    bind rarity = (seed * 13) - ((seed * 13) / 100) * 100
    bind goldAmount = 10 + level * 5 + rarity
    bind isLocked = seed - (seed / 3) * 3
    return [itemType, rarity, goldAmount, isLocked]
}
```

Same shape as `getMonsterStats(seed, level)` — a pure function of a seed and the current level, returning a `[itemType, rarity, goldAmount, isLocked]` tuple with no stored state anywhere. Unpack with `list_get(getChestContents(seed, level), 2)` for `goldAmount`, etc. Every chest with the same `seed` and `level` always produces the same contents, which is what makes this pattern work without persisting anything.


[System] You are a coding assistant for the Ling programming language.

[User] What is `list_get` used for in the context of entity representation in Ling?

[Assistant]
`list_get` is how you read a field back out of an entity's tuple after calling its stats function — since entities are represented as plain returned lists (no named-field objects), positional access via `list_get(list, index)` is the whole "field access" mechanism:

```ling
bind stats = getMonsterStats(seed, level)
bind speedMul = list_get(stats, 2)
```

Every real entity-representation example follows this two-step shape: call the pure entity function to get a fresh tuple, then `list_get` specific indices out of it for whatever fields you currently need (species, hue, multipliers, etc.).


[System] You are a coding assistant for the Ling programming language.

[User] How do I start a Ling server that other players can connect to?

[Assistant]
Call `net_host(port)` once during setup, then loop, polling for incoming lines with `net_recv_from()`:

```ling
bind start = do {
    bind PORT = 7779
    net_host(PORT)
    while 1 == 1 {
        bind msg = net_recv_from()
        while msg != "" {
            bind parts = split(msg, "|")
            bind cid = parts[0] - 0
            net_send_to(cid, "ok")
            bind msg = net_recv_from()
        }
        sleep_ms(15)
    }
}
```

No `use` import is needed — `net_host`, `net_recv_from`, `net_send_to` are global `ling-net` builtins. This mirrors the real `world_server.ling` shipped in LingForFun (originally written with Korean keywords `바인드`/`동안`).


[System] You are a coding assistant for the Ling programming language.

[User] What does `net_recv_from()` return, and how do I know there's nothing left to process?

[Assistant]
`net_recv_from()` returns a string shaped `"<connection_id>|<line>"` for the next queued message, or an empty string `""` once the queue is drained. So the standard drain-loop pattern is:

```ling
bind msg = net_recv_from()
while msg != "" {
    # ...handle msg...
    bind msg = net_recv_from()
}
```

Keep calling it in a `while msg != ""` loop until you get `""` back, meaning the queue is empty for now — then fall through to the outer loop's `sleep_ms(...)` before polling again.


[System] You are a coding assistant for the Ling programming language.

[User] Do I need to `use` a networking module to call `net_host` or `net_send` in Ling?

[Assistant] No. `net_host`, `net_join`, `net_status`, `net_send`, `net_recv`, `net_send_to`, `net_recv_from`, and `net_close` are all global `ling-net` builtins, available with zero imports — consistent with graphics and audio builtins, which also need no `use`. You just call them directly from wherever your setup or loop code lives, e.g. straight inside `bind start = do { net_host(PORT) ... }`. `use` is reserved for pulling in your own other `.ling` files by relative path, never for builtin subsystems like networking.


[System] You are a coding assistant for the Ling programming language.

[User] How is a connection identified in the messages returned by `net_recv_from()`?

[Assistant]
Each message comes back as a single string, pipe-delimited: `"<connection_id>|<line>"`. Split it apart with `split(msg, "|")`, then convert the id portion (a string) to a number by subtracting 0 from it:

```ling
bind parts = split(msg, "|")
bind cid = parts[0] - 0
```

`cid` is then the numeric connection id you pass to `net_send_to(cid, replyLine)` to reply to that specific client. This is exactly the pattern used in the real `world_server.ling`.


[System] You are a coding assistant for the Ling programming language.

[User] Show a minimal Ling TCP server loop that processes incoming messages, following the real shipped pattern.

[Assistant]
```ling
bind start = do {
    bind PORT = 7779
    net_host(PORT)
    while 1 == 1 {
        bind msg = net_recv_from()
        while msg != "" {
            bind parts = split(msg, "|")
            bind cid = parts[0] - 0
            net_send_to(cid, "ok")
            bind msg = net_recv_from()
        }
        sleep_ms(15)
    }
}
```

This is the real shape of `world_server.ling`: host once with `net_host(PORT)`, then an infinite `while 1 == 1 { ... }` outer loop, an inner `while msg != "" { ... }` drain loop over `net_recv_from()`, and a `sleep_ms(15)` at the bottom of each outer iteration so the server doesn't spin the CPU at 100% while idle.


[System] You are a coding assistant for the Ling programming language.

[User] How does a Ling client connect to a server and know when the connection is ready?

[Assistant]
Call `net_join(ip, port)` to initiate the connection, then poll `net_status()` in a loop until it equals `2` (connected):

```ling
net_join("127.0.0.1", 7779)
while net_status() != 2 {
    sleep_ms(15)
}
# now connected — safe to use net_send / net_recv
net_send("hello")
bind reply = net_recv()
```

Once connected, use `net_send(line)` / `net_recv()` for that single connection (as opposed to the server-side `net_send_to(id, line)` / `net_recv_from()`, which are per-connection-id). Call `net_close()` when the client is done.


[System] You are a coding assistant for the Ling programming language.

[User] What does `net_status()`'s value `2` mean, and how should a client wait for it?

[Assistant]
`2` means the client's connection is established/connected. After calling `net_join(ip, port)`, the connection isn't necessarily ready instantly, so the idiomatic pattern is to poll in a small loop with a short sleep between checks until the status reaches `2`:

```ling
net_join(ip, port)
while net_status() != 2 {
    sleep_ms(15)
}
```

Only after that loop exits should the client start calling `net_send(line)` / `net_recv()`. This mirrors the sleep-and-poll style used elsewhere in real networking code (e.g. the server's `sleep_ms(15)` between drain passes).


[System] You are a coding assistant for the Ling programming language.

[User] Do I need to deduplicate messages coming out of `net_recv_from()` in Ling?

[Assistant] No. `net_recv_from()` drains a true FIFO queue — messages are neither dropped nor redelivered, so once you've read a message out via `net_recv_from()`, it's gone from the queue for good and won't come back around on a later call. You don't need any sequence-number or message-id dedup logic on top of it; just drain the queue each pass with a `while msg != "" { ... net_recv_from() }` loop and trust that every line you get back is a distinct, once-only message.


[System] You are a coding assistant for the Ling programming language.

[User] Can a single Ling process act as both a server and a client of another server at the same time?

[Assistant] In these codebases, no — a process is a host (via `net_host(port)`) *or* a client (via `net_join(ip, port)`), never both. Critically, never call `net_join` to itself, or to another host, from inside its own request-handling loop — this is a documented real gotcha: doing so deadlocks the whole server tier, because the request-handling loop blocks waiting on a join/connect while it's also the thing that's supposed to be servicing incoming requests. If you need a process to relay to another server, that relay logic has to be structured so it isn't blocking the same loop that's draining `net_recv_from()`.


[System] You are a coding assistant for the Ling programming language.

[User] What happens if a server calls `net_join` to itself or another host from inside its own request-handling loop?

[Assistant] It deadlocks the entire server tier — this is a documented real gotcha, not a theoretical concern. The request-handling loop (the one calling `net_recv_from()` and replying with `net_send_to`) has to stay free-running to keep servicing clients; blocking it on a `net_join`/connect call to itself or another host stalls that loop, which stalls everything depending on it. The rule of thumb: a given process is either a host (`net_host`) or a client (`net_join`) — never call `net_join` from within the same loop that's handling `net_host`-side requests.


[System] You are a coding assistant for the Ling programming language.

[User] Walk through this real Korean networking snippet and explain what it does: `바인드 _start = 실행 { 바인드 PORT = 7779 net_host(PORT) 동안 1 == 1 { 바인드 msg = net_recv_from() 동안 msg != "" { 바인드 parts = split(msg, "|") 바인드 cid = parts[0] - 0 net_send_to(cid, "ok") 바인드 msg = net_recv_from() } sleep_ms(15) } }`

[Assistant]
This is LingForFun's real `world_server.ling`, with `바인드`=`bind` and `동안`=`while`. In English:

```ling
bind _start = do {
    bind PORT = 7779
    net_host(PORT)
    while 1 == 1 {
        bind msg = net_recv_from()
        while msg != "" {
            bind parts = split(msg, "|")
            bind cid = parts[0] - 0
            net_send_to(cid, "ok")
            bind msg = net_recv_from()
        }
        sleep_ms(15)
    }
}
```

It: (1) hosts a server on port 7779 once via `net_host`, (2) runs forever with `while 1 == 1`, (3) each outer pass drains the entire incoming-message queue with an inner `while msg != ""` loop, splitting each `"<connection_id>|<line>"` message on `"|"` to recover the connection id (`parts[0] - 0` converts the id string to a number), and replies `"ok"` to that specific client with `net_send_to(cid, "ok")`, and (4) sleeps 15ms once the queue is empty before polling again, so the loop doesn't busy-spin.


[System] You are a coding assistant for the Ling programming language.

[User] What builtin closes a client's connection to a server when it's done, in Ling?

[Assistant] `net_close()`. It pairs with `net_join(ip, port)` on the client side — after you're finished sending/receiving with `net_send(line)` / `net_recv()`, call `net_close()` to end that connection. (The server side doesn't use `net_close` in the same way — it keeps running its `net_host`/`net_recv_from`/`net_send_to` loop to keep serving other clients.)


[System] You are a coding assistant for the Ling programming language.

[User] How do I play a sound effect in Ling — is there a sample-playback function like `play_sound("gong.wav")`?

[Assistant] No — SFX in these real Ling games is procedural/additive synthesis, not sample playback. There's no "load and play an audio file" builtin used for SFX in this style; instead you call `audio_sfx(x, y, z, w, freqHz, amp, decaySec, waveform)` directly, describing an oscillator burst with a position, frequency, amplitude, decay time, and waveform shape. A single call gives you one simple tone; real instrument-like sounds (a gong, a bell, a laser) are built by calling `audio_sfx` *several times* with different frequency ratios, amplitudes, and decay times stacked together, additively synthesizing a richer sound out of simple pieces.


[System] You are a coding assistant for the Ling programming language.

[User] What are the parameters of `audio_sfx`, and what does the fourth parameter `w` mean?

[Assistant]
`audio_sfx(x, y, z, w, freqHz, amp, decaySec, waveform)`:

- `x, y, z` — the 3D world position the sound emits from (for spatialization/panning/falloff).
- `w` — a spatial 4th dimension parameter alongside x/y/z.
- `freqHz` — the oscillator's frequency in Hz.
- `amp` — amplitude/volume of this one call.
- `decaySec` — how many seconds the tone takes to decay/fade out.
- `waveform` — a string naming the oscillator shape: `"sine"`, `"square"`, `"triangle"`, or `"noise"`.

Real usage from soul-symphony-ling's gong instrument: `เสียงเอฟเฟกต์(x, y, z, 1.0, f0*1.00, amp*0.95, 3.4, "sine")` — here `w` is passed as `1.0`.


[System] You are a coding assistant for the Ling programming language.

[User] What waveform strings does `audio_sfx` accept?

[Assistant] Four confirmed real values, passed as the last (string) argument: `"sine"`, `"square"`, `"triangle"`, and `"noise"`. `"noise"` is used for broadband/percussive transients (like a struck-gong's initial strike), while `"sine"` is used for the tonal, sustained partials that follow — e.g. soul-symphony-ling's gong instrument fires one `"noise"` call for the strike and several `"sine"` calls at different frequency ratios for the metallic wash/sustain.


[System] You are a coding assistant for the Ling programming language.

[User] How do I build a rich instrument sound like a gong or bell in Ling, given `audio_sfx` only synthesizes one oscillator per call?

[Assistant] By calling `audio_sfx` multiple times with different frequency ratios, amplitudes, and decay times, and layering the results additively — a single call gives a plain tone, but several calls stacked together with detuned/inharmonic frequency ratios (e.g. `f0*1.0`, `f0*1.48`, `f0*1.97` instead of clean integer harmonics) and a mix of waveforms (a short `"noise"` strike plus long-decaying `"sine"` partials) is what produces a convincingly complex, metallic-sounding instrument. This is exactly how soul-symphony-ling's real gong function (`เล่นฆ้อง` / `เสียงเอฟเฟกต์`) is built — a handful of `audio_sfx` calls stacked, not a sample file.


[System] You are a coding assistant for the Ling programming language.

[User] Show a short 3-call example of stacking `audio_sfx` calls to build a bell-like instrument sound.

[Assistant]
```ling
fn playBell(x, y, z, f0, amp) {
    audio_sfx(x, y, z, 1.0, f0 * 3.5,  amp * 0.5, 0.12, "noise")
    audio_sfx(x, y, z, 1.0, f0 * 1.0,  amp * 0.9, 2.5, "sine")
    audio_sfx(x, y, z, 1.0, f0 * 2.4,  amp * 0.6, 1.8, "sine")
    return 0
}
```

A short, quiet `"noise"` transient for the strike, then two `"sine"` partials at an inharmonic ratio (`1.0` and `2.4`, not a clean integer multiple) with much longer `decaySec` values for the ringing sustain — the same additive-layering idea as the real soul-symphony-ling gong instrument, just with different ratios/decays for a bell-ish rather than gong-ish character.


[System] You are a coding assistant for the Ling programming language.

[User] Explain the real gong instrument function from soul-symphony-ling, `ฟังก์ชัน เล่นฆ้อง`.

[Assistant]
```ling
# เล่นฆ้อง(x,y,z, f0, amp): a struck gong -- broadband noise strike + inharmonic partials
ฟังก์ชัน เล่นฆ้อง(x, y, z, f0, amp) {
    เสียงเอฟเฟกต์(x, y, z, 1.0, f0*4.0,  amp*0.55, 0.20, "noise")
    เสียงเอฟเฟกต์(x, y, z, 1.0, f0*1.00, amp*0.95, 3.4, "sine")
    เสียงเอฟเฟกต์(x, y, z, 1.0, f0*1.48, amp*0.70, 3.0, "sine")
    คืน 0
}
```

`ฟังก์ชัน`=`fn`, `เสียงเอฟเฟกต์`=`audio_sfx`, `คืน`=`return`. `เล่นฆ้อง(x, y, z, f0, amp)` is "play gong" — a struck gong sound built from three layered `audio_sfx` calls: a `"noise"` burst at `f0*4.0` with a very short `0.20`s decay for the percussive strike transient, then two `"sine"` partials — the fundamental (`f0*1.00`) and a detuned overtone (`f0*1.48`, deliberately not a clean harmonic like `1.5`) — both with long `3+` second decays to produce the gong's characteristic metallic wash/ring-out. The header comment explicitly documents the *why* (broadband noise strike + inharmonic partials), which is the idiomatic commenting style in this codebase.


[System] You are a coding assistant for the Ling programming language.

[User] Why does the real gong instrument use a `"noise"` waveform for the strike but `"sine"` waveforms for the sustain?

[Assistant] Because those waveform shapes match what a real struck gong physically sounds like at each stage: the initial strike is a broadband, chaotic transient (hitting metal produces energy across many frequencies at once, which `"noise"` approximates), while the long metallic ring-out afterward is dominated by a handful of resonant tonal partials, which pure `"sine"` oscillators approximate well. The real function fires `เสียงเอฟเฟกต์(x, y, z, 1.0, f0*4.0, amp*0.55, 0.20, "noise")` — high amplitude-ratio frequency, short `0.20`s decay, for the strike — immediately followed by two long-decaying (`3.4`s, `3.0`s) `"sine"` calls at `f0*1.00` and `f0*1.48` for the sustained wash. Mixing a short noise transient with long sine partials is the core trick for making a single synthesized instrument sound percussive *and* tonal at once.


[System] You are a coding assistant for the Ling programming language.

[User] What's the purpose of using inharmonic frequency ratios like `f0*1.48` instead of clean integer multiples in `audio_sfx` calls?

[Assistant] Clean integer-multiple partials (`f0*1.0`, `f0*2.0`, `f0*3.0`, ...) sound like a simple, "pure" tonal instrument — closer to a flute or a plucked string. Real metal objects like gongs and bells don't resonate at clean harmonics; their partials are *inharmonic* — ratios like `1.48` or `1.97` instead of `1.5` or `2.0`. Deliberately detuning the partial ratios away from clean integers is what makes the additive-synthesis result sound metallic and gong-like rather than like a simple chord of pure tones. This is exactly what soul-symphony-ling's real gong function does: its two sustained `"sine"` partials sit at `f0*1.00` and `f0*1.48` — the second one intentionally off a clean `1.5`.


[System] You are a coding assistant for the Ling programming language.

[User] How would I write a `fn` using `audio_sfx` for a short laser-zap SFX?

[Assistant]
```ling
fn playLaserZap(x, y, z, f0, amp) {
    audio_sfx(x, y, z, 1.0, f0 * 1.0, amp * 1.0, 0.08, "square")
    audio_sfx(x, y, z, 1.0, f0 * 2.0, amp * 0.4, 0.06, "square")
    return 0
}
```

A laser zap wants a short, bright, slightly harsh sound, so `"square"` (harmonically richer/harsher than `"sine"`) with very short `decaySec` values (`0.08`, `0.06`) fits better than the long-decaying sine partials used for a gong's metallic sustain. Same additive-layering idea as the real gong instrument — just tuned (waveform, ratios, decay) for a completely different kind of sound.


[System] You are a coding assistant for the Ling programming language.

[User] Does `audio_sfx` require a `use` import in Ling?

[Assistant] No — `audio_sfx` is a global audio builtin, available with no import at all, exactly like the graphics builtins (`open_window`, `fill`, `present`) and networking builtins (`net_host`, `net_send`). Across both real codebases, nothing ever writes a `use "ling-audio"` or similar — you just call `audio_sfx(x, y, z, w, freqHz, amp, decaySec, waveform)` directly wherever you need a sound, including inside a plain `fn` like the real `เล่นฆ้อง` (play-gong) function.


[System] You are a coding assistant for the Ling programming language.

[User] What does the `decaySec` parameter control in `audio_sfx`, and why do the real gong example's values differ so much between calls?

[Assistant] `decaySec` is how many seconds that particular oscillator call takes to decay/fade to silence. In the real gong instrument, the three calls use very different decay times on purpose: the `"noise"` strike transient uses a short `0.20`s decay (a sharp percussive hit shouldn't linger), while the two `"sine"` partials use long `3.4`s and `3.0`s decays (the metallic ring-out of a struck gong sustains for several seconds). Mixing a short-decay transient with long-decay tonal partials in the same additively-stacked sound is exactly what makes the result read as "struck metal that keeps ringing" rather than either a dry click or a pure sustained tone.


[System] You are a coding assistant for the Ling programming language.

[User] What commenting style is idiomatic in real Ling game codebases?

[Assistant]
Comments that explain *why* something is done, not just what the code does — restating the code in prose is not the real style. A good example is the header comment on soul-symphony-ling's gong instrument:

```ling
# เล่นฆ้อง(x,y,z, f0, amp): a struck gong -- broadband noise strike + inharmonic partials
```

That comment doesn't just say "this is a function that plays a gong sound" — it explains the *design reasoning*: broadband noise for the strike, inharmonic partials for the metallic wash. That's the level of intent idiomatic Ling comments aim for — capture the reasoning a reader can't get just by reading the calls themselves.


[System] You are a coding assistant for the Ling programming language.

[User] How long should a Ling source file be before I should split it into modules?

[Assistant] Real shipped files in both LingForFun and soul-symphony-ling generally stay under roughly 500-1000 lines — one file per module or concern (e.g. a dedicated `game/arena.ling`, a dedicated gong/instrument file, a dedicated `world_server.ling` for networking, rather than one giant catch-all file). If a file is growing well past that, that's a signal to split out a concern into its own `.ling` file and pull it in with a relative `use "path/to/file"` at the top of whichever file needs it, keeping the top-level structure (imports, then functions, then a single entry point) intact in each piece.


[System] You are a coding assistant for the Ling programming language.

[User] What does the `entry` field in a project's `Ling.toml` typically point to, and how minimal can that file be?

[Assistant]
It points at the real entry `.ling` file for the project — but that file itself is often extremely thin, sometimes just a single line delegating straight to where the actual game logic lives:

```ling
use "game/main"
```

The substantive setup-and-loop code (the real `bind start = do { ... }` / `bind เริ่ม = do { ... }` with `open_window`/`open_fullscreen`, the `while window_is_open() { ... }` loop, etc.) then lives in the file that got `use`d, e.g. `game/main.ling`. This keeps the literal file `Ling.toml`'s `entry` points at stable and tiny, while the real logic can be organized and split however makes sense underneath it.


[System] You are a coding assistant for the Ling programming language.

[User] Show an idiomatic minimal entry file that just delegates to `game/main.ling`.

[Assistant]
```ling
use "game/main"
```

That's it — a single `use` line. This is a real, idiomatic pattern: the file named by `Ling.toml`'s `entry` field doesn't have to contain any actual logic itself; it can be a one-line delegator that pulls in the real module (here, `game/main.ling`) where the substantive `use` imports, helper `fn`s, and the entry-point `bind ... = do { ... }` setup-and-loop code actually live.


[System] You are a coding assistant for the Ling programming language.

[User] Why would a comment like `# เล่นฆ้อง(x,y,z, f0, amp): a struck gong -- broadband noise strike + inharmonic partials` be considered good idiomatic Ling style?

[Assistant] Because it front-loads two things a reader can't easily infer from the code alone: the function's signature/purpose in one line (`เล่นฆ้อง(x,y,z, f0, amp)`: a struck gong) and, more importantly, the *design intent* behind the specific `audio_sfx` calls that follow — "broadband noise strike + inharmonic partials" tells you *why* the function mixes a `"noise"` call with detuned `"sine"` partials instead of just describing that it calls `audio_sfx` three times. That's the idiomatic bar in this codebase: comments should carry reasoning that would otherwise only live in the original author's head, not restate what's already visible in the function body.


[System] You are a coding assistant for the Ling programming language.

[User] What's the idiomatic module-organization convention across LingForFun and soul-symphony-ling?

[Assistant] Small, single-concern files, wired together with relative `use` imports, entered through a thin top-level entry file. In practice that looks like: a dedicated file per subsystem (an arena/world file, a networking server file, an instrument/audio file, a UI-kit file, etc.), each kept to roughly under 500-1000 lines; a project's real `Ling.toml`-referenced entry file is often just a one-liner like `use "game/main"` delegating to where the substantive logic lives; and within any given file, the strict top-level order is `use` imports first, `fn`/`bind` definitions next, and a single entry-point `bind ... = do { ... }` (when the file is meant to run standalone) last. No project-wide "everything in one file" style shows up in the real shipped code.