Proposal: a namespaced standard library — Math (trig/lerp), Text, List, Time, Audio, and namespacing the bare builtins (World/Net/Sys/Save/Mem) #2
Labels
No labels
area:ci
area:docs
area:input
area:net
area:rendering
area:repo
area:stdlib
area:tooling
area:types
cleanup
dx
priority:high
priority:low
priority:medium
proposal
status:in-progress
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: workshopsoft/ludic#2
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
Ludic already namespaces part of its API —
Screen.*,Input.*,Random.*,Map.*,Color.*— but the rest of the built-in surface is small and unnamespaced:print,save,load,len,push,min,max,abs,clamp,fx,flr,bytes,words, theworld_*reflection ABI, thenet_*networking calls, and process calls (arg,exit,run,getenv,read_char,file_*). Notably there is nosin/cos/sqrt/lerp/remap, almost no string manipulation, no audio, and no time/frame access — things every game reaches for on day one.This proposal does two things:
Screen.*), moving the bare builtins into namespaces.Mathf, and Go / C# standard libraries.Legend: ✓ exists today (bare) → namespace it · + new.
Core math —
Math.(the biggest gap)Today only
min max abs clamp fx flrexist. A game needs the rest.Math.minMath.maxMath.absMath.clamp✓Math.signMath.floorMath.ceilMath.round+floor= today'sflr)Math.sinMath.cosMath.tanMath.atan2Math.asinMath.acos+Math.sqrtMath.powMath.expMath.logMath.hypot+Math.lerpMath.inverse_lerpMath.remapMath.smoothstepMath.ease+lerp/remap/smoothstep/ease)Math.move_towardMath.ping_pongMath.wrapMath.snappedMath.posmod+move_toward/pingpong/wrapi/snapped)Math.distMath.dist2Math.deg_to_radMath.rad_to_deg+Math.to_fixedMath.floor_to_int✓fx/flr, renamed for clarityText / strings —
Text.Today: only
str(x),len(s), and slicings[a..b]. Games format HUDs and parse input constantly.Text.lengthText.char_atText.sliceText.index_ofText.containsText.starts_withText.ends_withText.upperText.lowerText.trimText.splitText.joinText.replaceText.repeatText.pad_leftText.pad_rightText.from_intText.to_int+ (Gostrings, C#String; interpolation via backticks already exists)Collections —
List.(over[]Tslices)Today:
push,len. PICO-8 hasadd/del/all/count/foreach.List.push✓ ·List.popList.insertList.remove_atList.removeList.containsList.index_ofList.clearList.reverseList.sortList.swapList.firstList.last+ · plus aMap2.*/ dictionary +Set.*once the container types land (see #1).Drawing — extend
Screen.Today:
clear fill_rectangle draw_rectangle put_pixel draw_text draw_number show width height status. Add the primitives every 2D game uses (PICO-8line/circ/circfill/spr/camera/clip):Screen.lineScreen.circleScreen.fill_circleScreen.triangleScreen.fill_triangleScreen.ovalScreen.spriteScreen.sprite_scaledScreen.cameraScreen.clipScreen.measure_textScreen.blend_mode+Input — extend
Input.Today:
Input.key(). Add edge detection + pointer + pads (PICO-8btn/btnp, LÖVE mouse):Input.key_down(k)Input.key_pressed(k)Input.key_released(k)Input.mouse_xInput.mouse_yInput.mouse_down(b)Input.mouse_pressed(b)Input.wheelInput.axis(neg, pos)Input.button(pad, b)Input.text+Audio —
Audio.(missing entirely)Audio.play_sound(id)Audio.play_music(id)Audio.stop_musicAudio.stop_allAudio.volume(v)Audio.pitch(v)Audio.is_playing(id)+ (PICO-8sfx/music, LÖVElove.audio)Time —
Time.Time.frame()(deterministic frame counter) ·Time.elapsed()(fixed seconds since start) ·Time.delta()(fixed dt) + ·Time.now()+ (wall clock — non-deterministic, flagged; for seeding/telemetry only)Random — extend
Random.Today:
range chance seed. Add:Random.value()(fixed 0..1)Random.int(max)Random.sign()Random.pick(list)Random.shuffle(list)Random.direction() -> vec2Random.color()+ · andRandom.stream(name)+ — independent, named deterministic streams so gameplay RNG and cosmetic RNG can't desync a replay.Tilemap — extend
Map.Today:
size row tile. Add:Map.set_tile(x, y, ch)Map.in_bounds(x, y)Map.fill(ch)Map.find(ch) -> listMap.neighbors(x, y)+Rename the bare builtins into namespaces
world_get/set/has/count/size/spawn/save/load/prop_id/field_id/model_id/kind/register_prop/attach_dyn/detach_dyn/query_next✓World.*net_send/net_poll/serialize/apply/owner/set_owner/is_server/is_owner/local_id✓Net.*save()/load()✓Save.write()/read()(+Save.exists,Save.clear,Save.slot(n)+)arg_count/arg/exit/run/getenv/read_char/file_*✓Sys.*(Sys.args,Sys.exit,Sys.run,Sys.env,Sys.read_char,Sys.stdout/stderr/write)bytes/words(+fixeds/ptrs) ✓Mem.bytes/words/fixeds/ptrs+Mem.copy,Mem.fill,Mem.peek,Mem.poke+ (PICO-8memcpy/memset/peek/poke)print✓printas a convenience and addDebug.print/assert/log/watch+ui_build✓UI.build/open/tick/render/clicked/set_text/...(already partly namespaced conceptually)Creative additions — leaning into what Ludic is (deterministic ECS + 2D)
Query.— ECS-native helpers beyond thequerykeyword:Query.count([Prop]),Query.first([Prop]) -> entity,Query.nearest(from, [Prop]) -> entity,Query.within(center, radius, [Prop]) -> list. The built-in ECS makes spatial/aggregate queries a natural builtin.Vec.— 2D vector ops (pairs with thevec2type in #1):Vec.make,add,sub,scale,dot,length,normalize,rotate,angle,from_angle,lerp,distance.Ease.— tween curves:Ease.in,Ease.out,Ease.in_out,Ease.elastic,Ease.bounce,Ease.back— the "juice" layer, deterministic.Collide.— 2D collision:Collide.rects(a, b),Collide.point_rect(p, r),Collide.circles(a, b),Collide.rect_circle(...).Grid./Path.— 2D staples:Path.a_star(cost_map, from, to) -> list,Grid.line(a, b)(Bresenham),Grid.flood_fill(x, y),Grid.line_of_sight(a, b).Camera.:Camera.set(pos),Camera.follow(entity, lerp),Camera.shake(amount)(deterministic shake from the seeded RNG).Color.extensions:Color.rgb,Color.rgba,Color.lerp,Color.darken,Color.lighten,Color.with_alpha.Principles
Screen.*— discoverable viaNamespace.completion, and each becomes a documentation page (the reference already renders namespace overview pages).Time.now, a wall-clock RNG seed) are explicitly named and documented as such.Math.*/Vec.*/Ease.*calls are pure fixed-point and lower to a handful of IR ops.print,min,max,abs,clamp,flr) during a transition; everything else moves under a namespace.Suggested phasing
Math.*(trig, sqrt, lerp/remap/move_toward/smoothstep) — unblocks real gameplay math today.Text.*+List.*— HUDs, parsing, collections.World.Net.Sys.Save.Mem.).Time.*,Audio.*, extendedInput.*/Screen.*.Vec.Query.Ease.Collide.Camera.Path..References
spr,map,btn,sfx,flr,sin,cos,rnd,mid,circ,line,camera,peek/poke)@GlobalScope(lerp,remap,move_toward,smoothstep,ease,snapped,wrapi,pingpong,posmod, trig)love.graphics,love.audio,love.keyboard,love.math,love.timer)strings/math, C#Math/MathF/Stringvec2/ivec2/colorback theVec.*/Color.*calls).Researched against PICO-8, Godot, LÖVE, Unity and Go/C#; creative additions chosen for a deterministic ECS-based 2D language.
The namespaced-stdlib core is implemented and lives on branch
stdlib-namespaces(PR: main...stdlib-namespaces): 156 namespace methods acrossMath,Text,List,Ease,Collide,World,Net,Sys,Save,Mem, extendedScreen,Colorfunctions, extendedRandom, andTime— all tested, documented, and self-hosting (the C-free bootstrap fixpoint holds).Closing this in favour of focused follow-ups for the scope that needs work outside this proposal:
Already tracked elsewhere:
Vec.*/rect types → #1; extendedInput.*(mouse/gamepad/edge) → #7 (the input revamp, which supersedes #2's input sketch).