Commit graph

21 commits

Author SHA1 Message Date
ec9a650e65 feat(ui): ui_scale and ui_box, on-submit, zoom (and a length over a length in calc), on-hold
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 03:31:38 +03:00
3d2a103dfb fix(lang): a function named like a compiler built-in is refused; reseed
A program's own `run` was never called: every call to it lowered to the
built-in System.run (C's system()), and clang failed on the IR.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 22:09:29 +03:00
ae61e99e06 test(ui): a component with no stylesheet reads the theme's :root variables
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 22:07:05 +03:00
077b38e684 feat(ui): a title shows for the keyboard's focus as well as the pointer
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 22:06:27 +03:00
d15cc79822 feat(ui): a key field takes a mouse button, and is :capturing while it listens
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 22:04:47 +03:00
6bd3228990 feat(ui): translate="no", and a title of several lines translated whole or line by line
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 22:03:49 +03:00
7605a0253c feat(ui): linear-gradient backgrounds, object-fit and aspect-ratio
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 22:02:49 +03:00
abf45ef9db feat(ui): scroll-top holds a scroll box at an offset, on-scroll, and ui_scroll_set
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 22:00:21 +03:00
cf8b9e425e feat(ui): nine-slice corners clamped to half the box in each direction, cut on whole pixels
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 21:59:26 +03:00
12f4ba8431 feat(ui): min(), max() and clamp(); insets as percentages of the containing block
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 21:53:44 +03:00
355201f094 feat(ui): text-fit, line-height, and ems against the font size an element ends with
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 21:51:41 +03:00
d163bad406 feat(ui): a popover's align along its side, and within= for the bounds it flips against
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 21:48:58 +03:00
0aad2294ec feat(ui): pointer events for natives and elements, with capture; on-down and on-up; hits in painting order
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 21:48:02 +03:00
d2b0413c30 feat(ui): the gamepad moves the focus, presses and goes back; a held direction repeats on the clock
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 21:42:32 +03:00
a4c7a756f0 feat(ui): a scrollbar held where it was taken, a popover that keeps the mouse, easing that lands
- the scrollbar is .ui-scrollbar with a .ui-thumb, styled by the default sheet or a theme; a press
  on the thumb holds it at the point it was taken and the pointer moves it in proportion, a press on
  the track jumps the thumb's middle there and holds it, and neither presses what is under the bar
  (it used to centre the thumb on the pointer and press the row beneath as well);
- while a popover is up only scroll boxes inside it take the pointer, and a press outside it that
  closes it forgets any press in progress;
- a transition ends exactly on its value (it stopped a rounding error short, at every frame rate).

Tests: ui_popover_mouse, ui_scrollbar, ui_ease (60/120/180/240 Hz).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 21:39:28 +03:00
9f59000f5b feat(ui): number and key fields, notes, anchored popovers, text-shadow, and pictures as painted
- <input type="number" min max step>: typed digits replace its value (a minus when min allows one,
  a point when step has a fraction), Enter or leaving the field commits them held between min and
  max, the left and right arrows step it.
- <input type="key">: Enter or a click starts it listening and the next key is its value, Tab, the
  arrows and Enter included; Esc stops it listening, Backspace clears it, `shown` names the value,
  and ui_capturing() tells the host to leave its keys alone (through the frame that ended it).
- note="..." under any control's label (.ui-labels > .ui-label + .ui-note); a range's (or number's)
  value with decimals, format="percent" and a unit.
- A popover with `anchor="id"` (the nearest element of that id) or a bare `anchor` (the element
  before it) sits beside it by `placement` (right, left, bottom, top), its margin the gap, opens to
  the other side where it would leave the screen, and is kept on it.
- A tooltip's title splits into lines at a newline or a written \n.
- text-shadow, inherited, drawn sharp under the text.
- ui_opacity(): the group opacity a native's draw is at.
- border-image is drawn as painted with no background colour, tinted by one, and not at all when
  that colour is transparent (it drew a white nine-slice).
- A picture file is drawn untinted, as a browser draws one; an atlas cell (prefix:name) still takes
  the color around it, and an <img> with its own color is tinted by it.
- The render3d backend loads a picture again when its file changes or appears (a failed load was
  kept for ever), and at once after ui_image_reload(path); takes a path with a drive letter (C:/...)
  as a path rather than an atlas; and slices a nine-slice by its texture's own width and height.
- ui_inputs.ludic and ui_look.ludic; LANGUAGE.md and the changeset say all of it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 19:55:20 +03:00
0a7525b125 feat(ui): popovers, tooltips, progress; the render3d backend installs itself; duplicate names caught first
- `popover`: a top layer that keeps the pointer and the keyboard, closed by a press outside or Esc.
- `title` tooltips after half a second's rest, styled by .ui-tooltip.
- `<progress>` and `<meter>`.
- Atlases take rows and number cells, and importing ludic.ui/render3d.ludic is enough to draw with
  render3d.
- The compiler reports two declarations of one name before it type-checks, so a package global
  clashing with a program's reads as that, not as 29 type errors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 17:41:02 +03:00
1dad96102a feat(ui): ludic.ui is a UI framework - input, controls, render3d backend, the CSS a game needs
A game no longer writes a host:
- The runtime reads Input itself: focus and keyboard navigation (Tab, arrows, Enter/Space,
  autofocus), the pointer (hover, :active, click on release, drag), and scroll boxes with the
  wheel, a draggable scrollbar, clipping and scroll-into-view.
- HTML's controls are built in (button, checkbox, radio, range, select, text, key capture), made
  of plain parts a stylesheet styles, each reporting with on-change and event.value.
- ludic.ui/render3d.ludic draws with render3d's overlay: textures, named atlases (icon:NAME),
  nine-slice border-image, rounded rects and rings, clipping, and a scale.
- Hooks for the program's language, sounds and clock (ui_translator, ui_sounds, ui_clock).
- ui_dev: hot reload, errors on screen, LUDIC_UI_DUMP.
- CSS:
  - colours as #rgb / #rrggbbaa / rgb() / rgba() / names;
  - border-radius and outline (following the radius), box-shadow, background-image and a tinted
    border-image;
  - group opacity, @keyframes / animation, transition;
  - :focus, :focus-visible and :focus-within.
- HTML mixed content, and boolean attributes.
- render3d gains tex_width / tex_height, and the XML reader keeps text runs in order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 17:26:09 +03:00
20d011f8e9 feat(lang): UI components as files - component Name { ... } beside Name.xml and Name.lss
The compiler turns a component declaration into:
- a record of its props and state;
- a constructor, a props setter, a model and a call;
- a class, registered with ludic.ui at start.

Its template and styles are read from beside it and compiled in, with @import inlined, and a
missing template fails the build.

In the runtime:
- each mounted instance keeps its own props and state, and `set` in a template writes the state;
- styles are scoped to the component;
- class, style and id on a component's tag land on its root, styled by the parent's sheet too;
- ui_reload re-reads a component's files from disk and keeps instances.

The package's own module is now ludic_ui, so a program may call a directory of its own ui.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 16:50:12 +03:00
637d07400e feat(ui): ludic.ui grows toward HTML, CSS and React (Phase 0.U1-U4)
- Natives: ui_native(tag, measure, draw) makes an element the program draws itself; ui_fire
  runs its on-<event> with event.value. input, select and textarea have simple defaults.
- React:
  - keyed <each>, <let>, <provide> context through components, <fragment>;
  - named slots, default props on <component>;
  - on-mount / on-unmount;
  - inline text inside text elements.
- CSS:
  - custom properties and var();
  - position relative/absolute/fixed with insets and z-index;
  - em/rem/vw/vh and @media;
  - wrapping text and ellipsis, overflow;
  - + and ~ combinators, :nth-child(an+b), :checked, :active.
- Developing: errors with file:line, ui_errors(), ui_reload() keeping state, and an
  inspector-style ui_dump.
- view fields infer the type of a literal or a named function's result.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 16:17:25 +03:00
66a2bc2214 feat(lang): L11 views and templates - the UI is markup, not code
A `view Name { field = x; function q(..); on e(..) }` declaration is the one bridge between a
program and its UI: it writes view_<name>() -> UiView, whose model is a Value of every field and
whose call runs a query or an event by name.

ludic.ui is a template runtime:
- HTML-shaped XML screens and components, loaded at run time;
- {expression} bindings, if/else/each, props, slots, per-instance state;
- on-press / onclick actions (event, set, emit);
- component libraries (export="true", <import src as>).

Styling:
- stylesheets in <style> or importable .lss files (@import);
- CSS selectors (#id, .class, [attr=v], descendant and > combinators, :hover, :disabled,
  :first-child, :last-child, :nth-child, :not) weighed by specificity;
- the box model and flex under CSS's property names.

Also:
- default parameters, and positional-then-named calls;
- Value gains a float kind;
- a function shadowing a runtime one is refused;
- an index is evaluated before the slice is read;
- runtime errors name the right file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 15:58:47 +03:00