Commit graph

16 commits

Author SHA1 Message Date
aca263642d feat(cli): install in one command, and call the CLI ludic
Getting started meant cloning the repository, bootstrapping a compiler and
learning a task runner called `x`. That is a contributor's workflow handed to
everyone who wants to try the language.

Installing is now one command:

    curl -fsSL https://workshopsoft.pages.workshopsoft.io/ludic/install.sh | sh

install.sh puts a complete toolchain — compiler, CLI, engine runtime, bundled
ludic.* packages, formatter, language server — in ~/.ludic and adds it to PATH.
Prebuilt artifacts are checksum-verified; where a platform has none, or the
release predates this layout, it bootstraps from the compiler's own IR seed with
clang. The docs site publishes the script beside the pages that quote it, so the
page and the script can never come from different releases.

`x` becomes `ludic`, and the surface splits by audience. A user of the language
sees `new`, `run`, `build`, `test`, `add`, `fmt`, `lsp`, `doctor`, `upgrade`;
`ludic new` scaffolds a project that builds and plays as it stands. Everything
the toolchain repo needs moved under `ludic dev` — build, test, reseed,
bootstrap-cfree, docs-gen, release — unchanged apart from the namespace. Those
tasks read arguments one position further along, so dispatch_dev sets a shift
and commands use arg_n()/arg_total() rather than each knowing its own depth.

Release artifacts become complete install roots (bin/ beside runtime/, packages/
and VERSION) rather than bare binaries, which is what the installer unpacks.
`ludic dev test` asserts the whole shape: it stages an install, puts it on PATH
with no LUDIC_HOME, and runs new -> build -> test through it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 22:01:52 +03:00
c9ee303b69 docs: rewrite the README for someone meeting the language
All checks were successful
bootstrap / cfree-fixpoint (push) Successful in 22s
ci / build-and-test (push) Successful in 2m51s
commit-lint / conventional-commits (push) Successful in 1s
The README opened with three restatements of "no C", then a limitations table,
then a repo-layout map, and closed with Chrono Rift's keybindings — P2/Mage
`I`/`K` select, `J` confirm — which is a game manual, not a language README. It
never showed the language itself.

It now leads with what Ludic is, a compiling code sample, how to build, what the
language offers, and an honest status. The layout table is contributor material
and CONTRIBUTING already covers that ground.

Two things were not merely stylistic:

- Nine links pointed at wiki pages that no longer exist.
- "Language at a glance" advertised `system` with `reads`/`writes`, plus
  `requires`/`ensures`. None of those are keywords — the grammar has `handler`,
  and `System.*` is a namespace. That bullet described a vocabulary retired
  several releases ago.

The sample is verified to compile, every internal link resolves, and every
command named is one `x help` actually offers.

Also makes commit-lint survive a force-push: it linted `event.before..sha`
without checking that `before` still resolves, so rewriting or gc'ing that
commit failed the job with "Invalid revision range" on a push whose messages
were all valid.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 14:25:07 +03:00
4b81b55849 fix(docs): make the documented bootstrap work on a fresh clone
bin/ is gitignored and not checked in, so the first command in README.md,
COMPILING.md, CONTRIBUTING.md, tools/x/main.ludic and on the site —

    clang selfhost/ludicc.seed.ll -o bin/ludicc && ...

failed on a clean checkout with `ld: open() failed, errno=2 for 'bin/ludicc'`.
Verified against a fresh clone. Every copy now leads with `mkdir -p bin`, which
is what the CI workflows had been doing all along.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 01:48:01 +03:00
583783449a docs: correct stale references across LANGUAGE, README, COMPILING, CONTRIBUTING
- LANGUAGE.md: real diagnostic format, list literals, Font.load / Ui.*
  (no `reg`/`set_reg`, no `/Handler/Library` typo), `extern function`,
  existing example links, Input.key(); builtins table trimmed to what exists
