Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Roadmap #345

Open
5 of 38 tasks
nicoburns opened this issue Jan 30, 2023 · 16 comments
Open
5 of 38 tasks

Roadmap #345

nicoburns opened this issue Jan 30, 2023 · 16 comments
Labels
meta About the project itself

Comments

@nicoburns
Copy link
Collaborator

nicoburns commented Jan 30, 2023

I thought it might be useful to track possible future feature work in a more structured way (grouped into categories).

See also: the Taffy Project Board

Future

CSS / Web layout features

Non-CSS layout features

API Enhancements

FFI / Bindings for other languages

  • C bindings #399 (widely useful)
  • Wasm bindings #241 (Web/Node.js/Deno) Useful for examples/playground. Also enables Node.js where Taffy may be useful for TUIs. Deno even has GUI bindings)
  • Swift/Objective-C (for iOS/macOS)
  • Kotlin/Java (for Android)
  • C++ (widely useful, and we could expose our full LayoutTree API to C++ if we wanted to. Could enable cool use cases like close integration with layout code written in C++)
  • C# (Unity uses Yoga for layout. Could also be used in Xamarin)
@nicoburns nicoburns added enhancement New feature or request meta About the project itself and removed enhancement New feature or request labels Jan 30, 2023
@nicoburns nicoburns pinned this issue Jan 30, 2023
@shirakaba
Copy link

shirakaba commented Mar 18, 2023

Just to note that with bindings to C++ (or technically Objective-C, though would limit to iOS/macOS), it would become possible to create bindings for JSI (JavaScript Interface; a library originally designed by Meta and Microsoft for React Native).

JSI is a common interface for performing simple operations that make use of native data (e.g. calling functions, exposing HostObjects) on any JS engine. The idea is that instead of calling (for example) V8 APIs directly, you'd call the engine-agnostic JSI APIs and a corresponding V8 call would be made by the engine-specific implementation of the JSI.

As engine-specific implementations are already available for V8, JSC, and Hermes, it would allow exposing Taffy to each of them with reduced maintenance burden. The advantage over WASM is that it would work on JS engines not supporting WASM (even if only due to JIT being disabled, e.g. the App Store).

It's something I'd have an interest in helping with once C++ bindings were made! Spare time willing, of course.

@inobelar
Copy link
Contributor

