Commit graph

1098 commits

Author SHA1 Message Date
86644e6533 packages: the registry text a game fills is keys (Maroon Lake's phase 26.4) - ThingKind.name, GearKind blurb/howto/names, HintCard's words, JobDef title/text/how, NpcLine and NpcChoice text, WeatherKind.name are @Text Key fields (a compiled row that leaves one out takes its derived key, the English is the game's en.po); what a package hands back as text is the key's marked text, "" for none; NpcName.name, NpcChoice.line and SettingDef.text are not text and lose @Text; ludic.i18n's tr/trf/trn/key_text say @alloc_ok (tr is a cast); the packages' tests with key literals (built, not run); changes/text-keys-data.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 00:29:03 +03:00
86146782f7 Merge commit '9f8aec3' into lang/foundations (R8: the syntax vocabulary from the parser, grammars and LSP word lists generated from it, the LSP's outline/hover/definition fixed, 47 docs/language pages); reseeded, bootstrap-cfree fixpoint holds
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 00:04:52 +03:00
ed19fb5ce4 Merge commit '11447b8' into lang/foundations 2026-09-30 00:02:48 +03:00
9f8aec3bc1 Merge lang/i18nkeys (27024de) into lang/syntax: the vocabulary gains the text keys - the Key type, @TextKey (a registry's), the k"..." and kn"..." literals - and @Text's doc; docs/language pages for Key and @TextKey; ludic-dev syntax rewrote the grammars; reseeded, bootstrap-cfree fixpoint holds
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 00:02:48 +03:00
4ccbc12b48 Merge commit '27024de' into lang/foundations 2026-09-30 00:00:28 +03:00
86c46c629b changes: syntax-vocabulary (ludic syntax, ludic-dev syntax, the language server's outline and attribute arguments)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:59:47 +03:00
e2528c1b10 docs/language: a page for every keyword and attribute the vocabulary has
Keywords: module uses friend export internal numbers unsafe mut port bind action
reducer registry of as from def open alias component prop view (structure),
shows lasts then loads (scenes), system (ecs), dispatch (control), true false
null (operators). Attributes: @Ref @OneOf @Range @Unit @Asset @Color, @Node /
@Clip / @Material, @Tint @Derived, @Text / @Multiline, @Key, @AppendOnly /
@ByKey, @PerMap / @Chunked, @frame @max, @owns / @creates / @releases,
@deterministic @alloc_ok. Each is in tools/docgen/inventory.json; every fence
that is not marked skip parses (ludicc --fmt). annot-clearcolor's token loses its
quotes, which no reader strips.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:59:47 +03:00
eb2d6106af ludic-lsp: every declaration by its own kind, every field a child, attribute arguments resolve
documentSymbol named `export property X` and `export registry` a function called
"property" / "registry": `export`, `unsafe` and leading @attributes are now a
lead-in to the declaration after them, which keeps its doc comment and is marked
exported. A record's field default was skipped with padv, which crosses lines, so
a property showed only its first field; a member now ends at a comma, the brace
or its line, past a fn type's parameters and a generic's arguments, and an
attribute's arguments are skipped rather than read as fields.

New symbols: state, event (and cancellable), action and port as records (struct,
event, event, interface) with their members; registry (with its record, for
go-to-type, and its line as detail); enum and its members; component and view
with props, state, fields, functions and events; reducer, named "S on A"; a
module-level let as a constant; def and bind bodies, module / friend / numbers
lines read past. A member of a component is not a name for the whole unit.

Hover and definition on an attribute's argument: @Node(model) / @Clip / @Material
to the field of the record it is written in, @Ref(Kits) to the registry (as any
top-level name), and hover on the attribute shows its docs/language page. A
fn-typed or generic field's type is shown whole. lsp_test (test-lsp) holds all of
it on a module file with each kind of declaration.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:59:40 +03:00
2ad6edaae3 ludic syntax, and ludic-dev syntax: every grammar written from the compiler's vocabulary and checked against it
`ludic syntax [--json] [-o FILE]` prints what `ludicc --emit-syntax` does (a line
per entry, or the JSON). `ludic-dev syntax` writes, between "ludic-dev syntax:
begin" / "end" lines, the keyword, type, phase and attribute tables of
ludic_syntax.h, LudicVocabulary's sets (JetBrains), ludic-mode.el's lists and the
language server's word tests (is_keyword_word and the rest; is_contextual_word is
every word the parser does not reserve, and every declaring or modifying one),
and every TextMate pattern marked "comment": "ludic-dev syntax: <group>" (shared
and the VS Code copy). The grammars gain module uses port bind action reducer
dispatch registry def open component prop view alias friend unsafe numbers of as
from mut system; import and extern colour as declarations; the phase clause
knows Overlay; the bitwise pattern matches | and ^ on their own again.

`ludic-dev syntax --check` - and check-vocabulary, whose old parser comparison it
replaces, and the regression suite (syntax_cases, one line per file) - fails when
a written list is behind, when a grammar lacks a keyword, type or phase, when
docs/language has no page for a keyword, type, phase or attribute, or when the
parser (a scan of selfhost/frontend: is_id / text == words, a == / ann ==
attributes) tests a word or reads an attribute vocab.ludic lacks, or the reverse.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:59:30 +03:00
73f7d0b7a3 ludicc --emit-syntax: the language's vocabulary as one table beside the parser
selfhost/frontend/vocab.ludic holds every keyword with its role (declaration,
modifier, statement, operator, constant), every declaration's form, the built-in
types and phases, every attribute with what it goes on, its arguments and a
one-line doc, the operators and the literal forms; `ludicc --emit-syntax` prints
it as JSON ("syntax_version": 1) and exits before reading any program. The
parser dispatches on words where it meets them, so the table is held to it from
the emitter's side: a keyword's "reserved" is is_reserved_word's answer, a phase
must pass is_phase_name and a field attribute listed as read must pass
at_field_known, or the emitter refuses to print. Reseeded (both seeds assemble;
bootstrap-cfree: out.ll == seed.ll).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:59:02 +03:00
27024de00e ludic-dev test: the deps case expects english_left (26.2) after owned_leaks
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:57:56 +03:00
11447b8650 ludic.i18n: tr / trf / trn take the compiler's Key (k"...", kn"..." for trn), built from string(k); keys_test with key literals
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:56:05 +03:00
cdaeb33e12 Merge commit '9f9ac4a' into lang/foundations (26.2 follow-up: a Key in a template hole refused, trn only with kn"", tr/trf refuse one); reseeded, bootstrap-cfree fixpoint holds
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:48:35 +03:00
9f9ac4a7ce compiler: text keys' follow-up (Master's rulings) - a Key in a template literal's hole is an error (the parser marks each hole's string(), TPL_HOLE; write trf(k"...", ...)), trn takes only a plural key kn"..." and tr / trf refuse one (with or without en.po), and a program with no lang line (a package test) uses key literals unchecked and silently - the warning stays for a lang line whose en.po is missing; rejected/i18n_keys gains key_hole (2) and key_rules (3), key_missing's plural moves to trn; LANGUAGE.md and the changeset say so; reseeded, bootstrap-cfree fixpoint holds
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:46:48 +03:00
e3788c0a43 Merge commit '66b8e51' into lang/foundations (phase 26.2: Key, k""/kn"", derived @Text keys, the en.po checks, english_left, the schema's lang section); reseeded, bootstrap-cfree fixpoint holds
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:41:54 +03:00
66b8e51026 docs: LANGUAGE.md's Text keys (Key, k"..." / kn"...", the lang line, derived @Text keys and @TextKey, the checks, the schema's "lang"), the lang manifest key in SHIPPING.md, and the changeset
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:38:03 +03:00
f9808e31ec examples: text keys - lang/i18n (k"" and kn"" keys, == on them, a @Text Key field's derived key, @TextKey, a component's t('key', ...) and its one line of English left, en.po with a plural and descriptions, tr.po missing, fuzzy and extra) and rejected/i18n_keys (a key en.po lacks, a plural key without msgid_plural, a Key / string mix-up, a derived key en.po lacks, a template's missing t() key, hole counts and an undescribed split); their cases in ludic-dev test (added, not run)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:38:03 +03:00
4988adb170 compiler: a Key reaches a template as its marked text (a component's or a view's Key field, for t(expr)), and a derived key's message names it as one; reseeded, bootstrap-cfree fixpoint holds
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:38:03 +03:00
cc1ea0f4ae compiler: text keys (phase 26.2) - k"pause.resume" / kn"catch.count" of the builtin type Key (not a string, and no string one; == compares), its run-time value the key after a marker byte (1, or 2 for a plural); package.ludic's lang "assets/lang" en and a gettext .po reader; every key literal checked against en.po (a kn"" one wants a msgid_plural), trf / trn and a template's t('key', ...) against the English's holes, a component's template words and a @Text row's English as "English left" (warnings, english_left in ludic deps), a @Text Key field a compiled row leaves out filled with its derived key <registry>.<row>.<field> (or @TextKey's prefix; maps.<map>.<table>.<row>.<field> for a @PerMap row, checked), one English under several undescribed keys warned at en.po's line; the schema's "lang" (keys and their sites, unused, undescribed, split, and every other language's missing / fuzzy / extra); k"" in .lres data, @PerMap rows included (lres_key); ludic-fmt keeps a key literal whole; reseeded, bootstrap-cfree fixpoint holds
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:33:52 +03:00
12e2816480 Merge commit '92530c5' into lang/foundations 2026-09-29 23:21:08 +03:00
92530c5db7 render3d: gpu_tex_read_all and gpu_tex_write_all flush the frame first - the read-back is a submit of its own and took the image before the draws that fill it (the sky bake's BRDF table was all zeros at one width in three)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:18:05 +03:00
2fd01d0c9f Merge commit 'f0096ae' into lang/foundations 2026-09-29 23:17:27 +03:00
f0096aec87 ludic.i18n: keys (phase 26.1) - en.po as the base, tr/trf/trn marked strings made into text by L, keyed plurals, the fallback to English then the key ([[key]] loud in a dev build), the English form beside it
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:16:12 +03:00
b5b3edc6ec ludic.ui: t(key, holes...) in a template - the key marked (byte 1, a marked key kept as it is) and each hole's value after a byte 31, the text the translator decodes at draw time; joined through the text memo, so nothing is made while it reads the same (phase 26)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:16:05 +03:00
82c652ca31 ludic.ui: an override's path is compared normalised, and an absolute path matches the relative one it ends with - a lab build registers its components as lab/../src/ui/..., so the studio's src/ui/... (or absolute) path matched nothing and the override changed nothing; nothing is normalised while no override stands; examples/library/ui_override_up registers under a .. path as the lab does
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:00:12 +03:00
b3076597e5 Merge commit '78c261c' into lang/foundations 2026-09-29 22:55:32 +03:00
31dcc389a2 ludic.ui: ui_mounted(out) - the classes of the components the last frame showed, in tree order and each once, into the caller's list - and ui_model_of(cls), the first mounted instance's model read in place; examples/library/ui_mounted
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 22:51:33 +03:00
78c261c625 ludic.session: ply_rest_least, the party's rest for the clock (the valley's selftest57 down into the packages): the roster's freed slot reused and ply_leave_all, the nearest player alone, and ludic.shop's week of demand leaving the shared Random stream untouched
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 22:51:01 +03:00
5107d501f5 Merge commit 'aad3f8c' into lang/foundations 2026-09-29 22:49:24 +03:00
aad3f8ca27 ludic.ui: ui_override(path, text), ui_override_clear(path | "") and ui_overridden(path) - a template's or a stylesheet's text given from outside, its component shown again with its state kept and its own text brought back when let go; lib_text answers a copy of the override, and the dev poll leaves an overridden component alone; examples/library/ui_override
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 22:48:48 +03:00
5bc2342174 ludic.devlink: the interface's verbs (ui_screen, ui_model, ui_tree, ui_override) through a DevlinkUi port
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 22:48:34 +03:00
9f07fc8a62 render3d: heightgen's plain and SMOOTH variants compiled (61 programs) - a smoothed or noise-only terrain had no height field on Vulkan; run-time defines as pure functions (program_defs.ludic) and manifest_test holds every program the source can ask for, literal or computed, to the manifest
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 22:30:35 +03:00
a8ccd34559 Merge commit 'cebb78c' into lang/foundations 2026-09-29 22:26:47 +03:00
ef8bf09210 ludic.base: bake_maps refuses a first input without {map} (it would test one path for every map: all or none); bake_expand says a {map} row is expanded only with a key from bake_maps
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 22:23:44 +03:00
2161f28766 ludic.base: bake_expand(inputs, map) and bake_maps(first_input) beside bake_inputs_hash - {map} put, globs expanded in whole-path byte order with dot-names out - so a bake's runner and the check expand a row one way; tests/baked_expand_test
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 22:22:05 +03:00
cebb78c2c3 render3d: gd_fill tests a deflated tile's top bit as written, (b & 0x80000000) != 0, now that the compiler emits the literal (lang/hex-literal, reseeded) - the b < 0 stand-in goes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 22:20:20 +03:00
edc94e49e8 Merge commit 'c3fc896' into lang/foundations 2026-09-29 22:15:58 +03:00
03ecffbf52 Merge commit 'f864f94' into lang/foundations (@Asset(kind, map[, optional]) checked under every map's directory; ludic build --check reads the maps only for the package's entry)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 22:15:46 +03:00
f864f94207 ludic build --check reads the maps only for the package's entry - a partial program (a unit test, a molecule, a bake's runner) lacks the game's constants and cannot judge them; --maps reads them anyway, --no-maps never; ludicc unchanged
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 22:14:53 +03:00
af90a1a334 @Asset(kind, map): a path under each map's directory - ludicc --check looks for it in every map (a @PerMap row's in its own, a game-wide row's in all), unless @Asset(kind, map, optional); the schema marks it scope map; reseeded
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 22:13:14 +03:00
c3fc896dea render3d: a renderer that cannot draw says so and stops - LUDIC_HOME's leading ~ expanded (an unexpanded one left a run without shaders, logging 27 missing variants and drawing on), the SPIR-V manifest ends with E <count> and a cut or miscounted one is refused, and every such failure is a fault: r3d_open / r3d_load_step fail on it, r3d_fault() / r3d_fault_exit(code) for the game; tests/manifest_test
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 22:12:39 +03:00
9cc67fee74 Merge commit '55def86' into lang/foundations 2026-09-29 22:09:59 +03:00
847048825a Merge commit '37338cb' into lang/foundations (itoa of INT_MIN: a 2^31 hex literal in 32-bit arithmetic kept its value); reseeded, bootstrap-cfree fixpoint holds
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 22:09:09 +03:00
55def863d3 ludic.lab: 16-bit PNGs (lab_png_write16_from), so a test can write a height map render3d reads back as R16
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 22:08:22 +03:00
0a6485ca71 selfhost: the seed regenerated from the merged compiler (deps roots + chunked keys) - the merge commit 2c800ea took chunkkeys' seed and the reseed stayed in the working tree
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 22:07:45 +03:00
aac58ec6fa ui-preview: hold <id or key> <pseudo> - hover, active, focus, focus-visible, checked or disabled held on from the next frame on top of the real input, by the element's key (so through model and load), let go with "" or reset; ludic.ui's held.ludic keeps them and the matcher asks it first; protocol-v1.md and smoke.txt
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 22:04:20 +03:00
37338cb0f7 compiler: the most negative int is emitted as itself - itoa took its digits off -v, which overflows back to itself, so 0x80000000 in an int was written as a bare "-" (invalid IR); digits now come off v as it is, and the buffer holds a long's 20
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 22:00:49 +03:00
3d5aaa6f6e Merge commit '4db972f' into lang/foundations 2026-09-29 21:57:20 +03:00
2c800ea84d Merge commit 'ec49207' into lang/foundations (deps: roots out of the reach ratchet); the seed regenerated from the merged compiler, bootstrap-cfree fixpoint holds
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 21:56:57 +03:00
4db972f4c8 render3d: ground densities as LGD2 - empty tiles free, one-value tiles a word, deflated tiles, quantized
The first cut (LGD1) stored every tile of every layer raw, scale channel and all: 288 MB a map, which
made Maroon's pack 803 MB. LGD2 keeps a tile index per layer (8 bytes a tile, read whole at the map's
load): 0 all zero, 1 one value in the word, else an offset and a length, the top bit set when the bake
deflated it (inflated into the tile cache with the runtime's z_inflate, a reused buffer; nothing per
frame beyond the cache). A layer keeps its scale only where it varies, the density 6 bits and the scale
4 (the same integer arithmetic as the bake). The bake is maroon-lake's tools/bake/ground_density.py;
the dev copy here writes the same format stored. Maroon 23.2 MB, Lamar 17.2 MB.

The deflated flag is tested as a negative length: `b & 0x80000000` compiled to broken IR (an i32
`and` with a bare `-`), a compiler fault to fix separately.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 21:55:28 +03:00