- COMPILING.md: pipeline names selfhost/ (not compiler/*.c), `program`
  instead of game/module, all thirteen win_* entry points by group
- README.md: the window seam is not "five" functions
- CONTRIBUTING.md: docs are checked with `x docs-gen` / `x docs-check`
- docs/language: kw-ui and fn-ui_build use the namespaced API;
  @ClearColor documents constant expressions; examples/README lists
  operators.ludic

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-05 01:12:26 +03:00
b2a6a45a56 docs: 0.2 -> 0.3 migration guide
Comprehensive migration guide for the v0.3.0 release: non-breaking upgrade,
the windowed quit-key + input auto-drive behaviour changes, the draw_sprite
deprecation, and adoption recipes for the package manager, controllers, Tiled
maps, and the #75-#89 engine/language features. Linked from the README.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-02 08:37:13 +03:00
2c44bae496 feat(pkg): package manager — fetch + MVS resolve + namespace registration (#63)
All checks were successful
bootstrap / cfree-fixpoint (push) Successful in 17s
ci / build-and-test (push) Successful in 1m33s
commit-lint / conventional-commits (push) Successful in 2s
docs / build-and-deploy (push) Successful in 25s
Implements the v1 direction decided in the RFC as a set of `x` subcommands
plus a small, contained compiler change.

  * URL-as-identity, no registry — a dependency is named by its git import
    path and a `git tag vX.Y.Z` publishes a version.
  * Minimum Version Selection — a `require` is a minimum; the resolver picks
    the greatest required minimum per module, then the reachable closure at
    those versions. Deterministic, no SAT solver (tools/x/pkg.ludic).
  * Content-addressed global store + per-project links — packages live once in
    ~/.ludic/store keyed by a content hash; each project links them under
    ludic_modules/. package.ludic (manifest) + package.lock.ludic (lock).
  * Namespace registration for source packages via a module-root import
    fallback in the compiler: do_import resolves a non-local, non-absolute
    import under $LUDIC_MODULES (default ludic_modules/), so a fetched
    package's Ludic compiles into the consumer the way the built-in stdlib
    does. Collisions and missing prebuilt targets are hard errors.

Commands: x add / x get / x update / x verify / x vendor. New hermetic suite
`x test-pkg` (stands up throwaway git repos, offline) is gated inside `x test`.

Existing programs compile byte-for-byte identically (the import fallback only
fires when the local path is absent); the C-free bootstrap fixpoint holds and
the seed is regenerated. Full suite: 87 passed, package suite: 12 passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-01 07:08:12 +03:00
c040fff8c8 docs: move design/roadmap docs to the wiki, trim the repo root
All checks were successful
bootstrap / cfree-fixpoint (push) Successful in 12s
ci / build-and-test (push) Successful in 50s
commit-lint / conventional-commits (push) Successful in 3s
The repository root carried 11 large Markdown files (~330 KB); most were
long-lived design records rather than things a newcomer needs on first
contact, which buried the README and mixed "how to use Ludic" with "how we
decided to build it."

Move the design/roadmap docs to the Forgejo wiki (now enabled and
populated): Events, Networking, Scenes, Lifecycle, Mobile and
Syntax-redesign design records, the Bootstrap deep-dive and the Luanti
roadmap, under a Home index + sidebar. Each page had its selfhost/ source
links corrected for the #29 reorg and every repo-relative link rewritten to
an absolute URL on main so it resolves from the wiki.

All eight were current, actively-maintained records, so none were dropped.
The root now holds README.md plus the two user-facing references,
LANGUAGE.md and COMPILING.md; the README links to the wiki, and the
remaining references in LANGUAGE.md / COMPILING.md / examples/README.md and
the emit_net.ludic header comment point at the wiki pages. The emit_net.ludic
change is a comment only — the seed stays byte-identical and bootstrap-cfree
+ the full suite (56) stay green.

Closes #26

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-31 00:36:19 +03:00
fed80f2152 feat(release): SemVer + ludicc --version, changesets, and x release
Some checks failed
commit-lint / conventional-commits (push) Waiting to run
bootstrap / cfree-fixpoint (push) Successful in 13s
ci / build-and-test (push) Has been cancelled
The project had no versioning discipline: 0 tags, no CHANGELOG, no way for the
compiler to report a version. Add a lightweight, native release flow.

- Versioning: SemVer, with VERSION as the single source of truth. `ludicc
  --version` (and `ludic --version`) read it at runtime — so a bump touches one
  file and never reseeds the compiler. `x version` reports it too.
- Changesets: one small Markdown file per user-facing change under changes/
  (bump level + type + summary; see changes/README.md). This replaces "remember
  to edit the changelog" with a mergeable artifact, no Node changeset tool.
- `x release [major|minor|patch] [--publish]`: fold the pending changesets into a
  new CHANGELOG.md section (grouped by type), bump VERSION, commit, and tag
  vX.Y.Z. The level defaults to the highest changeset bump. `--publish` also
  pushes and creates the Forgejo release with source + toolchain tarballs;
  tools/ci/forgejo_release.py is the small stdlib-Python HTTP glue for the
  release API (a native Http client is issue #6).

Seed the initial changesets describing the shipped surface; the first `x release`
turns them into the v0.1.0 CHANGELOG. Reseeded for the --version flag; C-free
bootstrap fixpoint holds; suites 56 / 29 / 29 on macOS, 51 / 28 (+skips) on Linux
CI, bootstrap-cfree byte-identical on both.

Part of the repository-cleanup / DX pass (with #32, #34).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-30 23:46:59 +03:00
a422ef4375 docs: rewrite README as an accurate entry point (#35)
All checks were successful
docs / build-and-deploy (push) Successful in 2s
The README was macOS-centric and internally contradictory about backends
(claimed `--target wasm32` and ELF/COFF cross-compile as implemented while the
prose said they were retired with the C compiler). Rewritten to match the repo:

- Tight pitch: compiled, self-hosted, C-free, ECS, deterministic 2D.
- Honest **Backends** table: native 2D ships today; the web/wasm platform layer
  (runtime/web/) and native-vs-wasm diff harness are in-tree and documented, but
  emitting wasm is not yet re-wired on the self-hosted toolchain — same for
  `--target` cross-compile and `--shared` (per COMPILING.md). Removed the false
  "implemented" claims.
- **Quick start** verified end-to-end: the clang seed one-liner, `bin/x build`,
  `bin/x app examples/games/snake.ludic`, and the headless flow (now writing
  build/out.ppm, not the repo root).
- Layout table matches the reorganised tree: examples/ subdirs (with a link to
  examples/README.md), the golden hash manifest, runtime/native + runtime/web,
  tooling and docs.
- Replaced the giant inline roadmap with a concise status plus links out to the
  issue tracker/proposals, the docs site, and the wiki.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-30 18:57:39 +03:00
fb728bbefe chore(repo): DX cleanup — categorise examples, text-diffable golden, build/ output (#27 #28 #30)
Repository-cleanup / DX pass folding three tracker items into one coherent
change, verified green end to end (`bin/x test` 49/0, `bin/x selfhost-test`
29/0, `bin/x test-tools` 29/0).

#28 — curate & categorise examples/
- 42 flat entries regrouped into intent-revealing subdirs: games/, rendering/,
  ecs/, events/, networking/, lang/, library/ (was lib/).
- chronorift dir-vs-file duplication resolved: the entry file and its import
  modules now live together under games/chronorift(.ludic).
- Every path reference updated repo-wide (test runner, editor-tool drivers,
  docs/site, design docs).
- New examples/README.md indexes the whole set with run commands.
- Showcase examples without a self-asserting entry (hello, events, net_rt) now
  get a compile-only rot guard in `bin/x test`, so nothing here rots silently.

#30 — text-diffable golden baseline
- The 4 binary selfhost/golden/*.ppm blobs are replaced by a single
  selfhost/golden/renders.sha256 manifest (SHA-256 per render). Hashes are
  byte-identical to the old PPMs, so the baseline is unchanged — only its form.
- game_case now compares framebuffer hashes; a regression shows as a changed
  hex line in review, not "binary files differ".
- New `bin/x golden` regenerates the manifest deliberately (review with
  `git diff selfhost/golden/renders.sha256`).

#27 — PPM & asset handling
- Headless renders now write build/out.ppm, never the repo root; `x app`,
  `x clean`, messaging and .gitignore updated to match. Nothing is written to
  the working root any more.
- Redundant local Kenney .zip archives removed (the art ships extracted;
  .gitignore already excludes *.zip). CC0 License.txt files retained.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-30 18:54:21 +03:00
0bc5d76952 docs: add Apache-2.0 LICENSE for the compiler/runtime source
All checks were successful
docs / build-and-deploy (push) Successful in 2s
The tree had only the bundled Kenney asset licenses (CC0), leaving the Ludic
compiler and runtime source implicitly all-rights-reserved (issue #36).

- Add a root `LICENSE`: Apache-2.0 — permissive, with the patent grant that
  suits a language/compiler project.
- README: add a License section stating `SPDX-License-Identifier: Apache-2.0`
  and clarifying that code (Apache-2.0) and the third-party CC0 Kenney art are
  licensed separately. Also add a Contributing section linking CONTRIBUTING.md
  and the Forgejo templates.

Closes #36

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-30 16:46:39 +03:00
a38195128f feat(stdlib): namespaced standard library (issue #2)
Implement the bulk of the namespaced-stdlib proposal (workshopsoft/ludic#2):
156 namespace methods across Math, Text, List, Ease, Collide, World, Net,
Sys, Save, Mem, extended Screen, Color functions, extended Random, and Time.
All deterministic fixed-point; self-hosting (C-free bootstrap fixpoint holds).

Compiler (selfhost/):
- Math.*: sqrt/sin/cos/tan/atan2/asin/acos (fixed-point runtime prelude —
  bit-by-bit isqrt, 256-entry interpolated sine table, Ross atan2), plus
  hypot/dist/dist2/deg_to_rad/rad_to_deg/posmod/wrap/ping_pong/snapped/
  move_toward/smoothstep/lerp/remap/sign/floor/ceil/round.
- Text.* (complete): upper/lower/trim/repeat/pad, split/join/replace,
  and the libc-backed queries.
- List.* (complete): insert/remove_at/remove/sort plus the earlier ops.
- Ease.* (in/out/in_out/back/bounce) and Collide.* (rects/point_rect/
  circles/rect_circle).
- Phase 3: World/Net/Sys/Save namespaced over the bare builtins (byte-
  identical IR) and Mem.* (bytes/words/copy/fill/peek/poke).
- Screen.* extended (line/circle/fill_circle/triangle/fill_triangle via new
  runtime primitives; sprite/sprite_scaled aliases), Color.* functions,
  Random.* (value/int/sign), Time.* (frame/delta/elapsed/now — new
  game-loop frame counter).
- Fix a lexer bug: fixed-point literals with >4 fractional digits overflowed.

Docs & tooling:
- 129 new per-symbol doc pages; gen.py made data-driven (namespaces
  discovered from the docs, no hardcoded list); new check-impl.py enforces
  that every implemented namespace method / keyword / type / phase has a
  doc page, wired into `x test-tools`. Document the previously-undocumented
  keywords (break/continue/where/entry/new/public + and/or/not tokens).
- LSP: namespaced signature help (ns_method_sig) covering every namespace.

Tests: 12 new self-host/regression tests + a golden render for the drawing
primitives. All suites green (selfhost 21, regression 45, tools 29).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-30 00:26:19 +03:00
cc701013f5 Phase 6e: unify builtin naming (loaders domain-first, set_reg)
Fixed the naming inconsistencies the cohesion audit flagged, converging on the
domain-first style the bulk of the surface already uses (ui_*, text_*, rng_*,
font_load, image_load):

  - load_png    -> png_load       (asset loaders were split: font_load/image_load
  - load_sprites -> sprites_load   were domain-first, load_* were verb-first)
  - setreg      -> set_reg        (missing underscore vs ui_set_int/ui_set_text)

Game builtins resolve to their `rt_` runtime function, so the renames are in
runtime/native (rt_png_load, rt_sprites_load, rt_set_reg) plus the ~100 example
call sites; `become` lowering in emit_machine now emits @fn_rt_set_reg. Purely a
surface rename — every renamed call maps to the same runtime symbol, so behavior
and golden renders are byte-identical.

Vocabulary + docs updated (ludic_syntax.h, grammar, LudicTokens.kt, LANGUAGE.md,
README, SYNTAX-REDESIGN). Reseeded; C-free fixpoint holds; goldens identical;
17/17; vocab clean.

Left as-is: os_argc/os_arg (compiler-internal intrinsics, already namespaced and
consistent with each other; renaming would need a bootstrap dance for little
gain). reg/set_reg keep the getter-bare/setter-set_ shape ui_focused/ui_set_int
already use.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-27 23:38:10 +03:00
dfc17398cf Phase 6b: annotation DSL (@Queries, @Handles) + docs prose pass
@Queries(these: [Prop{constraint}, ...], on: Model) on a handler desugars to the
existing S_QUERY loop: each property binds by its own name, a Prop{...} block
qualifies its bare fields to that property, and on: adds a {Model} tag filter.
Implemented via parse_queries_anno + qualify_fields (parse_game.ludic), wired
into parse_one_decl; @Handles parses on the program (documentation).
examples/annotations.ludic demonstrates it (output 3 1 0 0); test.sh 15/15.

Docs: added the Annotations section to LANGUAGE.md and did the vocabulary prose
pass (component->property, archetype->model, system->handler, game->program)
across the docs. check-docs + test-tools green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-27 18:49:24 +03:00
9a558d6b58 Phase 3d: declaration modifiers become @annotations (Rule A)
edge/pure/export prefix keywords retired; modifiers are now leading @annotations
(@export, @edge, @pure, @deterministic). parse_one_decl collects a leading @anno
run and @export sets the fn export flag; dead edge-dispatch removed from
parse_system. Migrated examples/lib/combat.ludic; old prefixes now rejected.

Behavior-identical: the export flag is parse-only in the self-hosted emitter
(emits @fn_<name> for every fn, never reads the flag), so IR is byte-identical.
Reseeded, fixpoint holds, test.sh 14/14. Docs updated. Phase 3 complete.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-27 16:16:16 +03:00
985f9ad8f2 Baseline: Ludic compiler + toolchain, Phase 1 syntax fixes complete
Self-hosted compiler (selfhost/*.ludic), runtime, examples, editor tooling,
and docs. Phase 1 of the syntax-redesign cohesion pass has landed:
edge-system fix, signature-query, when-alias, and the documentation truth-pass.
Suite green (14/14), C-free bootstrap fixpoint holds.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-27 15:15:35 +03:00