I think, that pure C public interface (for FFI) is a key for making bindings for various other languages. It is common solution/strategy implemented in many projects, even in Yoga (written internally in C++, with C public interface, which used in Java/C#/JavaScript(WASM)/ObjC bindings)

@nicoburns
Copy link
Collaborator Author

I think, that pure C public interface (for FFI) is a key for making bindings for various other languages. It is common solution/strategy implemented in many projects, even in Yoga (written internally in C++, with C public interface, which used in Java/C#/JavaScript(WASM)/ObjC bindings)

Agreed that a C interface ought to be priority as it can serve as the foundation for the others (and more easily allow 3rd parties to bind to Taffy in lieu of 1st party bindings.)

@shirakaba Presumably C bindings would work for you?

@herefishyfish
Copy link

Could the JSI bindings used by https://github.com/triniwiz/nativescript-mason be reused @shirakaba?

@triniwiz
Copy link

triniwiz commented Mar 20, 2023

@shirakaba in the mason lib the iOS side is pretty much the c bindings you're looking for, wish I had a little more time to port it.

@nicoburns
Copy link
Collaborator Author

@triniwiz How come you're using cxx and jsi for Android and cbindgen and swift for iOS? They seem like completely different approaches...

@triniwiz
Copy link

It's due to how the JSI is setup in NativeScript for iOS but I'm thinking I could move things around to give me an ease up

@shirakaba
Copy link

Could the JSI bindings used by https://github.com/triniwiz/nativescript-mason be reused @shirakaba?

Oh, I hadn't realised that was @triniwiz's approach! Yeah, something exactly like that 😂🙇‍♂️

@shirakaba
Copy link

@shirakaba Presumably C bindings would work for you?

Presumably! Although I defer to Osei at this point as he seems to have got it bridged all the way to iOS/Android already.

@clarfonthey
Copy link

Commenting here since I haven't seen it shared anywhere: I assume there should also be tools to navigate the layouts, rather than simply… lay them out?

To make any one of these layouts navigable via keyboard or controller, you need the ability to, at minimum:

  1. Mark nodes as focusable/non-focusable. Taffy doesn't know what's text, what's a button, etc., and this affects navigation.
  2. Navigate the focusable nodes in order both forwards and backwards, which is what you'd do when pressing tab/shift-tab. This doesn't just navigate the children of a node, and has to be able to traverse the entire tree.
  3. Understand the nodes that are focusable around the given node in the four cardinal directions, to allow navigation with arrow keys or a controller stick.

To me, these kinds of inclusion make the most sense in this library, rather than any library that uses these trees, since they're fundamental properties of the tree itself. You can't simply lay out a second navigation tree, since you need to depend on the layout of the original tree; one simple example of this is flexbox, since that can affect whether an element is below or to the right of something, for example.

Sure, you can manually compute this data yourself by navigating the tree and checking the positions of the layouts, but that's super inefficient and I would expect anything consuming the layout data to be able to build a navigation tree at the same time as the layout tree.

Would be more than willing to help draft out the API for what this looks like and develop these features, but wanted to comment on the roadmap here first since these are pretty fundamental things that look missing to me.

@alice-i-cecile
Copy link
Collaborator

alice-i-cecile commented Dec 7, 2023

@nicopap has done more investigation into this on the Bevy side, but I don't think taffy is the right place for this abstraction: that should be handled on the UI crate's side.

@clarfonthey
Copy link

clarfonthey commented Dec 7, 2023

Okay, you think that taffy isn't the right place for this abstraction, but do you have any particular ideas how a UI crate would actually perform these operations by itself after using Taffy to generate a layout?

Like I mention, the goal isn't to be live-navigating the Taffy tree directly, but for Taffy to offer data in the generated layout on where nodes are laid out relative to each other that makes it easier for any potential UI library to generate their own navigation trees.

The only way you could do this currently, unless I'm missing something major from the API, is manually sorting the position information from the nodes yourself, which seems way less efficient than just having Taffy add in a bit of extra metadata on each node that includes that information as it's generating the layout. Since the positions of things can depend on flow, this also affects the resulting navigation tree (example I gave was buttons being vertically or horizontally stacked based upon a flex layout) and so that needs to be taken into account.

@nicoburns
Copy link
Collaborator Author

Hmm.... are you saying you want Taffy to output absolute positions rather than parent-relative positions? That is something that Taffy could feasibly do. Although we would likely do it as a pass over the data after existing computation had be completed (so it wouldn't be any more efficient than you doing it yourself).

Regarding actually having a "node above", "node to left" reference on each ndoe. I think the only way to do this in Taffy would also to manually sort the positions of the nodes. As things like absolute position can mean that a node's position isn't necessarily in any particular order. And I don't see how Taffy would compute relative positions between nested nodes. In fact, it doesn't seem obvious to me how to order such nodes at all.

The bigger problem from my perspective is that I don't think there is a single best way to do this. For example, I don't think it's usual to determine the next/previous focusable node by visual position in the document. I think it's usually done by tabindex, falling back to source order.

Taffy 0.4 (upcoming) does allow for either:

  • A user-defined context type to be stored on a node
  • A custom tree implementation to be used, in which you can store whichever custom information you like.

Which might make it a bit easier for you to implement any custom functionality you want on top of Taffy's tree.

@shirakaba
Copy link

shirakaba commented Dec 8, 2023

For example, I don't think it's usual to determine the next/previous focusable node by visual position in the document. I think it's usually done by tabindex, falling back to source order.

Yep, that's it. Though strictly speaking, that's tab navigation rather than orthogonal navigation, which is still unsolved.

The bigger problem from my perspective is that I don't think there is a single best way to do this.

For sure. I've seen loads of attempts at implementing Spatial Navigation (previously having worked in Smart TV) and there are loads of ways to go about it, each with different strengths and weaknesses. Norigin Spatial Navigation to name one, the WICG's Spatial Navigation (implemented by Opera) to name another, and also Mozilla's Spatial Navigation. Then there are frameworks from the BBC and no end of in-house frameworks from other manufacturers (like Netflix).

Some take the approach of measuring and hit-testing, while others (I assume BBC's TAL) probably take an explicit numbered grid. There are lots of problems to solve like z-index, modals, drawers, toasts, popovers, transparent container views, virtualised lists, spatial memory (going back and forth across the same path, remembering which route you came from) and at some point there comes a balance between handling all use-cases and... having an API worth using.

Given the amount of application-level context needed to handle the more complex cases, I do think it would be better handled by a framework that sits on top of Taffy, that has that full context. These days, I'd probably base upon the WICG implementation myself, though it does of course assume a DOM-capable JS environment (which of course is not necessarily what Taffy will be targeting).

@clarfonthey
Copy link

Hmm.... are you saying you want Taffy to output absolute positions rather than parent-relative positions? That is something that Taffy could feasibly do. Although we would likely do it as a pass over the data after existing computation had be completed (so it wouldn't be any more efficient than you doing it yourself).

But wouldn't orthogonal navigation not really need the absolute positions, since relationships with parents are mostly preserved in children? While CSS supports much more complicated layout structure via weird operations like the position property, my understanding was that Taffy wasn't trying to support these, and so you'd still understand things like:

  • If A is the parent of B
  • if C is the parent of D
  • if A is to the left of C
  • then the item to the left of any child of C is either a child of C or a child of A

And sure, there are other cases where you're right that you'd just have to sort things by hand, but I was under the impression that, at least part of generating the flow, you'd still be able to add at least some metadata to help out any potential UI library looking to leverage this information, even if it's only at the same nesting level and they'd have to manually compute beyond that level themself.

That said, the ability to add your own metadata to the tree does provide a good starting point for implementing this as something external to taffy that's still attached to the same tree, and it would be a good way to evaluate whether adding this into taffy itself would really make sense.

For example, I don't think it's usual to determine the next/previous focusable node by visual position in the document. I think it's usually done by tabindex, falling back to source order.

It would still be nice to, for example, have the ability to navigate nodes in a linear fashion without having to navigate the tree yourself. Of course, this could easily be done with a plugin, I think it would be nice to add some sort of helper on top of the tree structure that lets you navigate leaves with an iterator that stores its own stack.


Also just want to say thank you @shirakaba for the links on the different ways other folks have tackled this problem. It's certainly not an easy one to solve, and the main reason why I wanted to bring it up here rather than just filing specific issues is that I think there may be some way Taffy could help out with this, even though obviously a bulk of the work would still be on any UI engine that used the resulting layouts.

@adjabaev
Copy link
Contributor

[ ] Kotlin/Java (for Android)

I am actually working on this in #705, hope it helps :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
meta About the project itself
Projects
None yet
Development

No branches or pull requests

8 participants