- grass_cull.comp decides each candidate blade once a frame (place, ground, density, water,
slope, frustum, colour field) and writes survivors into three bands by distance, one indirect
draw each; grass_inst.vert only bends and places the vertices. OpenGL keeps grass.vert's
per-vertex path; R3D_GRASS_GPU=0 compares
- compute programs take sampled textures after their buffers (gpu_compute_tex / gpu_dispatch_tex),
and every dispatch now records a compute-to-draw memory barrier
- the blades as a sward: 4 m cells, bands with five, three and one-quad blades, spacing doubling
every 18 m to 70 m, never narrower than a pixel; lit facing the sun and leaning to the sky,
shadow looked up above the ground (it read the terrain as its caster), a colour ramp that
leaves only the sheath dark, clumps, dry patches and a tussock shade worked out per blade
- scatter layers flagged grass are skipped while the blades draw (and under R3D_NOGRASS);
R3D_BLADES, R3D_NOBLADES win over the game's setting; R3D_GRASS_S0/D0 for measuring
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Checked on both machines with a bundled Jolt probe: the licence and the library in place, the app
signed (Mac) and the probe's ball landing at the same height on both.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tools/native/lib.sh passes -implib rather than /implib: Git Bash rewrites an argument starting
with / into a Windows path, and lld-link was handed 'C:\Program Files\Git\implib;...'. Both DLLs
import KERNEL32 alone, so no C++ runtime ships beside them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The water floats the hull, the wind pushes every boat as a force, the lake bed stops it at the shore;
the swell takes the outward share of a stroke. ludic.physics: phys_hull_add (a buoyant box),
phys_row, phys_bow_speed, and a test that floats one a quarter under, rows, turns and grounds it.
The vehicles tests row a real Jolt hull on the fake shore; the horse moved to horse.ludic.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflicts with 0.R5's state defaults in ludic.wildlife resolved; wl_step writes the push's answer, so
its callers take WildlifeState mut again.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- ludic.wildlife: WildlifeWorld.push / pushed_x / pushed_z (defaults change nothing); a ground
walker's step is slid clear of a still thing with a body from its species' size and scale, and
a step that gets nowhere turns away as the water does. Birds are not pushed; no dice added.
- ludic.npc: NpcWorld.push / pushed_x / pushed_z (a person 0.35 m round) in npc_walk, and
NpcWorld.clear (default true), which npc_line_ok asks at 1 m so a detour does not cut a trunk.
- ludic.aim: AimView.clear replaces AimView.ground and the ground march; the pick asks the line
a body's width short of where the ray enters the thing (aim_clear_at(t, back)), so a solid
thing does not hide itself. probe.ludic (the ground-agreement probe) and AimView.dry are gone.
- ludic.photo: PhotoLens.clear replaces PhotoLens.ground, PhotoLens.trunk and the march.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- a CAMetalLayer on the view (cocoa.ll win_metal_layer), VK_EXT_metal_surface, QuartzCore linked
with Vk.*; the drawable measured after the layer sets the backing scale
- vk_mac.ll opens MoltenVK directly after any loader: a bundle ships only libMoltenVK.dylib
- a covered window is not presented to (win_visible); one frame in flight on macOS
(R3D_VK_INFLIGHT), with images, buffers and descriptor pools held until it is done
- win_held / win_mouse / win_pad / win_touch / win_text / win_present pass slice elements (arg_buf):
every windowed program died on its first input poll
- variants.list and SPIR-V for the three NEAR_FADE foliage programs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The package keeps the rules and hands them over each step: speed and heading, whether a jump
leaves, CHAR_STEP and the boots' slope limit. The walker (Jolt CharacterVirtual) does gravity,
landing, steps, slopes and following the ground down. Too steep is ground too steep facing the way
the body wanted to go; stepping off an edge is not. ludic.physics: phys_walker_move (follow the body
if something else moved it, then step), the slope limit, the jump always honoured. The character's
tests run on a real Jolt walker over the same fake world: 15 pass, a knee-high boulder now a step.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Five new tests: stand and walk at the asked speed, a low stone is a step and a tall one a wall, a
jump up and back, a crate shoved aside, a hull turned by a torque and carried by a force.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Maroon Lake: 149 parameters became read-only. What stays mut is a real write - in the packages mostly a
lazy start inside a question (things_all, gear__ensure), which is what to take out next.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
collide.ludic (circles in a cell grid that could not be removed) and its Render3dState fields are
deleted, and the reload example stops asserting colliders. A game still calling col_* must move to
ludic.physics first (Maroon Lake's src/solid).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Our own shim (native/shim/jph_shim.cpp) over Jolt built from the pinned tag with cross-platform
determinism and no fp contraction: shapes as handles (box, sphere, capsule, cylinder, dome,
offset, heightfield, mesh), still/kinematic/dynamic bodies by id with real removal, rays,
top_at and push (what CharacterGround asks), overlaps, buoyancy against the PhysWater port,
contacts recorded in C and drained as PHYS_HIT / PHYS_SPLASH facts. Fixed 1/60 steps, at most four
a frame. Nine tests against the real library, including a pile run twice to the bit.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
native "<target>" "<path>" in a package's package.ludic; the compiler records the libraries of
every package a program imports and writes them into the IR (; ludic-native:), so ludicc -o,
ludic build, ludic test and ludic bundle all link one list. macOS: an rpath to the package and to
Contents/Frameworks, where ludic bundle copies and signs each library and drops the build
machine's rpath. Windows: the import library, the .dll copied beside the exe (--natives-out for
the bundle). tools/native/lib.sh builds from a pinned, checksummed source with clang on both
machines; ludic.nativeecho is the worked example; the shim rules are in packages/README.md.
Linked at build time rather than dlopen (docs/PACKAGES.md says why). Reseeded.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The old kit read Input.mouse_x() * gl_scale; ludic.ui read it raw against a layout sized in
drawable pixels. A backend says how many screen pixels one pointer unit is (pointer_scale);
render3d's is gl_pixel_scale(), 1 on Windows and headless.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A reach through Port.member() follows that member's binding (or its default), and Registry[i].field -
or a local holding Registry[i] - follows that field in each entry, so a question asked of a port or a
table that also holds verbs no longer reaches the verbs. In Maroon Lake that took the valley's
'what is this Thing called' from 47 states it could change to 1. examples/state/write_reach.ludic.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What only becomes known inside the drain - a value another reducer just set, the map in play - no longer
has to be faked into the action, so a verb that reads several systems while it changes one is a reducer
instead of an act handed its states. A second state to write is still refused, and the message says the
way out. examples/actions/reads.ludic; reseeded.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ludic.ui runs a frame's presses after drawing it, and what they dispatched waited for the end of the
phase - after the host had presented - so a button's change showed a frame late. Decided: drain, not a
phase per action. ui_show and ui_press drain the queue once the presses have run, so the code after
them and the frame presented next see the change; a host that runs presses some other way calls
drain_actions() before it presents.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A game's exported UiAct collided with ludic.ui's, which nothing outside ludic.ui uses: it is private
to ludic.ui now, and a private record of one spelling in two modules never clashed. A real clash - a
type named like one a package exports - is still refused, and the message names the package and the
way out (`ludic_ui exports it, and exported names are one namespace - rename this one, or declare it
without export inside a module of your own`).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A step list or a registry of fn values takes no state and still reaches every state its steps take.
The compiler now writes `reach <n> <function>` - every state a function can come to by a call, a
`fn f` it writes or a global holding fn values it reads, to a fixed point - and ludic deps reports
widest_reach beside widest_function, with how many of those states the function does not take
(Maroon Lake: app_boot, 72, all 72 through fn values). --widest N lists the N functions that take the
most states with what each reaches; --reach N orders them by reach. A baseline without widest_reach
does not hold it until rewritten.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>