Re: [css-houdini-drafts] Proposal: Custom functions for modifying CSS values (#857)

The Houdini Task Force just discussed `Custom functions`, and agreed to the following:

* `RESOLVED: Draft this proposal up as css-functions-api`
* `RESOLVED: TabAtkins and AmeliaBR as editors`

<details><summary>The full IRC log of that discussion</summary>
&lt;TabAtkins> Topic: Custom functions<br>
&lt;fantasai> ScribeNick: fantasai<br>
&lt;TabAtkins> https://github.com/w3c/css-houdini-drafts/issues/857<br>
&lt;fantasai> AmeliaBR: This is a proposal for a new module to have a way to have custom functions that you could use in CSS values<br>
&lt;fantasai> AmeliaBR: Math functions, color functions, things that you put in a CSS value and it evaluates to an existing value type<br>
&lt;fantasai> AmeliaBR: I sketched up a rough API in the proposal<br>
&lt;fantasai> AmeliaBR: There's been good discussion over the past few months<br>
&lt;fantasai> AmeliaBR: We separated things out into "stuff that can be easily isolated" vs. "stuff that is complicated"<br>
&lt;fantasai> AmeliaBR: Looking at existing functions we have in CSS<br>
&lt;fantasai> AmeliaBR: We have ones like the new math functions<br>
&lt;fantasai> AmeliaBR: where they take an input value and output value<br>
&lt;fantasai> AmeliaBR: end result is always the same for the parameter you gave<br>
&lt;fantasai> AmeliaBR: sin(90deg) will always be sin(90deg), doesn't depend on the element<br>
&lt;fantasai> AmeliaBR: On the other handl calc(percent + pixels) can't be evaluated until layout<br>
&lt;fantasai> AmeliaBR: So that's simple idempotent functions that can do isolated<br>
&lt;fantasai> AmeliaBR: vs ones that dpeend on DOM tree, inheritance, etc.<br>
&lt;fantasai> AmeliaBR: proposal at the time is to create Level 1 custom functions that only address the isolated idempotent case<br>
&lt;fantasai> AmeliaBR: always gives the same result for same parameters<br>
&lt;fantasai> AmeliaBR: Except that we also allow putting in custom properties<br>
&lt;fantasai> TabAtkins: Also allow *<br>
&lt;heycam> q+<br>
&lt;fantasai> AmeliaBR: There will be arguments to the function, when you use the function you will know what they are<br>
&lt;fantasai> AmeliaBR: One other issue that came up in the discussion<br>
&lt;fantasai> AmeliaBR: what is the structure for declaring your custom function<br>
&lt;fantasai> AmeliaBR: I based it on Paint API<br>
&lt;fantasai> AmeliaBR: valid suggestion that maybe that's overkill and doesn't need a custom class<br>
&lt;fantasai> AmeliaBR: and maybe just need a registration object<br>
&lt;fantasai> AmeliaBR: in this case one of the items of those configuration object would be an actual JS function<br>
&lt;fantasai> AmeliaBR: that's a point of debate<br>
&lt;fantasai> AmeliaBR: Qeustion is do we go with class-based API or simple config option<br>
&lt;fantasai> myles: Runs in a worklet?<br>
&lt;fantasai> AmeliaBR: Yes, actual evaluation of function would be in a worklet<br>
&lt;fantasai> AmeliaBR: either way we need some isolated module so the function is defined in the global scope<br>
&lt;fantasai> AmeliaBR: So doing custom property where you're registering all the data in the main thread doesn't work because the function you're including has to be in a separate module<br>
&lt;fantasai> myles: Style resolution can be multithreaded<br>
&lt;fantasai> myles: Is that compatible with this proposal?<br>
&lt;fantasai> heycam: Our style resolution is multithreaded<br>
&lt;fantasai> myles: potentially one day ours might be too<br>
&lt;fantasai> AmeliaBR: So long as you do dependency calculation for cross-references<br>
&lt;fantasai> AmeliaBR: have to think of those dependencies<br>
&lt;fantasai> AmeliaBR: but function itself is very isolatable<br>
&lt;fantasai> TabAtkins: Ths is basically JS-computed var functions<br>
&lt;fantasai> TabAtkins: ...<br>
&lt;fantasai> emilio: Style resolution includes value computation<br>
&lt;fantasai> iank_: Architecturally this would be impossible<br>
&lt;fantasai> myles: Paint has the same requirements<br>
&lt;fantasai> iank_: Paint has the ability to run on multiple hreads<br>
&lt;TabAtkins> q?<br>
&lt;emilio> q+<br>
&lt;bkardell_> s/hreads/threads<br>
&lt;astearns> ack heycam<br>
&lt;fantasai> heycam: I was going to ask about the worklet stuff as well<br>
&lt;fantasai> heycam: Is it that we have to wait for worklet to synchronously finish its computation<br>
&lt;fantasai> heycam: e.g. on getComputedStyle?<br>
&lt;fantasai> heycam: Is that also what happens with layout?<br>
&lt;fantasai> iank_: If you call layout, we'll synchronously wait for it to finish<br>
&lt;fantasai> TabAtkins: have to run layout on getComputedStyle for width<br>
&lt;astearns> ack fantasai<br>
&lt;TabAtkins> fantasai: If the value can't change on properties of the element, etc, what are the intersting things we can compute here?<br>
&lt;emilio> fantasai: If the value can't change the properties of the elements and what not what's this useful for?<br>
&lt;emilio> ... it cannot even depend on lengths<br>
&lt;emilio> AmeliaBR: custom color mod functions, custom math functions<br>
&lt;emilio> TabAtkins: because we're waiting for computed value time, your ems are fine for example<br>
&lt;emilio> ... we can resolve lengths beforehand<br>
&lt;emilio> fantasai: oh you can resolve lengths<br>
&lt;emilio> AmeliaBR: yeah, not percents since they depend on layout<br>
&lt;fantasai> s/resolve lengths/resolve lengths; I had the impression from Amelia that you couldn't because length resolution varies per element and depends on e.g. font resolution<br>
&lt;emilio> TabAtkins: the restrictions mean that it's not guaranteed for your function to be called for every element that matches it if they have the same input<br>
&lt;emilio> emilio: then how does that work with multi-threading?<br>
&lt;emilio> TabAtkins: you're not required to not call the function multiple times<br>
&lt;heycam> q+<br>
&lt;emilio> AmeliaBR: you always get the same result<br>
&lt;emilio> emilio: but you can't guarantee that<br>
&lt;fantasai> ...<br>
&lt;fantasai> TabAtkins: Because you can invalidate apainter whenever, if you use random value it can flicker<br>
&lt;fantasai> TabAtkins: same result here<br>
&lt;fantasai> AmeliaBR: We can't force the Web author to write idempotent functions<br>
&lt;fantasai> AmeliaBR: But can say browser is allowed to assume the function is idempotent<br>
&lt;fantasai> emilio: If they write a non-idempotent, am I allowed to eat their laundry?<br>
&lt;fantasai> dbaron: invalidation thing is useful for debugging<br>
&lt;fantasai> [emilio's comment got lost in translation]<br>
&lt;fantasai> myles_: ...<br>
&lt;fantasai> AmeliaBR: if you look through issue discussion, brainstormed some ways that you could define just the right amound of randomness<br>
&lt;fantasai> AmeliaBR: do you want random per element -- same element gget same result<br>
&lt;TabAtkins> s/.../so how do you implement random() with this?/<br>
&lt;fantasai> AmeliaBR: or random per element + property -- different result per property?<br>
&lt;TabAtkins> TabAtkins: you can't implement random() at this level<br>
&lt;fantasai> AmeliaBR: That's part of the thing that's too complicated to deal with right now<br>
&lt;fantasai> TabAtkins: Have plans for that, but not worry about that right now<br>
&lt;fantasai> TabAtkins: want to handle things like more math functions without going through WG<br>
&lt;fantasai> myles_: So hashing?<br>
&lt;majidvp> q+<br>
&lt;fantasai> TabAtkins: yeah<br>
&lt;emilio> ack emilio<br>
&lt;fantasai> AmeliaBR: This is all about saying that browsers have a set of things they're looking at for when result will be invalidated, then it will be rerun<br>
&lt;fantasai> AmeliaBR: They can also rerun whenever convenient<br>
&lt;fantasai> AmeliaBR: that's the contract to authors<br>
&lt;Rossen_> ack heycam<br>
&lt;fantasai> heycam: This might already be partially answered by what happens in custom layout<br>
&lt;fantasai> heycam: but what happens when worker throws exception or times out?<br>
&lt;fantasai> TabAtkins: invalid at computed value time<br>
&lt;fantasai> heycam: also the case that with custom layout, you just have to wait until browser decides it wants to recalculate that it will try again?<br>
&lt;fantasai> TabAtkins: whenever your inputs are changed, we invalidate<br>
&lt;fantasai> TabAtkins: or whenever the browser feels like it<br>
&lt;fantasai> myles_: wouldn't want it to be observable<br>
&lt;fantasai> TabAtkins: If you had something that mapped out random &lt; .5 throws exception<br>
&lt;fantasai> TabAtkins: "please run me again I'll do better!"<br>
&lt;fantasai> TabAtkins: browser will run whenever not because you failed<br>
&lt;fantasai> myles_: ...<br>
&lt;fantasai> TabAtkins: randomness is ill-defined<br>
&lt;Rossen_> q?<br>
&lt;emilio> q+<br>
&lt;myles_> s/.../presumably this would have the same thing as custom paint where it would throw away the world every so often?<br>
&lt;fantasai> majidvp: When I sw this proposal immediately what came to mind is our discusison yesterday about easing functions for animations<br>
&lt;fantasai> majidvp: The current use case is focused o nstyle resolution<br>
&lt;fantasai> majidvp: but idea of stateless function with results cachced<br>
&lt;fantasai> majidvp: is similar to what we want fo reasing<br>
&lt;fantasai> majidvp: I'm interested to see if we can make the design such that it can be used for ?<br>
&lt;fantasai> majidvp: example, one could have ?<br>
&lt;fantasai> majidvp: you don't bind all the arguments at styele resolution<br>
&lt;bkardell_> s/?/partial currying<br>
&lt;myles_> q+<br>
&lt;fantasai> majidvp: create function with some paratmeters bound at style resolution<br>
&lt;fantasai> majidvp: and one varible, % progress, that gets fed in<br>
&lt;fantasai> AmeliaBR: way to think about it is, easing fucntion in CSS is a function that returns as its value an f(x) type function<br>
&lt;fantasai> AmeliaBR: custom CSS function could return a function that was used as an easing function<br>
&lt;fantasai> AmeliaBR: to do that, we'd need a TypedOM representation of an easing function<br>
&lt;fantasai> AmeliaBR: Would be useful to create a custom easing function<br>
&lt;fantasai> AmeliaBR: right now they're defined in a string<br>
&lt;fantasai> AmeliaBR: but custom one, already talking about<br>
&lt;fantasai> AmeliaBR: knock out lost of use cases for custom animation worklet<br>
&lt;fantasai> AmeliaBR: wrap it up in a TypedOM object<br>
&lt;fantasai> AmeliaBR: then your function in this proposal would return such an object<br>
&lt;fantasai> AmeliaBR: that represents the easing function<br>
&lt;fantasai> myles_: Why can't you animate the input?<br>
&lt;fantasai> AmeliaBR: I think there's some circulatrity there<br>
&lt;fantasai> TabAtkins: This proposal is not meant to produce new value ypes<br>
&lt;fantasai> TabAtkins: takes input to provide existing value type<br>
&lt;fantasai> TabAtkins: if we need some new type of value, that would be a separate proposal<br>
&lt;fantasai> TabAtkins: once accepted could be something these functions can output<br>
&lt;fantasai> AmeliaBR: Myles was saying ...<br>
&lt;fantasai> AmeliaBR: converting your x progress to the change you want to have<br>
&lt;fantasai> AmeliaBR: indirect way to get what you want<br>
&lt;fantasai> majidvp: basically bypassing web animations machinery<br>
&lt;fantasai> ...<br>
&lt;Rossen_> ack majidvp<br>
&lt;fantasai> TabAtkins: You can use a transition delay to set exactly where in the animation you want to be at that moment<br>
&lt;emilio> ack emilio<br>
&lt;fantasai> ?: Thing deciding your animation position is being decided by another animation<br>
&lt;fantasai> myles_: We have that in animating custom properties<br>
&lt;fantasai> myles_: you animate custom property x from 0 to 1<br>
&lt;fantasai> myles_: you say left: custom-function(..x)<br>
&lt;fantasai> ?: will come up with the ?? proposal<br>
&lt;fantasai> flackr: ...<br>
&lt;AmeliaBR> `.el { width: custom-func(0px, 100px, var(--x)); --x: 0; transition: x 0.3s linear;} .el:hover { --x: 1}`<br>
&lt;fantasai> s/?:/flackr:/<br>
&lt;fantasai> s/?:/flackr:/<br>
&lt;fantasai> myles_: Do we need extra facilities?<br>
&lt;fantasai> myles_: are we going to try to make custom functions return more functions?<br>
&lt;fantasai> majidvp: no<br>
&lt;fantasai> majidvp: I don't think we should do that, was just thinking<br>
&lt;fantasai> majidvp: happy to limit right now<br>
&lt;fantasai> AmeliaBR: Right now custom functions return TypedOM objects<br>
&lt;fantasai> AmeliaBR: if we later have TypedOM objects for easing functions, it'll come along for the ride<br>
&lt;Rossen_> ack myles_<br>
&lt;fantasai> myles_: In the GH issue it shows that the return type is a single type<br>
&lt;fantasai> myles_: but a CSS variable can expand to a sequence of things<br>
&lt;fantasai> TabAtkins: No we don't need a return type if we build on variable machinery<br>
&lt;flackr> s/.../This will come up with our resolution on #869 where we can animate property --x from animation A and read that property in animation B to produce property --y.<br>
&lt;fantasai> TabAtkins: you can output arbitrary, if you want to do that with TypedOM, you represent it as CSSUnparsedValue<br>
&lt;fantasai> AmeliaBR: Not as usefut to return an unparsedValue<br>
&lt;fantasai> AmeliaBR: but I expect TypedOM to return lists ad other complex types<br>
&lt;fantasai> emilio: does this mean these nee to be handled like variable references<br>
&lt;fantasai> TabAtkins: yeah<br>
&lt;fantasai> TabAtkins: you look sad :(<br>
&lt;fantasai> emilio: No, it's OK<br>
&lt;fantasai> s/OK/fine<br>
&lt;Rossen_> q?<br>
&lt;fantasai> emilio: but that means the input can be anything as well<br>
&lt;fantasai> emilio: so same implications that ppl complain about<br>
&lt;fantasai> AmeliaBR: same resolutions as references in paint<br>
&lt;fantasai> TabAtkins: I still should change that to be not like variables, but at least for now will be more like variables. Can add more strongly typed later<br>
&lt;fantasai> TabAtkins: Questions like "what happens if throws an error" get answered that way<br>
&lt;AmeliaBR> s/change that/change env()/<br>
&lt;fantasai> ...<br>
&lt;fantasai> emilio: How do you resolve relative units?<br>
&lt;fantasai> emilio: If input is unparsedvalue<br>
&lt;fantasai> heycam: inputs are typed<br>
&lt;fantasai> emilio: so input syntax is in the definition of the function<br>
&lt;fantasai> TabAtkins: Yes. Unless you say *. But if you say &lt;length> ems will resolve<br>
&lt;TabAtkins> q?<br>
&lt;fantasai> TabAtkins: I think I'm ready to write a spec for this if no one objections<br>
&lt;fantasai> AmeliaBR: I will happily let you the work, but also happy to continue involved<br>
&lt;fantasai> bkardell_: co-editor involved?<br>
&lt;fantasai> AmeliaBR: sure<br>
&lt;fantasai> [naming discussion]<br>
&lt;fantasai> myles_: This has a bunch of JS stuff too<br>
&lt;fantasai> Rossen_: So proposed resolution is Tab and Amelia to co-edit CSS Custom Functions<br>
&lt;fantasai> [more naming discussions]<br>
&lt;bkardell_> ?<br>
&lt;fantasai> bkardell_: I like keeping custom in there because it's not immediately clear to everyone that -- is our universal custom thing<br>
&lt;fantasai> bkardell_: so ties it in that way with custom properties<br>
&lt;fantasai> css-functions<br>
&lt;TabAtkins> css-functions-api<br>
&lt;fantasai> function-api<br>
&lt;dbaron> CSS Value Functions (as fullname)<br>
&lt;bkardell_> sepia-mode<br>
&lt;fremy> +1 to &lt;css-funcs> CSS Value Functions<br>
&lt;bkardell_> +1 css functions api for the short name<br>
&lt;Rossen_> CSS Custom Functions<br>
&lt;fantasai> bkardell_, did you mean css-functions-api<br>
&lt;flackr> +1 css-functions-api<br>
&lt;fantasai> ?<br>
&lt;bkardell_> yes<br>
&lt;bkardell_> I am saving all my dashes fantasai  for custom things<br>
&lt;AmeliaBR> short &amp; sweet, css-functions<br>
&lt;fantasai> RESOLVED: Draft this proposal up as css-functions-api<br>
&lt;fantasai> RESOLVED: TabAtkins and AmeliaBR as editors<br>
&lt;bkardell_> also resolved to include Custom in the title?<br>
&lt;fantasai> Rossen_: That's it for Houdini<br>
</details>


-- 
GitHub Notification of comment by css-meeting-bot
Please view or discuss this issue at https://github.com/w3c/css-houdini-drafts/issues/857#issuecomment-499980921 using your GitHub account

Received on Friday, 7 June 2019 17:57:40 UTC