Skip to content

dmvs_html: scripts compiled by dmvs_js - the host of its DOM - #4

Merged
JohnAmadis merged 11 commits into
mainfrom
feature/js
Oct 11, 2026
Merged

JohnAmadis merged 11 commits into
mainfrom
feature/js

Conversation

@JaxCalder

@JaxCalder JaxCalder commented Oct 10, 2026 •

Copy link
Copy Markdown

Summary

The page's scripts are now compiled by dmvs_js. dmvs_html's own evaluator (lexer, parser, abstract runner: about 1800 lines) is gone, and script.c is now the compiler's host, i.e. the DOM. Scripts get the whole language dmvs_js compiles:

  • timers (setTimeout / setInterval / clearInterval);
  • texts (innerText / textContent);
  • numbers (parseFloat, toFixed, Math);
  • loops, functions with returns, closures.

Before, all of that was reported and left out.

What the host does

  • Elements: getElementById, querySelector(All) (an array) and getAttribute, resolved at conversion.
  • Classes and styles:
    • classList.add / remove / toggle / replace / contains and style.<property> = <static text> are laid out as before: moves and fades are variables animated by CSS transitions, other looks become variants, and :active gives pressed looks.
    • Each change is a CALL of a handler reserved during compilation and filled once every change is laid out.
    • Classes an element changes together become one change (one look). The compiler's flush hook marks where the code changes direction, as the old code did.
  • Element variables (let current = null; … current = w): a change of the element a variable holds is an IF for each element dmvs_js_object_domain() gives.
  • Texts:
    • innerText / textContent is a text variable of 64 bytes.
    • It is painted on the element's first line, or on its content box when the element starts empty, and placed by text-align.
    • Its font gets every character the scripts contain.
    • A number variable shadows it, so parseFloat(el.innerText) reads the number it shows.
  • Clicks:
    • addEventListener('click', f), el.onclick = f and onclick="…" (with this set to the element) make up an element's click handler.
    • el.click() calls it.
    • The click handler and the element-variable IFs copy their callees' actions instead of calling them, because dmview's calls nest only 8 deep.

Still reported and left out: createElement / innerHTML, src, setAttribute, styles known only at runtime, Date.

Depends on

  • dmvs_js#4, with a release of dmvs_js (there is none yet). The module links dmvs_js@>=0.1 and dmvsi@>=0.4, so CI can't pass until that release exists.
  • For views using the new code: todmvs#4 (code IR, long texts split), todmv#7 and dmview#14 (APPEND, format 0.5).

Added after the board test (car HMI)

  • What scripts build as the page loads is part of the page:
    • dmvs_js's evaluator runs the loading. createElement, className, innerHTML with markup and appendChild are recorded as operations on the page's elements, and applied on every layout, states included.
    • A created element carries data-dmvs-built="k", so the compilation's k-th createElement() is that element, and its listeners become clicks.
    • The car HMI's queue shows its 5 songs, with the current one highlighted.
    • A list rebuilt later, while the view runs, stays as it was at load.
  • innerHTML set to text in an element with no child elements becomes its text (the climate temperatures).
  • Room for script texts: a script's text in a box as narrow as its text takes the room of the first wider ancestor, centred or right-aligned as the box sits in it. The speed was "6" instead of "68".
  • No undefined texts: a text that is undefined is not set.
  • New test step: a list built from an array, with its texts, the current row's background, and the three rows' clicks. 10/10 locally.

Added for the car HMI's home screen and queue

  • CSS animations:
    • @keyframes, Tailwind's spin / ping / pulse / bounce, and animate-* / animate-[...] are supported for what dmview can move: transform: translate and opacity.
    • An animated element gets its group's variables, and the view gets one timer. Every 20 ms it starts each animation's segment that is due: an ANIMATE to the next keyframe with its timing function and duration. Animations repeat forever (infinite), and alternate goes there and back.
    • The equalizer bars bounce. Rotation and scaling (the spinning cover) are reported and not drawn.
  • Rounded images:
  • Choices:
    • className set to one of known class lists becomes a change to each list, applied according to which one it is. The queue's highlight follows the current song.
    • img.src set to one of known images becomes a variant per image, shown by its variable. The cover changes with the song.
  • Icons in looks: an element's look includes its text, so an icon font's ::before (play / pause) counts as a different look.
  • Other looks seen as the element is: the queue's rows no longer vanish in their other look inside a screen that is hidden at load.
  • Scroll extent: a box that scrolls can scroll as far down as its children go (the queue).
  • dmvsi 0.5 is required.

