Repository navigation
TrigScript 4.0.0 - #3
Merged
Merged
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TrigScript 4, B5: Local values, sync() and select()
…hat give records
A function kept as a value may now use variables of the function or block it was
written in: they live in an environment (a row of a pool of arrays), one for each
run of the block, reference counted and given back at the program's next wait.
The let of a for is one for each turn, as in JavaScript. IR 24 adds VarDecl.held.
Also: ++n, n--, n = v and n += v used as values; a function may give a record it
makes (return { inc, get }); xs[i] += n lowers to the game's Add action.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…any file, trigscript/ui and trigscript/console Texts: trim, replace, replaceAll, toUpperCase, toLowerCase, lastIndexOf, split, parseInt / Number / isNaN. Arrays of every kind: shift, unshift, splice, at, lastIndexOf, join. A function declared (or a const arrow) at the top of any file is callable from a program with its own values, and usable as a JSX component; components get props as a record and write their lines into the text they stand in. A const array or record that a function it is handed writes is the program's. A function declared in a block sees that block. Standard library: trigscript/ui (Meter, Panel, MenuList, DialogBox, LogLines, choose, say, typewriter, log, clock, thousands) and trigscript/console (Screen: clear, set, get, rect, line, blit, number, present on the minimap; ScreenView in the text lines; sprite). The library may hold .tsx modules. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
It holds a Screen and nothing else; in JavaScript a console is console.log. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Generic classes and functions: a type parameter stands for what it is in the instance or at the call (the checker wrapped to say so), a copy of a generic function for each set of type arguments. A function handed to a task keeps what it uses of the block it was written in, held by the program for the task's slot. A script function that uses the game never runs when the script is built. A field of what a call gives (v.rotate(a).x). timers: every, after, Cooldown, Countdown, Stopwatch. signals: Signal<T> with on, once, off, emit. random: chance, range, dice, pick, weighted, shuffle, and a seeded Random (xorshift). math: lerp, remap, approach, wrap, distances, angles, easing, Vec. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Played: Snake's board did not show. Its pixels are other players' units, and the fog of war hid them; Tetris made Map Revealers over its board, the library did not. Screen.reveal(player) does, and Snake calls it. The view showed twice: each showing is printed, and the one before stayed above until it faded. ui.lines now prints its view and then lines of a space, eleven in all, so the one before goes out of sight. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…; Space, not Enter Played (round 2): it works. The board was a corner of a 96 x 96 minimap beside minerals and terrain: probes/lib/screen-map.mts makes a 64 x 64 map of Space, platform only along the bottom, and Snake's board (30 x 24) fills most of its minimap. The screen's owners were in another order than TEXT_COLORS and the probe's player colours (the snake showed red): now P3, P4, P5, P1, P6, P7, P8. A screen's arrays are a fixed 2,048 cells, not pushed one at a time (the first frame was 712k conditions and actions, now 434k). ui's choose and say take Space (Enter opens the chat in a game of several players) and W / S beside Up / Down. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The minimap draws an Overlord as a dot, and Overlords a tile apart do not fit (the lifted game would not place most of them). It draws a building as its footprint: new Screen(x, y, w, h, "solid") makes each pixel a Pylon, two tiles square, so neighbours join into one block. Needs buildable ground: screen-map.mts --ground. 320 Pylons on the grid in the lifted game, none moved. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TrigScript 4: closures over locals, generics, and the ui, screen, timers, signals, random and math libraries
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A class the program needs to keep by reference - a variable or a field that may be none, an array or a variable of a type several classes fit, a variable given another instance, an array of instances inside an instance, a Map or Set of them - is found by walking the program, and the next walk keeps its instances as rows of the closures' pool, a column for each field (shared by name and kind), the class in the pool's function column. A reference is the row; calls through one that may be of several classes ask the row's class. Only variables a wait may come between their declaration and a use are counted now. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…in the lifted game Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…umns; a new object's constructor under one test Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e given whole; a number or nothing
p = p.add(q), r = { ... }, r = c ? a : b copy the fields; const q = p of a p
given whole is a copy, refused when a field of either is written. A class
whose fields only its constructors write is a value; one changed in place
and given whole goes by reference. number | undefined is a value and a flag:
=== undefined, ??, !, narrowing and truthiness read them; find() and a
Map's get() give one; a field, a row's or an object's, may be one.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A for...of walks a generator at the top of a file, a generator method, and an instance's *[Symbol.iterator](); yield* walks another generator or a list there. A generator or an async function at the top of a file is the script's own function now: called and started with the program's values. sleep(frames(n)) and sleep(seconds(n)) of a number the game holds count down a frame at a time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
stdlib/cutscene.ts: Camera (look, pan with easing, follow, shake), walk, charge, walkAll, line (a talking portrait and the words in the middle of the screen), play (a scene started as a task that a key skips). Found on the way: a class from another file used only inside a function at the top of a file was never declared for the program (its methods were walked in the wrong file); a parameter's default naming a constant of its file was not worked out for those functions; a unit variable the checker narrowed to null was tested as a boolean. probes/game-cutscene.ts passes in the lifted game and the simulator; probes/cutscene.ts is a played probe: a scene, then a list of effects of two classes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…utscene Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n a program A function narrowing its argument with typeof was inlined with both sides of a c ? a : b, and the side its argument does not take read a number variable as a text: text() and textOf() called each other until the stack ran out. The ternary now folds a condition known when the script is built, as if did, and a variable of the program is read as its own kind. Date.now(), new Date(), Math.random() and performance.now() were worked out when the map was built, silently. Inside a program, or a function of the script's a program calls, they are refused with elapsed(), memory.game.frame or random(n) named; at the top of a file they stay the build's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TrigScript 4, B9: references and values, generators finished, and trigscript/cutscene
…d, not 16 Since step 14 the build wrote the state flag two bytes late, so every map built our way made its input carriers in the open and no key, click, sync or typed line reached a program. The first play of Tetris found it; the step 12 probe answers every key again, and game-key-tap and game-events-input pass in the game on the own build. The test checks byte 14 set and byte 16 clear. The plan says what was found. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01En4SHqafb1QFJ4xgbUkAe5
…layers too A run after the first had every @in. array renamed as its own, so only the first program that read keys, clicks or typed lines ever heard them. The prefix rule the events pass uses, a test holding a second program's reads to the first one's cells, and the plan's account of the input probe's play. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01En4SHqafb1QFJ4xgbUkAe5
…e owner while the program sleeps A unit handed to a died handler has the order Die, which the guard every field read had asked to be otherwise: every field read as 0. A read asks now only that the place holds the record. And the tasks' turn comes while the program sleeps, from the last player's list with the current player theirs: a run with tasks sets it to its owner before its wake, every frame, so that what a task shows, the owner sees. Two tests, and the plan's account of the events map's play. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01En4SHqafb1QFJ4xgbUkAe5
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01En4SHqafb1QFJ4xgbUkAe5
The gate before the Python goes (step 16)
README: the language reference against the ledger, and a plainer read
… 4, step 17) Deleted: python/trigscript.py (7,113 lines) and its embedding (scripts/embed-python.mts is scripts/embed-stdlib.mts, the standard library's half), the IR's hand-off to it (serializeIr, packTable, PACK_FROM, IR_VERSION and Program.version, the `graph` statement), the emitter's hybrid mode (emitLoop, emitGraphs, islands, fixed-point calls, the `native` flag — emitBody is the one way through), vendor/eudplib.ts and the service's contribution to the library's build, the MSQC/chatEvent plugin sections of the input plan (and the location it reserved for them, which the own build never needed), the `requires` of plugin-eudplib, tests/python.test.ts, tests/eud-build.test.ts, scripts/drive-eud.mjs, the EUDPLIB=1 path of build-fixture.mts and --eudplib of random-scripts.mts and gate-sweep.mts. The build step now applies to every script with programs: one the emitter does not take is a Problems warning while typing and a failed step on save, with the reason; a map with Magenta's member is refused with the reason too (Magenta's eudplib build rewrites the strings section the payload sits behind; Magenta on TrigScript's layout is the next slice). Found on the way: the editor's compile never passed `emitter: false` (only the tests did), so the own build was handed loops already turned into `graph` statements and refused every script with a plain numeric loop — such maps had gone through eudplib with a warning since step 14. Gone with the hybrid. A list read a bit at a time is laid out a dword a value (stride 1, not the EUDVArray's 18). The debugger, cost and allowlist wording says "the build's own triggers" where it said eudplib's; the Korean follows. README and docs/ir.md updated; the IR carries no version. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01En4SHqafb1QFJ4xgbUkAe5
… plan's account, three tests A line of 24 one-digit numbers (game-lowering's C line) was 290 bytes of template, which the game's 218-byte text line cut short in the lifted game: a number's field is now 4, 8 or 12 bytes by what the value ranges know of it (`fieldWords`), the digits routine's last dwords copied into it; the probe's eight tests pass in the game. The plan's section "The Python goes (2026-10-25)": what went, what the build does now, the editor-compile finding, and the game-*.ts tests gone through — game-tests, key-tap, events-input, local-players (with a guard in scm-sim's differences(), 8852b7c on scm-sim-eud's branch) and lowering pass; game-events' per-player listener (and a refusal in the events pass found with it), game-events-2's on.killed/on.order in the lifted game and game-key-held's late frame are recorded open with what was learned. Three tests that pinned the IR version, the serialised text or eudplib's name follow the deletion. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01En4SHqafb1QFJ4xgbUkAe5
…6-10-25) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01En4SHqafb1QFJ4xgbUkAe5
The Python goes: TrigScript's own build is the only build (step 17)
… contribute their programs through
Magenta on our backend, part A (decided 2026-10-25: TrigScript is the library). `contract.d.ts` publishes the
service: `contribute({ id, label, applies, collect })` brings TrigScript source under a folder of the plugin's own
(`magenta/main.ts`) and names which files run as entries; `check(files, entries)` compiles it against the open map
without building, for the contributor's preflight; `onBuild` is the editor's events. The build step applies when
the script has programs or a contribution applies; the script and the contributions compile together
(`CompileOptions.entries`: files run as entries after the script's, before the test files) and every program goes
into one build. A contribution holds programs only; a failure in one is said in its name. The step 17 refusal of
Magenta's member stays for a Magenta that has not contributed and asks for the update. Plan section "Magenta on our
backend (2026-10-25)": the design, what Magenta renders, what the language still lacks, the parts.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01En4SHqafb1QFJ4xgbUkAe5
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01En4SHqafb1QFJ4xgbUkAe5
…ADME test compiles Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01En4SHqafb1QFJ4xgbUkAe5
TrigScript as the library: the trigscript.build service (Magenta on our backend, part A)
… our backend, part C) bounds(location) is a record of the four edges of a location as cells of the game's location table, read where the location is now and written one edge at a time; the hoisting plan knows them as game cells in the call's, a const's and a destructured form, and the simulator keeps them in its locations beside centerLocation(). A unit gains buildTime, rank, matrix (written: 250 points for the frames), speed (read only), speedUpgrade, hasTarget and inTransport, and hallucinated takes a write. Fourteen ledger rows, all taken; the own payload walked beside the simulator for each. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01En4SHqafb1QFJ4xgbUkAe5
bounds(location) and the unit fields Magenta's rows need (Magenta on our backend, part C)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01En4SHqafb1QFJ4xgbUkAe5
Remastered, Magenta probe 6 (2026-10-25): marines bitten on screen for ten seconds never read as under attack. The attack-notify timer at +0x87 runs only when the "under attack" alert sounds; the last-event bytes (+0x8A timer, +0x8B 174 = was hit) are what BWAPI reads, true for about a second after a hit. The lifted-game view reads the same bytes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01En4SHqafb1QFJ4xgbUkAe5
…an one under a third burns Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01En4SHqafb1QFJ4xgbUkAe5
…mastered ends the game on the last-event bytes Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01En4SHqafb1QFJ4xgbUkAe5
…ten from them (Magenta's put-back row) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01En4SHqafb1QFJ4xgbUkAe5
Plan: Magenta on our backend, parts B and C merged, D built
underAttack said for what it is, buildTime's early finish noted
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01En4SHqafb1QFJ4xgbUkAe5
Merged
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01En4SHqafb1QFJ4xgbUkAe5
TrigScript 4.0.0
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TrigScript 4: the whole of
trigscript-4intomain, released as v4.0.0. The plan with an As built section for every slice isdocs/v4-plan.md; the README's Coming from 3.12 says what changed for a script author.The build is TrigScript's own. Programs are laid out into the saved map by the plugin itself (steps 1–17 of "the way off eudplib"), in under a second, with nothing to install; what the build does not take is a Problems warning and a failed step that saves the rest. The Python lowering and the eudplib hand-off are gone. Every row of the ledger (
ledger/, 845 scripts) is taken, and every probe of the way was played in StarCraft: Remastered.The game as the checker. Tests run in the lifted game beside the simulator (
GameSim), each run's memory accesses are held againstdata/allowlist.jsonline by line, a frame's cost is weighed in Remastered's time, several seated copies are hashed for desyncs, and the debugger reads a program's variables from the game's memory.The language.
async/await, tasks andPromise.*;on.*events; functions as values and closures;try/catch/throw;Local<T>andsync();fixedandMath; the game's tables andmemory; per-player programs; sounds, pictures and videos imported into the map; the standard library (math, random, timers, signals, ui, cutscene, fog, screen, music); the build's own input (keys, clicks, the mouse, typed lines);bounds(location)and the unit fields Magenta's rows need.For other plugins: the
trigscript.buildservice; Magenta 0.12 builds its rows through it.After the merge: CI commits
dist/onmain,v4.0.0is tagged on that commit, scm-js pins it (and drops the eudplib plugin from its defaults), Magenta 0.12.0 is tagged.🤖 Generated with Claude Code
https://claude.ai/code/session_01En4SHqafb1QFJ4xgbUkAe5