Wednesday 13 March 2024

Betime + svelte 2

Here's an interesting bit of non-error in the middle:

 

Anyway, we're in here wondering how to make this nicer:


We've already created a <wrapper>|<spacer> dualism, which allows bits of html to overlap as they change size, the larger groups adjusting slowly.

We are missing the final adjustment once things stop changing, which I simulate by clicking on things.

We might have access to that time (after everything has settled down, per Con) at the outer awareness already, which repeats itself via a simple singleton+ttl+delay loop (at the end of itself):

        if (ttl < 3) {
            ...
setTimeout(() => {
animalsizing_loop(uniquely,ttl+1,was),

And if I make this adjustment to go the inner awareness every time,

// model chaos
// change &&
await animalsizing(ge)

it basically fixes it, but never ends:


Those sleeves stay green because it's inflooping, which is CPU toxic, see https://youtu.be/HuD_zzgMdtk?t=192 the Material Science Gameplay Loop


chart labels

They are all piled up!

let label_height = 20
function spread_ys_labels(ys_labels) {
// sort by y
ys_labels = ys_labels.sort((a,b) => a.y - b.y)
// needy may get ahead of lab.y when lab are too bunched
let squidge = (i,needy) => {
let lab = ys_labels[i]
if (!lab) return
if (needy && needy > lab.y) {
// we are told lab.y needs to be further
lab.further = needy - lab.y
lab.y = needy
}
// next one should be...
needy = lab.y + label_height
squidge(i+1,needy)
}
squidge(0,0)

// console.log("ys_labels: ",map(lab => sex({},lab,'y,further'),ys_labels))
return ys_labels
}

This most basic bulldozing algorithm took a few tries.



Perhaps why good_width follows wrapperx so closely is because it is increasing.
You can see good_height fall towards wrappery before height is conservatively inched down.
Wi is width being tweened - we get an occasional intermediate value of it.

All looks okay? How about height not being put so low at the end... The way wob_height disappears it seems like our algorithm sort of fails.

Many things to look into there, eg:

// see if what we set it to before (sizehop) is close enough to our current guess (ge)
// this should avoid lots of slight adjustments around wobbling geo
let close_enough = 1
map((k) => {
let wob = getwobble([de[k],sizehop[k]])
if (isNaN(wob)) debugger
let far = wob > de[k]/4
if (far) close_enough = 0
}, ks)

But lets try and tidy our frenzy of browser activity:


Well, our chart comes out at 4fps:

        // about 5% of the time?
if (oldness < 0.25) return verbose && console.log("freshness")

If that is decreased to 0.05 we never hit the ttl on animalsizing_loop:


But it does get around to closing the gaps at the end. The end being when wob is negligible and we settle on exactly the geometry with no padding.

I try to get there, wondering why it loops like so:

        // model chaos
// change &&
await animalsizing(ge)

So I look at the compiled javascript in devtools, and spot some spurious reactivity:


Which I work around:

if (spaciness != 'absolute') {
spaciness = 'absolute'
}
// look_selected = 0

Also here:


Updating <Chart {spam} />  is an update

Up in Code.svelte, which contains the other organs:
    setContext('Names',{})
And a unified:
    <Charting />

Then in Con.svelte (somewhere inside Code.svelte):
    ...
// send us over to Charting
// Send (contains getContext()) must be called inside component initialization
let Chart = geometricating && Send("Chart",C)
    ...
let geometricate = (ge) => {
     ...
spam.N.push(ge)
// attach charts to us, we eventually Charting
ahk(C.sc,'charts',"geo",spam)
Chart && Chart.update && Chart.update()

Yes, it must be done in two places...
Wanting to avoid complexity in Con.svelte, due to its wide use!
    Con form a repeating container pattern that we can hang layout generalisations on.

There's a whole side of things called T, which is how the control end targets certain things amongst the wild end, eg to configure a little something somewhere. It's kind of a self-consciousness layer. If we are a thing that wants to chart, here we call that geometricating.

In Charting.svelte:
let g = Named("Chart")
That makes it findable to others, via the Names context.
We define a data loader for Send to reach. It simply collects all the remotes (by name) and later insists those remotes have C.sc.charts.
g.charts indexing by C.t means we clobber C with the same name, which is probably correct.
g.charts ||= {}
g.input = (C) => {
g.charts[C.t] = C
g.update()
return g
}
Then reactivity into charts: lose the indexing, becoming a list for each.
let charts = []
g.update = () => charts = havs(g.charts)
// they have a collection C%charts.$t = spam
let list_charts = (C) => havs(C.sc.charts)

havs gives all the values as an array, ~~ perl's values %$ahash  (as a list).
Then look through it:

{#each charts as n (n.t)}
<h2>{n.t} -></h2>
{#each list_charts(n) as spam (spam.t)}
<h3>{spam.t} -></h3>
<Chart {spam} />
{/each}
{/each}

spam is not Cish, but should be. Back in Con.svelte:
    let spam = {C,t:'geo',began:now(),vers:0,N:[]}

And here's the charting, struggling with the frequency of updates:

So all this:
// sweep together (delay and singularise) calls to g.update()
let updating = null
let updatingHz = 2
g.update = (to) => {
if (!updating || updating != to) {
if (!updating) {
// the first call comes back:
updating = {}
setTimeout(() => { g.update(updating) }, 1000/updatingHz)
}
}
else {
updating = null
charts = havs(g.charts)
updated++
}
}



Ah! Nice and calm.

springs

Apparently for values that change a lot, spring() will look better.
I also visually indicate wrapper|spacer size, as they seem to go hectic now:

So I snip off my padding logic:
// desired shape of spacer, given recent turmoil
let de =
// good_size(ge)
ex({},ge)



Updating