Testing

test_dmvs_html passes 11/11 locally (with dmvs_js feature/host-objects).

  • The existing script tests now check the actions with CALLs inlined (flat_actions()). Those are the same actions the old code emitted: windows sliding in with their transition, current held and tested, a class toggled.
  • A new step converts a page with a speed text driven by setInterval and a temperature changed by a click with parseFloat / toFixed. It checks:
    • the text nodes are bound to text variables, centred, with the initial text;
    • the shadowing number starts at 21500;
    • the click sets both;
    • the view has a timer.

The car HMI (car_hmi_480x272.html) converts with todmvs (#4) into 36 boxes and 247 instructions, and assembles with todmv (#7) into a 53 KB view. It hasn't been tested on the board yet.

🤖 Generated with Claude Code

JohnAmadis and others added 9 commits October 10, 2026 13:39
The page's scripts and onclick code are compiled by dmvs_js into the
view's code (init, click handlers, timers, variables); script.c is now
its host. Its own evaluator goes; what it did stays: a class or style
change is laid out (moves, fades by transitions; other looks as
variants; classes changed together - up to the compiler's flush - one
look; pressed looks). A change is a CALL of a handler made when every
change is laid out; one of the element a variable holds an IF for each
element dmvs_js_object_domain() gives. innerText / textContent are text
variables, with a number shadowing them (parseFloat(innerText)), painted
on the element's first line, placed by text-align. Click handlers copy
their listeners' actions (dmview's calls are 8 deep).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ned not set

A text a script sets in a box as wide as its text (a flex item, its
column as narrow) gets the room of the first wider ancestor, placed as
the box is in it - centred, at its right, or from where it is: the car
HMI's speed was "6" of 68. A text that is undefined is not set.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The scripts' loading evaluated by dmvs_js (every variable known,
functions run at each call): the elements they make - createElement,
className, innerHTML of markup, appendChild - recorded as operations on
the page's elements, applied each time it is laid out (its states too).
A made element is marked data-dmvs-built="k": the compilation's k-th
createElement() is it, so its listeners are its clicks; what it sets of
it (className, innerHTML, appendChild, emptying its list) is as it was.
The car HMI's playlist: its five songs, the current one highlighted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… look

el.className set to one of known class lists (a row rendered as
`row ${active ? 'on' : ''}`): a change to each, on which it is - the
row's looks follow the current song. img.src set to one of known images
(playlist[i].cover): a variant of the image for each, shown on its
variable. An element's look counts its text (an icon font's ::before):
play / pause changed nothing before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A look of an element is laid out in a state of the page, where a screen
hidden as the page loads (visibility) still is: revealed in the page by
the change that shows it, not in the states. A row of a list in such a
screen was painted unseen in its other look - it vanished when another
song was chosen. A look is now seen where the element is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A box that scrolls (overflow: auto) scrolls what is in it: a flex column
of a definite height (flex-1) is laid out as tall as it is, its content
height that too - so the playlist's queue, longer than its box, did not
scroll. What can be scrolled to is now as far down as its children go,
with its bottom padding.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Keyframes (and Tailwind's spin, ping, pulse, bounce; animate-*,
animate-[...]) of what dmview can move - transform: translate, opacity:
an element animated gets its group's variables, and the view one timer,
every 20 ms starting each animation's segment that is due (an ANIMATE
to the next keyframe, its timing function and time; infinite; alternate
there and back). The car HMI's equalizer bars bounce; rotate / scale
(its spinning cover) are reported, not drawn.

An image's corners: its own border-radius, or that of a box around it
that clips and that it fills (a cover in a round frame) - dmvsi's
image radius, made round by todmvs / todmvi.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@JaxCalder JaxCalder closed this Oct 11, 2026
@JaxCalder JaxCalder reopened this Oct 11, 2026
JohnAmadis and others added 2 commits October 11, 2026 10:48
dmvs_html loads dmvs_js to convert a page's scripts, so every conversion
in the tests needs it installed. CI installs only what the test module's
.dmd lists (dmf-get install -d), which was dmvsi alone: all 11 steps
failed with "Cannot load required module 'dmvs_js'". It passed locally
because dmvs_js was already installed.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The test's .dmd lists what the test itself imports (dmvsi). dmvs_js is
imported by dmvs_html, the module under test, so only its .dmd lists it:
CI installed one package and every step failed with "Cannot load
required module 'dmvs_js'". The ctest command had the same gap.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@JohnAmadis
JohnAmadis merged commit 173aa99 into main Oct 11, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants