#Next Generation Scenes

1 messages · Page 6 of 1

rare whale
#

Floating elements are still useful for their original, narrow use cases: having text flow around images.

slender lion
rare whale
#

The first time I read about flexboxes in CSS, my immediate reaction was "why didn't we have this 10 years ago? Every other GUI framework has rows and columns already."

karmic rock
#

from unity:

thick slate
slender lion
rare whale
loud mural
thick slate
#

(I wouldn't bother with stretch / any resizing for our anchor impl)

thick slate
karmic rock
rare whale
#

If you look at that Java article, you'll notice that all 8 of the options are just flexboxes or grids (nested in some cases) - IOW, flexbox is just a generalization of what preceded it.

slender lion
#

yeah, this anchor thing looks like absolute positioning afaict. The unity page requires you to have an absolutely positioned box, that then children define absolute offsets from.

#

pre-defined width/height, etc

karmic rock
#

It's not absolute, you have center and right

#

It's relative to an anchor

slender lion
#

I'll give you center, but top/left/bottom/right exist in absolute positioning

karmic rock
#

ah yup, that's true

leaden dew
#

i think that's the only part of the terminology that consistently wrecks me, everything else like start/end is fine

karmic rock
#

Maybe it's because I'm not a native english speaker, but justify-anything is not intuive to me at all

slender lion
karmic rock
#

main axis or secondary axis would've been better

slender lion
#

yeah maybe

karmic rock
#

another option would've been to add dedicated halign / valign and forego the flex-direction thing

#

I get why they did it, but it's confusing because it makes everything you do context dependent

autumn bane
#

I wrote a rant but suffice it to say I would love to drop the dubious naming of CSS flexbox properties even if we keep the concepts. It might have made sense at the time in the context it was made, but it is.... neither elegant nor clear.

#

While I enjoy knowing the right incantation to center something in bevy_ui, I don't enjoy the part where people not fresh off CSS will 100% have to look up wtf AlignItems vs JustifyContent means.

cobalt stone
#

I really like flutter and gtk's layouts systems. They're not as powerful as css, but simpler cases are much easier.

loud mural
slender lion
karmic rock
#

Maybe a better model would be to have a small number of common layout options with intuitive names, and for everything else heavily rely on calc

slender lion
#

having "layout components" is pretty common in the web world, even for things like Flex, etc. Someone could create <Grid>, etc for preset layouts

nocturne lotus
rare whale
#

In fact, part of my goal for feathers - which I prototyped, but which did not make the 0.18 cut - was to start working on a set of "standard containers"

#

Another point I want to make about CSS, is that some of the confusion occurs when we have gaps where we are missing a feature of CSS that people would expect to be there. Working around the missing piece often requires diving deeper into the guts of layout to find an alternate solution.

rare whale
slender lion
viral roost
#

I feel CSS alignment comes with all the baggage of CSS history, I think it's better for Bevy UI to be its own thing and well documented in the new book (yes take inspiration from existing systems, but don't be trapped by it)

crude pawn
#

I feel really comfortable with CSS nowadays, but it's very easy to forget how much of a struggle it was to work with initially

glossy tide
#

Interesting. How did you do the FFI? A lot of people have been asking for C/C++ bindings to Taffy, but I haven't gotten around to making them.

#

I've been thinking about it as a small extension to absolute positioning that allows you to choose which part of the box the absolute position applies to (although CSS has it's own anchor positioning which is way more complex)

glossy tide
#

FWIW, my latest thinking on how to integrate a "morphorm-like" (which is also GTK-like, Iced-like, etc) layout mode into Taffy, is to stick with the CSS box model (padding/margin/border) but to add a new unit that is defined as "a proportion of available space" (kinda like the fr unit in CSS grid, but which can be used for width, height, etc. The aim would be to create a mode that could potentially be upstreamed back to the web (and implemented in actual web browsers).

#

There are some complications around things like wrapping (flex-wrap), because if you have a container with wrapped contents then it's not obvious how you ought to define "remaining available space"

#

But I think these are solvable

glossy tide
# viral roost I feel CSS alignment comes with all the baggage of CSS history, I think it's bet...

Bevy could probably get away with just renaming the alignment properties (and seperating the Flexbox and CSS grid ones). IMO CSS properties are confusing mostly because they try to abstract over Flexbox coordinates (main and cross axes) and CSS Grid coordinates (inline and block axes). That's how you end up with "align" and "justify" that don't intuively mean anything to anyone. I think if had align_main and align_cross for flexbox and align_inline and align_block (or even align_x and align_y if we don't care about vertical writing modes) for CSS Grid, then it would be pretty intuitive.

#

I guess perhaps we would also need to make the "content" (rows/columns) vs "items" (children within each row/column) distinction clearer.

golden notch
silver bramble
#

Is there something planned for gather data from children on spawn?

The event hocks

pub fn on_add(mut world: DeferredWorld, ctx: HookContext)

seem to not have the children setup when the hook is executed.

copper dragon
#

With singleton entities as resources are we gonna have resources be setable in bsn files?

tawny stone
#

Just FYI, the latest version of morphorm now implements the auto layout strategy from figma, because I really like designing with it. The implementation is pretty much complete, but the documentation is lacking. There is a guide in the vizia book though. To be honest I don't know what this means for the future of any taffy integration.

dense timber
#

My friend just heard BSN and decided it can be pronounced Bassoon

#

What are the odds that can be the official pronunciation of the format name? smileyyyy

split harness
#

everyone already hates me for calling it "b-scene"

silk lava
#

Well considering cart wants it to be BevySceNe I dont think so lol

#

Darn ninja'd

split harness
queen oak
#

You've lost this battle heh

split harness
#

and critically "bee ess enn" means nothing on its own

rare whale
#

I posted some thoughts on what a binary BSN might look like in bevy discussions; I proposed bsb (Bevy Scene Binary) for the binary format, and fortunately that file extension does not appear to be used by anything.

silk lava
#

Eh, just wait till he changes the letters for the macro bscene! 😂

split harness
#

obligatory: "this is an open conversation and I'm not a dictator unless I have to be"

#

obligatory: the board could depose me at a moment's notice

rare whale
#

So here's a story: when I was working on Faery Tale 2, I came up with the term "knowledge packages" to represent mixin behaviors for character dialogues; but someone started calling them "knowledge packets" which was one less syllable, and nothing I could do (even with my power as creative director of the project) could turn the tide.

silk lava
#

packets, what are they networked dialogues? 🤔

rare whale
#

The story of King Canute and the tide is an apocryphal anecdote meant to illustrate the piety or humility of King Canute the Great (also written as Cnut), recorded in the 12th century by Henry of Huntingdon.
In the story, Canute demonstrates to his flattering courtiers that he has no control over the elements (the incoming tide), explaining that...

split harness
rare whale
#

OK this is officially OT 🙂

dense timber
#

"In the meantime, Bassoon is an instrumental name."

rare whale
#

It will be done "Real Bas-Soon now"

karmic rock
dense timber
#

@heady sierra get in here

heady sierra
#

I'd like to apologize for the carnage I've caused

elfin surge
#

bscene is just easier to say

silk lava
#

Cart, is it possible to trigger hooks on Components added to a Scene when building it, after the Scene is ready.
Currently, wherever you spawn the Scene Root, that structure is ignored via hooks because they are run while the Scene is still building itself, which is less then optimal for certain use-cases.

#

Context: #1351602963352911963 message

slender lion
#

The issue in that thread is that you can't iter_ancestors through the top of the Scene's root into the entity with the SceneRoot in a Component hook or observer, because the hooks fire between when the scene starts instantiating and before its parented to the SceneRoot entity

silk lava
#

Yeah, I dont know the terminology or lifecycle as well as I should, but the above code is ergonomic and I expected it to work, to find out that it actually doesn't seems like a bug from my perspective.

slender lion
#

The specific issue that started the conversation is that this line of code sets the parent after the scene is fully spawned: https://github.com/bevyengine/bevy/blob/227c2222e5d5643929e4a09789491a7e4ef9952b/crates/bevy_scene/src/scene_spawner.rs#L487

The behavior difference would be something like to set the parent after the scene root (not the SceneRoot, but the root node in the scene) has been spawned instead. Currently the code scans for "an entity without a parent" to represent the scene's root node, then sets ChildOf on it, so it would require digging into the scene to find that node earlier.

silk lava
#

But scenes are always meant to have a single root entity right? So theoretically you could spawn that entity before hand and just map it later?

split harness
#

Currently, entity spawning is done "top down", but "bottom up" makes way more sense for some scenarios

#

And notably, other engines have equivalents

silk lava
#
  1. Introduces potential multi-event requirements, if what you care about is an OnAdd Event, having to care about SceneIsReady is extra overhead to using Scenes.
  2. This would only work for Children, so other Relations would still fail. (yet another Children specialization 😢 )
split harness
#

(2) is a matter of phrasing. In theory this could be (and probably should be) generalized to any "sub entities"

silk lava
#

That could work then 👍
Although while that will allow intra-scene availability for hooks, it doesnt(?) allow inter-scene/world availability for hooks, right?

slender lion
split harness
#

given that higher level entities are generally "orchestrators" of lower-level entities, we need an "onready" event to facilitate that behavior

silk lava
split harness
slender lion
split harness
silk lava
#

We have a way to avoid hooks for relations right? Could extend that to all components, and then manually call the hooks afterwards, probably not the right choice though 😂

rare whale
#

@split harness I have some BSN questions:

  • Do you have an ETA for when there will be a new branch? I realize that you're probably recovering from release madness, and it will take you some time to catch up on all the feedback in the PR comments.
  • Don't feel that you need to do the feathers migration yourself; I can do it if you prefer. Your PoC is already validated so you don't need to do the migration again (unless you really want to).
  • There is a question about whether we should provide a non-BSN way to use feathers. For example, bevy_immediate has demonstrated an ability to spawn and control feathers widgets, and while the @cloud fog says that they can potentially work with BSN, I suspect it will be easier for them to work with components directly. If that's the case, then I presume that we want the "nicer name" to be the BSN-compatible one.
    • If BSN ends up supporting "structs as templates" I would like the "nicer name" to be the PascalCase spelling: :Button rather than :button.
    • This means we'll need to come up with a "less nice" name for the non-BSN alternative functions.
split harness
# rare whale <@153249376947535872> I have some BSN questions: * Do you have an ETA for when t...

Do you have an ETA for when there will be a new branch?
I'd like to sort this out this week, provided nothing critical comes up to derail me

Don't feel that you need to do the feathers migration yourself; I can do it if you prefer.
Cool cool. I might farm this out, although porting is a great way to ensure everything is working / to get more familiar with the current state of things.

There is a question about whether we should provide a non-BSN way to use feathers
I'm not immediately opposed to this, although I think this risks compromising (or at least, complicating) the data model. If we have a "raw component" version of feathers (ex: defined as a Bundle), that would "hide" those components from being patched.

#

This means we'll need to come up with a "less nice" name for the non-BSN alternative functions.
If / when we add PascalCase support, it would be because Button exists explicitly as a Rust type that correlates to the BSN functionality. That would free up button() to be used by the raw version.

#

that would "hide" those components from being patched.
I meant to qualify this with "if we use the raw component version inside the BSN version". We could of course fully duplicate the declaration across the two paradigms.

rare whale
summer cove
#

This is me throwing out an idea as an uninformed outsider but

#

With the new upcoming nightly rust reflection syntax

#

Couldn’t there be some automatic duplication/generation of BSN <-> code?

slender lion
#

I might've missed something in the upstream api, but I was pretty sure its the type id/type info data and such, which we already have available.

summer cove
#

yeah this

slender lion
#

yep that's the one I was thinking of

silk lava
#

Yeah, doesnt really unlock anything new I dont think, except that bevy_reflect can be less heavy by using this as a backing.

thick slate
#

But yeah, I'm not super excited about it for Bevy itself

native mesa
#

reducing macro code-gen could be a significant boost to compile times

lone sleet
#

Interestingly Bevy is mentioned as the example. Are those things meant to be solved by the MVP or future work?

If this experiment is successful, crates like bevy will be able to "just work" with arbitrary types instead of requiring authors to #[derive(Component)], #[derive(Bundle)], or #[derive(Resource)] their types just to get the bevy_reflect information built at compile-time. Crates like bevy_reflect and facet will still exist, but only as different libraries with different goals and methods for exposing reflection information.

https://rust-lang.github.io/rust-project-goals/2025h2/reflection-and-comptime.html

thick slate
#

Future work! The hope is to gradually reduce the amount that we need to maintain by finding better solutions upstream

copper dragon
heady latch
#

Yeah #[derive(Component)] seems neat to have. #[reflect(Component)] on the other hand is something I want to see gone if possible.

copper dragon
#

Yea manually flagging for reflection is the greater problem
I resisted reflection with editor for awhile cause forcing users to add reflect to everything sounded antipattern

tawdry owl
# heady latch Yeah `#[derive(Component)]` seems neat to have. `#[reflect(Component)]` on the o...

We can remove the #[reflect(_)] requirement for some known set of traits using autoderef specialization if needed. Last time I've tried it I ran into the usual problem of it not working well with generics, but other than that there shouldn't be any other problems with that approach. Removing it for all traits would require real reflection with trait support, which we'll hopefully get someday

rare whale
#

Going to go OT for a little bit: having worked in both the games industry, and the animated film industry (during my time at Nimble Collective), I find it interesting the way that the word "scene" means wildly different things in each of those fields despite the fact that both are based heavily on 3d computer graphics.

In the games industry, a "scene" is generally an adjective that is part of the term "scene graph", which I think everyone here understands.

In companies like Pixar and DreamWorks, however, "scene" is a unit of temporality and storyboarding: That is, films are composed of frames, which are grouped into shots, which in turn are grouped into scenes. A "shot" is a single contiguous "take" in which there are no jump cuts; A "scene" is a sequence of shots which take place in the same location or involve the same characters, and may have jump cuts between shots.

#

(I'm not making an argument here, just pointing out something I think is interesting)

slate pewter
#

i wonder if eventually someone will try to encode some sort of shot sequence into a bsn scene

silk lava
rare whale
# silk lava Wouldn't the Scene->Shots->Frames be a scene graph? maybe not

It could, however, I think workers in those industries tend to think in terms of more classical film editing techniques. Shots are storyboarded and rendered, and then the rendered frames are assembled after the fact. The need to switch camera positions in mid-playback is more of a game engine cut scene kind of feature.

#

(There's that word "scene" again)

lone sleet
# rare whale Going to go OT for a little bit: having worked in both the games industry, and t...

The more similar term is Mise-en-scène.

(Also sorry for the nitpick but in general film nomenclature a scene is a unit of story that doesn't necessarily imply the same time nor space. E.g. in Tenet when they are setting up the heist they have the same conversation across n different locations (do they suffer from short term memory loss???). The other way is usually true though that the same time and space implies the same scene.)

split harness
#

@rare whale: to keep the complexity of the port down (and ensure this branch is as "patchable" to 0.17 as possible), I did not include the "newer" feathers widgets that 0.17 didn't ship.

Also: theres currently two bugs to resolve:

  • The initial state of the color swatch is not synced to the "swatch color resource" when first spawned. Things "snap" to the correct value after dragging once.
  • The "alpha texture" is not rendering correctly
heady latch
#

Since I know quite a few people are burning to try the bsn! macro out in their stuff

#

checking out the feathers example, I don't love how there's a visual mix between lines that want to end in , and lines that don't

#

and Rust not allowing ..default(), is not exactly helping bavy

#

How come Node has implicit ..default(), but ButtonProps seemingly does not?

#

Is that a technical or a stylistic limitation? Is it related to the fact that one is used as a component and one as a parameter?

#

hmm GitHub's syntax highlighting is not liking this else here

#

But I love how much more concise this all is 😄

#

thanks for making sure this is patchable to 0.17, excited to port the rerecast code to BSN and give practical feedback then 🙂

heady latch
#

Next question, how come here we need to say Children before the [

#

But not here?

#

Sorry if all of this was already mentioned before 😄

#

Just trying to understand BSN better

rare whale
rare whale
#

The first two appear to be system ordering issues, trying to untangle them now

#

For each slider, there are two update systems:

  • The color_slider has a system in PreUpdate/PickingSystems::Last which computes the gradient and position from the slider value
  • The feathers demo has a system in Update which sets the slider value from the current color
rare whale
#

If I disable change detection so that the sliders are updated unconditionally, it works as expected

#

I'm able to work around the issue with a somewhat unitutive hack:

fn update_colors(
    colors: Res<DemoWidgetStates>,
    mut sliders: Query<(Entity, Ref<ColorSlider>, &mut SliderBaseColor)>,
    swatches: Query<(Ref<SwatchType>, &Children), With<ColorSwatch>>,
    mut commands: Commands,
) {
    // Check to see if sliders or swatches were added after resource has changed.
    let sliders_added = sliders.iter().any(|(_, slider, _)| slider.is_added());
    let swatches_added = swatches.iter().any(|(swatch, _)| swatch.is_added());
    if colors.is_changed() || sliders_added || swatches_added {
#

This also fixes the initial state of the color swatch, but I have no idea why the alpha pattern isn't working

#

I could do the alpha pattern as a repeating checkerboard texture, but I'd like to understand the problem rather than masking it

#

The whole alpha pattern setup is a bit of a hack, a pattern that is used in several places within feathers: because we want to avoid building APIs that requires the user to pass in a reference to AssetServer, we instead insert a marker or token or something that tells us "hey, an asset handle goes here, please fill it in when you have a chance". In the case of the alpha pattern it's an observer on the marker

#

For some reason that observer isn't firing.

#

I suspect that the whole pattern could be jettisoned with bsn, but I'd still like to understand why it's not working.

forest shuttle
#

How would bsn get around the problem? Exciting if it can. I assume you meant it could help with the problem of having to pass assetserver

rare whale
#

That's a feature

lethal juniper
keen patio
#

Maybe I should PR that to main instead, as it doesn't rely on anything next-gen-scenes-specific

keen patio
elfin surge
elfin surge
somber rivet
# keen patio I believe the reason it isn't working is because bsn internals currently inserts...

This is one of the things I really hoped to avoid with bsn. My statechart create is really sensitive to the order you build entities in a way that is unintuitive and hard to explain to users because of exactly this. This problem crops up in my main project as well to the point that I wish there was a way to add components to entities in a system, in multiple commands, that treated all of those inserts as a single bundle and resolved observers as such

rare whale
rare whale
rare whale
#

In any case, I think we need to get a ruling on whether bsn component insertion is intended to be transactional or not, this will help us decide which path to go down.

golden notch
copper dragon
thick slate
#

Various properties that define a scene in the game sense make sense to serialize and import

copper dragon
rare whale
#

I would like to give extra scrutiny to statements of the form "feature X won't be possible until we implement Y as entities.", when the actual truth may be closer to "feature X will be a lot easier" rather than "impossible".

#

The danger is when "X as entities" becomes an unnecessary roadblock.

thick slate
#

Agreed. Note that our current scene impl supports resource serde just fine

copper dragon
elfin surge
#

why aren't asset paths working here when they work in the example?

#

what might I be doing wrong?

#

does TextFont also need to derive GetTemplate?

keen patio
# elfin surge does TextFont also need to derive GetTemplate?

Yeah many of the types hasn't been migrated to Template/GetTemplate yet.
A workaround is to use the template fn which allows you to do "anonymous" templates:

bsn! {
    Text("hello world")
    template(|context| {
        Ok(TextFont {
            font: context
                .resource::<AssetServer>()
                .load("fonts/FiraSans-Bold.ttf"),
            font_size: 33.0,
            ..default()
        })
    })
}
elfin surge
#

yeah that's what I've been using

keen patio
#

I'm not even sure exactly how Template/GetTemplate would be implemented for TextFont , as the font handle is optional.
Doing a custom Template implementation requires removing Default (or Clone) from TextFont, but that may not be what we want since it does have a default.

elfin surge
#

I don't understand, if it has a default then isn't that what the template should use?

elfin surge
tribal yacht
#

So resources-as-entities are not necessary (but they are nice)

copper dragon
tribal yacht
#

I haven't looked to deeply into the bsn implementation

#

and because my branch is currently messy I can't even test how it works now

keen patio
# elfin surge I don't understand, if it has a default then isn't that what the template should...

GetTemplate is blanket implemented for Default + Clone types. So to add a derived/custom implementation for TextFont that makes use of HandleTemplate (allowing the nice bsn syntax), I guess one would first have to remove the Default impl for TextFont.
So sadly it's not as simple as just deriving GetTemplate for it 🙁

Maybe TextFont could get split up to something like TextFont(Handle<Font>) and TextStyle { size, etc... }, where TextStyle implements Default and TextFont requires a valid Handle (and uses default font if component not present)

tribal yacht
#

but how I think it currently works is this: after you spawn a resource, a hook makes sure it's the only one - replacing the previous one if it already exists. So the last definition of a resource is the definitive one. This does not concern itself with patches at all

keen patio
tribal yacht
#

(I'm half hoping to get this finished before bsn is merged, so I don't have to figure that logic out)

keen patio
#

Something like this could work until we have "resources as entities":

#[derive(Default)]
struct InsertResource<R: Resource + Clone>(R);

impl<R: Resource + Clone> GetTemplate for InsertResource<R> {
    type Template = Self;
}

impl<R: Resource + Clone> Template for InsertResource<R> {
    type Output = ();

    fn build(&mut self, entity: &mut EntityWorldMut) -> Result<()> {
        entity.world_scope(|world| {
            world.insert_resource(self.0.clone());
        });
        Ok(())
    }
}
bsn! {
  InsertResource<MyResource>(MyResource { .. })
}
split harness
# heady latch You *may* want to do a dev-announcement about this at some point

You may want to do a dev-announcement about this at some point

I'd like a bit more bake time (personally) before doing an adoption push like this. Lots of rough edges to sand off. I don't think its quite ready yet people "out of the loop" to start putting it to the test.

Is that a technical or a stylistic limitation?

Currently a technical one, but it is well-motivated. The current implementaton assumes they are standard rust code, which means you can do "anything" there. The reason we can omit ..default() for component patches is because we know with certainty that we are dealing with a struct or an enum that definitely implements GetTemplate (meaning we know we can rely on that to create an instance of it).

If we want to support arbitrary Rust expressions for function parameters, that means we can make no assumptions about what is present there. We could detect the cases where a struct is being instantiated, but we cannot (and should not) assume that it implement GetTemplate. Function parameters do not need to implement GetTemplate (this would be annoying, and adding it would provide no value). Likewise, we cannot assume that an initialized struct has a Default impl in normal Rust code. It might have no Default impl, but rely on specifying all of the fields.

I think the XProps scenario will be less weird ultimately, as our goal is to embrace type driven scene inheritance, so :button(ButtonProps { corners: RoundedCorners::Left, .. default() }) would become :Button { corners: RoundedCorners::Left }.

Should they be inlined as shown here or in an on method

I like inline observers when they are small, and factored-out observers when they are large.

split harness
split harness
magic belfry
split harness
#

I'll fill that out

split harness
heady latch
#

thanks for the explanations, appreciate it 🙂

split harness
heady latch
#

this is a neat example

#

I cannot help but think that this here is almost XML

native mesa
#

so the rule is <...> indicates a child entity and you'll generally have stuff like this:

Components
Components
Components
<Child>
<Child>
<Child>
heady latch
heady latch
native mesa
#

it's worth noting that, if we wanted to be closer to how XML does things, this would be

<Components Components Components>
Child
Child
Child
</>

this is almost exactly the opposite.

split harness
#

And notable the </> makes no sense here

#

I think over-embracing XML would be a mistake

#

It breaks down for the multi-component case, and it introduces unnecessary syntax

heady latch
split harness
#

The big fundamental difference is that children are defined inside of an element:

// alt-bsn syntax
<
  Component
  <Child>
>
// XML
<Component>
  <Child />
</Component>
native mesa
#

it's going to take a lot for me to get used to seeing > used as an end-bracket for a list of children. i do see why () is not ideal.

#

in general... i like kinda it? it's weird though. very terse.

split harness
#

In addition to removing the </ Component> which is nonsensical in a multi-component world

heady latch
#

My first read of this is that I also like it. Your examples make a very compelling point.

rare whale
#

My concern is that it looks enough like XML that you are never going to hear the end of it.

split harness
# native mesa in general... i like kinda it? it's weird though. very terse.

I agree that it increases our weirdness budget. But my defense there is "this is a weird new thing we're doing". If we pretend to be Rust too much, it creates weird friction (as we see in the current bsn impl) and if we pretend to be XML too much, it creates weird friction (as we see in the "actual XML" example)

native mesa
#

is there any way at all we could use [] instead of <>? just to increase the hamming-distance from xml?

split harness
rare whale
#

A while back I did propose [Relationship: Child, Child] but that didn't get much traction.

split harness
#

The "Rust-ey list syntax" would introduce its own weirdness

#

Especially given that we aren't using , separators

split harness
rare whale
#

I'm going to say something that might seem tangential, but I'll make the connection clear at the end. One of the limitations we struggle with currently is that our impl Bundle functions assume that a widget caller is free to add arbitrary children: for Button, any and all children are the button's label. However, for many of the more advanced widgets, like dialogs, menus, and scrollviews, the "content" or "caption" will be actually the grandchildren of the widget's root entity. The direct child is an internal entity used for layout or positioning. Other advanced widgets may have "slots" that can be filled in by sub-trees. Currently we have no syntactical support for this.

Now I realize that this is a different problem - we're talking about template parameters, not the direct construction syntax - but I wonder if solving the one might suggest a solution for solving the other.

#

That is, I wonder if one problem might be a superset

native mesa
#

I have a question. Can components follow children? Is this valid

Component
<Child>
Component
#

If not, then we don't really need the closing brace. If we wanted to be really weird we could try a prefix

Component
Component
+ Child
+ Child
++ Child
rare whale
thick slate
#

Is the < > syntax going to cause problems with generics?

native mesa
#

yeah, i am reluctantly in favor, i think. this is an odd solution but it resolves the constraints.

split harness
split harness
white lichen
#

how would nested children work with closing syntax in this example

split harness
#

<> syntax?

white lichen
#

yep

split harness
#
Node
<Node>
<
  Node
  <Node>
>
karmic rock
#

but with {} instead of <>

white lichen
#

wow im really not a fan of angular braces just standing alone on a line like that

#

i dont really want to influence this though i trust yall

native mesa
white lichen
#

it looks a lot like json

split harness
native mesa
#

Using colons to distinguish between children and properties is smart

rare whale
buoyant venture
white lichen
#

same

karmic rock
split harness
karmic rock
#

The downsides of my approach vs. BSN are (for as far as I understand):

  • you always need to add {} when defining an entity (so not e but e {})
  • you need to always put {} around components, they can't appear by themselves (so not Position: {10, 20} but { Position: {10, 20}})
rare whale
split harness
rare whale
split harness
#

{} feels very "arbitrary" to me, and because it is the "scope" syntax in rust, it is used everywhere

#

It certainly feels more familiar, but I think it comes at the cost of losing clarity of intent

native mesa
#

curly braces are used in almost all c-like languages to denote “start of object / end of object”. this use more clearly follows that convention, which is why it reads more easily to me.

split harness
#

And it is more likely to get lost in the noise of many other {} instances all next to each other

#

Also this is ambiguous:

{
  Node
  {}
}
#

Is that a Node {} or a Node with an empty {} child

rare whale
karmic rock
#

Yup, the : is what disambiguates between an entity & component value

split harness
#

Ah yeah I was just swapping <> for {}

#

I don't like that we're departing from Rust syntax in the context of defining the Rust types

#

Ideally the messaging is "use Rust syntax when defining rust types: Enum::Variant, Struct(10.), Struct { x: 10. }"

thick slate
rare whale
#

Well, we're not going to get a perfect solution that satisfies both aesthetics and familiarity, there just aren't enough ASCII delimiters available. Any solution is going to be disappointing in some aspect.

native mesa
#

to me, the difference from rust seems a lot more minor than the potential confusion with xml. how faithfully can we really hope to capture rust’s syntax anyway?

#

do we even support generics?

split harness
#

We do!

rare whale
native mesa
#

oh, neat!

split harness
# rare whale Well, we're not going to get a perfect solution that satisfies both aesthetics a...

From my perspective, we're going to be unfamiliar no matter what we pick, as we are using unfamiliar semantics. There is no mainstream syntax that captures the semantics we require. I think "<> syntax with some similarities to xml but not quite" actually serves us reasonably well:

  1. It allows us to retain some of the existing associations: <> defines an "element" (or in our case, an Entity), inside you can define multiple properties, you can nest elements under each other producing "hierarchy", etc.
  2. It is fundamentally different enough that it forces developers to fully acknowledge that it is different (ex: no closing </button>, accepts Rust types inside / uses Rust syntax inside for those types, children live inside <>, etc)
  3. Because <> is less prevalent/more scoped in the context of Rust, it reduces ambiguity / noise. Imo, Intent is much clearer, especially to newcomers, compared to a () or a {} syntax on its own
split harness
#

This feels simultaneously more "rusty" and more "nested hierarchy-ey" to me

karmic rock
#

I can't speak to the rustyness but I don't intuitively see the nested hierarchy here 🤔

#

Is this a parent with Node and BackgroundColor with two children?

split harness
#

Yup!

karmic rock
#

Why does the outer entity not need the < >?

split harness
#

A list of bsn entries would require <>:

bsn_list! { 
  // list item 1
  <Node>
  // list item 2
  <
    Node
    <Child1>
    <Child2>
  >
}
karmic rock
#

Ah ok. What is the difference between () (also delimits an entity?) and <>?

#

() is an entity, <> is in an entity list?

split harness
karmic rock
#

Ah gotcha

#

So <> always means entity (is optional for the root) and () is always a component value

split harness
#

But yeah <> always means entity

karmic rock
#

Gotcha makes sense

split harness
#

With the exception of generics: Ex: List<Item>

white lichen
#

what about square brackets?

karmic rock
#

Do you foresee any use cases for where you want to use the root for other things? Like something I do is:

// import components from namespace into current namespace
using flecs.components.*

e {
  Position: {10, 20} // flecs.components.transform.Position
}

(not suggesting you should do something like this- more whether you want to have root-level syntax not related to a root entity)

split harness
#

Theres also "trait disambiguation syntax": <Transform as Component>::on_add(), but that isn't relevant in the component-position

split harness
silk lava
#

I like it weirdly, makes finding each new entity easier.
Is a shame though that it makes short-hand Children stick out more compared to user Relations.

split harness
split harness
#

Is that an empty root or an empty child?

#

So it would need to be <> is disallowed at the root

white lichen
split harness
#

Or alternatively <> is disallowed

split harness
#

Here: #1264881140007702558 message

white lichen
#

got it

split harness
#

One benefit of using {} to indicate an entity is that it already pairs with bsn! {}

heady latch
split harness
#

But I think that is pretty powerfully cancelled out by the need to abandon Rust syntax for initializing types

split harness
#

But in most cases, that case would still benefit from <#Name> or <Marker> to identify a specific entity

silk lava
heady latch
nocturne lotus
#

too bad rust macros don't support <> brackets, bsn!< ... > would be nice

split harness
silk lava
split harness
#

The inventory case can be covered by having Inventory and InventoryContents be separate components

#

Then you can do Query<&Inventory, Without<InventoryContents>>

split harness
#

Ah but I missed the appeal of the bsn! [] matching [] entities

silk lava
#

What is the syntax name for the bsn, I cant find the right one xD

split harness
#

That would certainly be a pro

silk lava
split harness
#

I've been using rust there

#

However <> does make that work less well

#

But there were other aspects of bsn that broke naive (non-semantic-token) highlighters

silk lava
#

Huh I thought there was another one that highlighted better
Ah, it was javascript

nocturne lotus
#
bsn! [
    Node { width: px(10) }
    Inventory <
        [Item] 
        [Item] 
    >
    [Node]
]

nim works for this snippet somehow (ruby and js work too) :p

split harness
#

There might be, but I always use rust

split harness
#

But thats worth investigating

#

And its worth factoring in how rust highlighting will behave for naive highlighters (such as those on blogs / discord / github)

rare whale
#

At this point I'd be willing to drop the shorthand syntax for Children. Yes, it's an extra word, but it doesn't increase indentation in most cases. And as I mentioned before, most of my use cases have a complex relationship with children anyway. EIBTI.

split harness
split harness
rare whale
split harness
#

Just as an FYI

rare whale
split harness
#

If we're sticking with the current () syntax, I'd prefer keeping [] for terseness and adopting Children: [] to disambiguate

#

I think having Children [] everywhere would be very noisy

rare whale
#

The implicit "followers are children" feels YAML-ish to me.

split harness
silk lava
#

I am not sure we can change that at this point, I think there is more interest in it being implicit. (I prefer explicit)

split harness
#

🙂

rare whale
#

(Unrelated to this discussion, but YAML is banned for internal use at AWS because a truncated YAML file is still syntactically valid.)

karmic rock
#

Dropping this here in case it provides food for thought, I noticed that in a lot of my script code entities have a component that is very clearly the entity's "kind". I added a bit of syntax to make that more readable (and is also a bit more rusty):

div(width: 200, height: 100) {
  button(text: "Hello")
}

// same as

{
  div: {width: 200, height: 100}
  {
    button: {text: "Hello"}
  }
}

found it to work very well with UI code

split harness
karmic rock
#
div(width: 200, height: 100) {
  MarkerTag
  AnotherComponent: {10, 20}

  button(text: "Hello")
}
#

The syntax inside the { } is still the same

karmic rock
#

There's just a Component(value) shorthand for { Component: { value } }

karmic rock
rare whale
karmic rock
silk lava
karmic rock
split harness
silk lava
split harness
#
// flecs shorthand
div(width: 200, height: 100) {
  button(text: "Hello")
}

// proposed `<>` bsn syntax (1 line longer)
<
  Div { width: 200, height: 100 }
  <Button { text: "hello" }>
>
// same, but one-lining this case to save space (same length)
<Div { width: 200, height: 100 }
  <Button { text: "hello" }>
>
#

Having one way to do things does simplify the mental model

karmic rock
karmic rock
split harness
karmic rock
# split harness I see the appeal, although I'm not in love with the arbitrary nature of deciding...

It's not entirely arbitrary. Components can provide hints to the parser by providing a "default kind" for the children in the scope, so you can do:

enum Color { // default kind = constant
  Red,
  Green,
  Blue
}

// same as

enum Color {
  constant Red
  constant Green
  constant Blue
}

// same as

Color {
  enum
  
  Red { constant }
  Green { constant }
  Blue { constant }
}

It's definitely a bit to unpack, but if you have to write that code hundreds of times over, I def prefer the first syntax 😛

split harness
#

For normal "scene" use cases, I suspect that would be less relevant

karmic rock
#

But yeah, definitely most useful for type definitions

#

I see this part of the language more as a guilty pleasure :p It's much less obvious than the other stuff, but too much fun to leave out

split harness
split harness
#

More likely we would call it the InInventory(#Inventory) relationship

#

Or maybe ItemIn or ItemOf

leaden dew
#

converted the bsn in bevy/examples/ui/feathers.rs to the <> syntax to see how it feels on a "real world" scene

#

some thoughts:

  • two of the issues this syntax resolves relate directly to the Node [ ... ] shorthand (the one that doesn't use ()), but i don't think that shorthand was used once in this example - if it's causing issues, maybe just forbidding the shorthand would be an alternative
  • my brain is not prepared to read child entities and parent components on the same indentation level
  • i do think there's something lost making bsn less "rusty" - Bevy exists in an ecosystem that includes multiple very rusty syntaxes (rust, wgsl, ron) and there's a comfort there that feels bad to give up in a syntax that we expect to be a very common sight in user code
golden notch
#

going to incept slowly inventing bevy lisp notation into carts dreams tonight

leaden dew
#

i had that thought looking at this example:
Node <Node Marker <Node>><Node Marker <Node>>
it's so close to being lisp:
(Node (Node Marker (Node)) (Node Marker (Node)))

rare whale
leaden dew
#

so that people stop expecting commas to be required

viral roost
#

So my immediate feel is ick for the <> syntax

I feel that the Children [] ambiguity can be solved by removing [] shorthand and instead have e.g. @[] for children - we just call out in the docs that Children is aliased as @ (or whatever other single character). I think this is warranted as Children is such a fundamental relationship for Bevy

#

Maybe another question that's worth thinking about: how will many-to-many relationships work in bsn? Suppose I have 5 entities with #name components, how can I encode relationships between them?

#

I know they don't exist yet, but it's worth not backing ourselves into a corner

fallow cloak
#

Personally I really like the lisp-y version!

Option 2 for custom relationship syntax also seems nice. Does it have to rely on newlines/whitespace for disambiguating though? Could it just read all entity items until it reaches the next non-parenthesized thing?

#

also, would it be helpful if we had a prototype bsn grammar? Might help with alternative syntax proposals, and I need the practice for my uni class lol

slate pewter
#

i’m most worried about ambiguities with generics, struct initializers and inline expressions

rancid tangle
#

I do not mind the <> syntax but having no delimiters between components (not on the same line) feels strange/unnatural and would definitely take while to get used to (but that does not mean it is bad).

Seeing the example of Runi i would no longer vote for {}, instead of <>, given the otherwise syntax "ambiguity" of rust initializers (e.g. the first Node); i like how you can quickly differentiate between both on a glance. Same for the function call's with () (e.g. button(...), on(...)). So i like the "different syntax for different concepts".

lethal juniper
#

I also like to point that using () to identify an entity feels more natural than <> because after years of writing queries like Query<(&ComponentA, &ComponentB)> it seems strange to use <> on bsn! and () in queries.

karmic rock
spark badge
#

I may sound like a heretic, and it's not particularly rusty, but to help distance the syntax from xml, you could flip the brackets:

Node { width: 100 }
BackgroundColor(GREEN)
>
  Node { width: 10}
  BackgroundColor(GREEN)
<
>
  IsA(#checkbox)
  InteractionDisabled
  Text("Hello There")
<

It looks intuitive if formatted like this, but could break down in the later examples

>Div { width: 200, height: 100 }
  >Button { text: "hello" }<
<

extreme example:

> Div { width: 200, height: 100 } > Button { text: "hello" } < <
karmic rock
#

.<

magic belfry
#

Personally I find the <> syntax basically completely unreadable; my brain has been trained to read {}, [], and () for blocks or groups of things in programming languages, and <something>content</something> in XML/HTML, but I have never seen <> used like the proposed syntax anywhere and it's kinda breaking my brain

#

Also this one isn't a point for or against the syntax, but it's kinda funny to me that one could technically write this (assume no formatter)

bsn! {
    <Div>
        Text("Hello")
    <Div>
}

and it would actually produce a text node with two div children, rather than a div with a child text node

#

(of course this wouldn't be valid in HTML either though, since the second tag isn't closing like </div>)

karmic rock
#

It's funny, when you start designing a language it feels like you can do anything, but if you add up all the constraints and include people's sensibilities there's really only a very small number of reasonable options

magic belfry
#

what about this :P

bsn! {
    Node { width: px(100) }
    BackgroundColor(GREEN)
    // Anonymous child
    #: (
        Node { width: px(10) }
        BackgroundColor(RED)
    )
    // Named child
    #checkbox: (
        :checkbox
        InteractionDisabled
        #hello: Text("Hello there")
    )
}
#

(I still prefer the existing syntax tho)

karmic rock
#

This is probably obvious to others, but why is it not this?

    Node { width: px(100) }
    BackgroundColor {GREEN}
magic belfry
#

BackgroundColor is a tuple struct like

struct BackgroundColor(Color);
#

you need to create tuples like that with TupleName(Value)

#

in normal Rust syntax

karmic rock
#

Hm gotcha. Is that a constraint on BSN? Or could it deviate if it wanted

magic belfry
#

I imagine it could deviate, but that would be changing fundamental Rust struct initialization syntax, which I imagine Cart would be against

buoyant venture
lethal juniper
#

I don't mind the syntax <>, it's just it is a price to pay, the uncanny valley of XML/HTML, but if this solves our problem, I think we should go for it.

fallow cloak
#

We could resolve at least the ambiguity without the <> syntax ("entity delimiters"?)

#

the <> is mostly for improving the mixed commas afaict

magic belfry
fallow cloak
#

The closest to the original proposal would be something like

bsn! {
  Node [
    // normal children
  ]
  InventoryItems: [
    // inventory items, disambiguated by the ':'
  ]
}
#

I think the lisp-y version of entity delimiters would be great for the commas situation though

#

(if we can avoid adding another ambiguity)

karmic rock
# buoyant venture Being rusty is technically a design constraint of BSN, but what is and isn't rus...

You could get cheeky and reframe the scope of an entity as a regular struct scope where each "member" is a component. Basically like in my original example:

{ // parent
  Node: {width: 100}
  BackgroundColor: {GREEN}

  { // child
    Node: {width: 10}
    BackgroundColor: {GREEN}
  }
  { // another child
    Text: {"Hello There"}
  }
}

That'd still be valid Rust syntax I think, just with a different mapping to Rust concepts (removed the flecs specific stuff for clarity)

magic belfry
#

My syntax was inspired by the flecs syntax above, except instead of a "kind" there is just the (optional) name before the :

autumn bane
karmic rock
rare whale
magic belfry
#

Oh hmm we could even drop the : and just do this

bsn! {
    Node { width: px(100) }
    BackgroundColor(GREEN)
    // Anonymous child
    #(
        Node { width: px(10) }
        BackgroundColor(RED)
    )
    // Named child
    #checkbox(
        :checkbox
        InteractionDisabled
        #hello(Text("Hello there"))
    )
}
fallow cloak
magic belfry
magic belfry
karmic rock
rare whale
karmic rock
magic belfry
rare whale
#

I was thinking something like:

:DialogBox {
    header: #[
        Text("Do you want to Quit?")
    ],
    body: #[
        Text("There are unsaved changes")
    ],
    footer: #[
        (
            :Button { label: #[ Text("Cancel") ] },
        ),
        (
            :Button { label: #[ Text("Quit") ] },
        )
    ]
}

Where #[ is shorthand for {bsn_list!(...)}

lethal juniper
magic belfry
#

Ah right, nice

fallow cloak
#
bsn! {
    Node { width: px(100) }
    BackgroundColor(GREEN)
    Children: // imagine this was a custom relationship 
        (
            Node { width: px(10) }
            BackgroundColor(RED)
        )
        (
            #checkbox
            :checkbox
            InteractionDisabled
            #hello(Text("Hello there"))
        )
}

bsn! {
    Player
    InventoryItems: 
        (#MySword Sword)
        (#MyShield Shield)
}
lethal juniper
#

the removal of implicity [] for Children solves two issues: identation and the ambiguity

fallow cloak
#

ok maybe entity delimiters doesn't work as well for bigger entities 😅

lethal juniper
#

the problem/issue with Cart proposal is it try to solve a lot of problems at once, so many solutions/proposals become mixed.

karmic rock
rare whale
#

You could also pass in a variable or expression of the right type

fallow cloak
karmic rock
rare whale
#

A curried template

#

The difference between bsn and bsn_list is that the former produces a single root entity, while the latter produces a vector of entities

thick slate
magic belfry
karmic rock
# rare whale A curried template

Gotcha, that's very similar to how I was thinking about it. Will it have access to its own context? For example:

template DiagBox {
  div(class: "diag-body") {
    slot("body")
  }
}

DiagBox() {
  const padding: 4 // contrived, but example of local variables
  const width: 100

  slot "body" {
    Text("ECS Slots!", width: width - padding)
  }
}

(if there is even such a thing in bsn)

magic belfry
rare whale
karmic rock
#

Yeah the tricky part (for me at least) was that it is like passing down a template, but it needs to be executed with access to its own scope

#

Passing down that context is a bit annoying, because I don't want to inherit too much complexity from the AST

rare whale
lethal juniper
# magic belfry Alternatively, with curly brackets ```rust bsn! { Node { width: px(100) } ...

In this case, there are two ways to declare children, implicitly, by using #{}, and explicitly using Children [].

What happens with:

bsn! {
    Node { width: px(100) }
    BackgroundColor(GREEN)
    // Anonymous child
    # {
        Node { width: px(10) }
        BackgroundColor(RED)
    }
    // Named child
    #checkbox {
        :checkbox
        InteractionDisabled
    }
    MarkerForSomething
    // More child
    Children [
        Text("Hello there")
    ]
}

Would this even be legal?

magic belfry
#

Either just combine them, or return a compile error, I'm not sure why you'd mix both syntaxes in the same entity

lethal juniper
#

Users, they are just, users

magic belfry
#

We'd need to combine several # {} children anyway, so I imagine it could do the same when there's additionally Children []

karmic rock
lethal juniper
#

this has the advantage of already making room for entity ID, if this become a thing in the future, because #name_child can be also it's Name or some arbitrary ID, defined somewhere in the BSN settings

royal python
leaden dew
#

it's not perfect, but generally i like the idea of bsn being a "very sugary" syntax over typical bevy spawning code. the more similar it is, the easier it is to convert between the two formats, and the easier it is to learn and read bsn imo

#

i think <> syntax gets a little further away from that

#

using parentheses gets a little closer, comma delimiters would be even closer

split harness
split harness
split harness
split harness
# magic belfry Oh hmm we could even drop the `:` and just do this ```rust bsn! { Node { wid...

I think this is a pretty solid proposal (both #() and #{}). Retains most of the benefits of my <> proposal, with the added value of not rubbing some people the wrong way with <>. However in every way but <>-avoidance, it feels worse to me:

  1. I really like that <> fully "bounds" the entity. #Name is still a component that exists "on" the entity, so it makes sense for it to exist "inside" the entity bounds. #Checkbox is just (super-powered) sugar for Name("Checkbox"), so hoisting it out feels wrong to me. This is also notably how people think about html ids, which are filling essentially the same role (ex: <#Name Node> vs <div id="Name" />)

  2. Defining names at the root would need to be "different". We cannot write bsn! #Name (). I don't like that inconsistency. We would likely need to do the following, which reads to me like the #Root is a peer of #Child (especially when considering that in Rust Foo and Foo() are both "struct syntax"):

bsn! {
    #Root
    #Child()
}
  1. Anonymous entities (which will be very common) require one more symbol (#{}) compared to <>.

  2. Because # comes first for children, people will come to associate # syntax both as the "child entity designator" and the "entity name sugar". This overloads the semantics in a way that I don't love.

  3. () and {} are still very common symbols. We're losing out on having a distinct "entity bounds" symbol.

split harness
split harness
karmic rock
#

Right, I am not as used to the rust syntax so to me using a different delimiter for component values looks weird, but I can see how that's different if you come from rust

split harness
#

I do think the <>-aversion will come up regularly. Which is a shame because I think it is the "best" option

crisp garden
#

Why we wrapping values in <> thonk

split harness
#

I also think the <> aversion is "just" because it isn't seen as much. Its the kind of thing people would get used to. But I do suspect it would color first impressions

karmic rock
#

So I guess it's more about how badly you want tuple type assignments to be explicit

split harness
#

But yeah thats a matter of opinion

karmic rock
#

language mutation
Is it though? You have to map something that doesn't exist natively in the language (an entity->component relationship) to something that exists in the language. What you map it to is kind of arbitrary. There are ECS frameworks out there that let you access components as if they're members on an entity

crisp garden
karmic rock
crisp garden
#

Now ofc neither is really rust, since it represents this:

(
  Component {a: 10, b: 20},
  BackgroundColor(Green)
)
split harness
karmic rock
crisp garden
#

If the only problem with the proposal is <> we could just use any other random delimiter, we could even use ^$ and make everyone think it's a regex instead super_bavy

split harness
#

I still think <> is the best choice, as it is already the open/close syntax for "markup language elements"

#

Which is what this is

silk lava
#
bsn!{
    Node{width: 100, height: 200}
    BackgroundColor(CYAN)
    Inventory [
        (Item Name("Spear"))
        (Item Name("Axe"))
    ]
    (
        Node
        Text("Text Here")
    )
}

Could keep the old syntax, and enforce () for entities and Children short-hand is root-level entities.

split harness
magic belfry
#

Cursed idea / not a serious suggestion; what if we allowed both RelationshipTarget [] and RelationshipTarget(), where the former takes a list of entities, and the former latter takes a single entity. This would at least kind of address the extra indentation problem, if nothing else 😛

bsn! {
    Node { width: px(100) }
    BackgroundColor(GREEN)
    // One child
    Children(
        Node { width: px(10) }
        BackgroundColor(RED)
    )
}

(I don't actually like this, still kinda verbose and confusing especially if you want many "inline" children like this)

split harness
# silk lava Theres a space in between?

Yes, but (1) thats a pretty easy mistake to make that would result in confusing results and (2) Rust is not a language where whitespace is semantically relevant.

silk lava
split harness
#

We could bend that rule here, but it would be a departure

crisp garden
#

Yea the way Rust handles all the ambiguities that arise here is by putting (almost) commas everywhere

#

(Or turbofish in the case of generics)

split harness
#

Ah shit yeah current proposal also relies on whitespace reliance:

Node
<Node>
#

Although maybe not actually. I believe that currently requires turbofish: Node::<Node>

magic belfry
#

-# (I'll just ignore that in HTML you can also do <br> without explicitly closing it)

split harness
#

I just aspired to defeating the turbofish in bsn

split harness
#

And that we're pulling in "undesired context" in addition to "desired context"

queen oak
crisp garden
#

-# The turbofish is not to be defeated, but to be worshipped

queen oak
#

OH its so bad compared to the joy and beauty of the previous syntax 😭

split harness
#

Haha I didn't find this bit particularly joyful:

crisp garden
split harness
#

There were a lot of unreconcilable rough edges

crisp garden
#

Time for commas!

bsn! {
    Node { width: px(100) },
    BackgroundColor(GREEN),
    (
        Node { width: px(10) },
        BackgroundColor(RED)
    ),
    (
        :checkbox
        InteractionDisabled,
        Children [
            Text("Hello there")
        ]
    ),
    (Node { width: px(10) })
}
magic belfry
#

[] is very clear to me as "an array of entities", and () is very clear to me as "a bundle of components", practically the same way it would be with e.g. the children! [] macro

#

<> says nothing except "generics" or "XML-like templating"

lethal juniper
#

Cart made a good point about how #{} would make inconsistent the naming of entities with inside and outside of it's declaration. I think it is a valid point to be concerned. since it would be nice if we could ID the entity just as any component, maybe in the futre, having a special trait that could be used to unique identify that entity which any component that implements this trait, and using #my_custom_id, I don't know, just wondering the possibilities.

#

If we consider that we wanna #id to be inside the declaration of the entities, together with components, what are our options, aside from <>?

crisp garden
#

All #{}/#() tells me is that I'm doing proc macros, which is not a good for the average rust dev ferris_sob

silk lava
#

Yeah I dont think pre/post-fixing the entity/'s components, like how flecs does it, is a good idea personally

queen oak
#

Could we use {{ and }} as a new kind of separator? 🤔

silk lava
#

No double character symbols pls

magic belfry
#

we could just do syntax sugar with @ or $ (ew jquery) or something I guess

bsn! {
    Node { width: px(100) }
    BackgroundColor(GREEN)
    // Children
    @(
        Node { width: px(10) }
        BackgroundColor(RED)
    )
    @(
        :checkbox
        InteractionDisabled
        @(Text("Hello there"))
    )
}
karmic rock
silk lava
karmic rock
silk lava
lethal juniper
#

so at this point, it's a trade-off between @() or anything + braces/brackets, vs <>. I think the weirdness of <> makes it a good candidate, since it will be unique and have no conflicts with other semantics in the future (aside from generics, but turbo fish is out there)

karmic rock
silk lava
karmic rock
#

That's a bit of a self inflicted problem tho

#

Which is easy to solve

split harness
silk lava
#

Also, I prefer all of the data to be inside of the entity syntax

karmic rock
split harness
karmic rock
#

Right, it's 2 extra characters in what is probably going to be very large documents

split harness
#

Theres also the "benefit" (there are pros and cons) of "list syntax" and "single-root" syntax looking the same, other than one vs many

#

ex: currently they are "different":

bsn! {
  Node
  <Node>
}

bsn_list! {
  <
    Node
    <Node>
  >
}
silk lava
#

Does a canonical root need to exist for a BSN, inside of the BSN or could the BSN always create one implicitly for itself, meaning you could have multiple 'root' entities, but would always be spawned under the implicit BSN entity.
Could potentially merge the list vs single syntax then (although there might be problems with the traits/impls still)
Guess then you would have extra BSN entities that would be just for metadata storage 🤔
Nvm guess it doesnt really work when using them as patches on a single entity

crisp garden
#

Oh no, that "feature" from the current scene system

split harness
#

Thats not something I want to give up personally. Although whether that is enforced statically (bsn! vs bsn_list! vs bsn_set!) or at runtime (everything is bsn! and we fail if there is no canonical root and one is expected), is an open question

#

I think statically gives us nicer guarantees (and skips some runtime checks / simplifies representations), but I see the appeal and simplicity of having a single bsn!

karmic rock
#

But not unreasonable ig. HTML also has <html>

keen patio
magic belfry
#

why do I not entirely hate that lol

#

better than the <> syntax at least

crisp garden
#

It looks like quote syntax on discord, or maybe a terminal prompt

keen patio
#

Yeah now that I look at it, it actually reads pretty nice 🤔

white lichen
#

is all this syntactical gymnastics just to avoid writing Children sometimes

magic belfry
#

and to reduce over-indentation and newlines

#

and "child misalignment"

split harness
white lichen
#

i did read this

karmic rock
rare whale
# split harness Have you tried porting the `feathers.rs`example to `Children []` everywhere? I h...

Getting back to this for a moment: I think that if the feathers example were properly written, there would be about half as many Children than there is now. The reason there are so many is because every button has a text label child. But I would rather see buttons as having a "label slot" or "caption". Sure, in the case of buttons, you can assume that the children of the button is the contents of the button. However, I don't think that is a good habit for users to get into, because for many widgets just blindly adding children will break them.

#

Now, even with half as many children it might be argued that this is too many instances of Children and that it deserves a dedicated shortcut.

keen patio
white lichen
#

so, as far as i understand it the () inside the Children [] currently is superfluous and was added because a comma alone is easy to miss, but now the complaint is that its too noisy.

magic belfry
white lichen
#

is this not good?

Children [
    Node { width: px(10) }
    BackgroundColor(RED),
    Node { width: px(10) }
    BackgroundColor(RED)
]
#

like we can put the comma on its own line if we want it to be more visible

lethal juniper
#

the point is it become too verbose to always write Children []

#

I would prefer to use <> instead of having to type dozens of Children []

white lichen
#

i disagree with that tbh

lethal juniper
#

that's fair

silk lava
rare whale
#

I would even go so far as to say that most widgets want to be able to accept interior entities as parameters, and those entities will not be direct children. A typical dialog box for example:

  • Full-screen barrier element (absolute positioned)
    • Dialog box frame (Flexbox / Column)
      • Header slot
      • Body slot
      • Footer slot
white lichen
#

we can have a shorthand for Children and not completely replace relationship syntax

#

i dont like the idea of Children being extra extra special among relationships

silk lava
lethal juniper
white lichen
#

as far as i can see the two complaints are

  1. Children is verbose
  2. too much indentation/parens
    and i feel that 1. is resolved by one of the various "just use some symbol like # that expands to Children" and 2. is basically self inflicted by not liking commas
keen patio
lethal juniper
#

Circling back to a discussion above, #[] would be confusing, since there is already plans for # to be used to identify the entity, like #my_entity. So it would have to be @[] or something like that

keen patio
autumn bane
#

that seems very asset unfriendly

white lichen
#
bsn! {
    Node { width: px(100) }
    BackgroundColor(GREEN)
    ^ [
        Node { width: px(10) }
        BackgroundColor(RED),
        :checkbox
        InteractionDisabled
        ^ [
            Text("Hello there")
        ],
        Node { width: px(10) }
    ]
}
keen patio
lethal juniper
#

^^

white lichen
#

does ISO not have caret?

karmic rock
#

following this conversation is starting to feel like reading a chatgpt log where it's running out of context

#

maybe you can use ^ for the opening character and v for closing

lethal juniper
white lichen
#

the comma distinguishes

viral roost
#

What's wrong with commas? Bone of the biggest issues with JSON is the lack of trailing commas

autumn bane
#

I've been writing a decent amount of UI code with bundles lately, and I'd argue that indeed children! (and its fully qualified BSN equivalent Children) is very noisy and verbose. I'd encourage anyone who thinks it's not verbose to try it out and compare it to more traditional UI languages.

keen patio
lethal juniper
white lichen
#
bsn! {
    Node { width: px(100) }
    BackgroundColor(GREEN)
    ^[  Node { width: px(10) }
        BackgroundColor(RED)
    ,   :checkbox
        InteractionDisabled
        ^[Text("Hello there")]
    ,   Node { width: px(10) }
    ]
}
viral roost
white lichen
#

(not entirely serious)

keen patio
magic belfry
# magic belfry Cursed idea / not a serious suggestion; what if we allowed *both* `RelationshipT...

Vaguely related to this ^ idea, can we yeet the [] shorthand, but make () represent a single entity which, when not inside a relationship like Observers [], represents a single child entity

bsn! {
    Node { width: px(100) }
    BackgroundColor(GREEN)
    // Child entities
    (
        Node { width: px(10) }
        BackgroundColor(RED)
    )
    (
        :checkbox
        InteractionDisabled
        // Relationship syntax still works too
        Children [
            Text("Hello there")
        ]
    )
    Node { width: px(10) }
}
#

and disambiguate TupleComponent(...) from Component (...) based on the space (or can we not do that?)

magic belfry
silk lava
magic belfry
#

Oh right I guess that's the same

keen patio
lethal juniper
#

Just to try to sum things up, these are the questions/discussions to be had, which are different solutions to different problems with may or may not be related.

  1. RelationshipTarget vs Children, should it have a special short hand (like currently it has, only using []), should it be explicty at the end (like the cart proposal at #21431) or should it have no distinction between them?

  2. Entity definition scope, currently it uses a "lisp-like" approach, with (Node {} Tag Enum(A)), cart proposal is to change to <>, since when combining with (1), the current approach is ambiguous with A (Node) - Should this be a component and a Node child? or this is an Enum/newtype component ?

#

the main point is how to design those two points and all pros/cons they bring together

#

Every proposal needs to address those two points, focusing only in one will just circle back to previous discussions

karmic rock
copper dragon
#

On 2 relations are components.
If () is a entity then everything about that entity should be inside it, and only omit the () when there's only one entity.

rare whale
#

@split harness I wanted to ask some questions about the #Name syntax: In the BSN doc, it says that this is just a shorthand for the Name component. However, I think that may be a problem: consider a case where a scene inherits from another scene which has conflicting ideas about the name:

(
   #animatable
   :widget(...etc...)
}

Where widget internally assigns #othername to the same entity. This means that one or the other name will be overwritten.

#

I think it would be better if #name was locally scoped to the scene, and completely independent of the Name component (which would have no special syntax).

#

That is, the syntax #name binds the string name to the entity id, and that binding is accessible during scene construction. The binding would be short lived, any code that wanted to keep the reference around would need to dereference it into an entity id.

#

A typical use of names is to be able to designate particular entities as targets for animation or dynamic modification, cutting across the normal lines of the hierarchy.

#

However, in a world where behaviors are defined via mixin scenes, we could see conflicts where different partial scenes are attempting to assign names for their own internal purposes.

#

Or perhaps we need a different syntactical construct for the kind of use case I am thinking of. Something like React's ref param.

#

There's a particular pattern that comes up in widgets, especially complex ones, that I'm not terribly fond of: it's where a parent widget needs to grab some descendant by the scruff of the neck and do some brute-force mutation on it - examples are moving the thumb of a slider, or setting the gradient parameters of a color plane. The way this happens now is that we have to set some marker on the descendant, and either hard-code the knowledge of the descendant hierarchy in the parent, or call iter_descendants searching for the marker. It seems much cleaner if we could just get the child's entity id at spawn time and capture it in a closure, allowing us to go straight to the target without searching. But we can't use Name for this because it has too global of a scope.

#

With reactions, we have a choice: we can put the reactions on the parent and capture the descendants, or put them on the descendants and capture the parent id. But with observers we are more constrained, we have to put them on the entity that has all the state.

amber pebble
# magic belfry Vaguely related to this ^ idea, can we <:yeet:941199111422627891> the `[]` short...

It's time to ascend to Markdown list syntax super_bavy

bsn! {
    Node { width: px(100) }
    BackgroundColor(GREEN)
    // Child entities
    - Node { width: px(10) }
      BackgroundColor(RED)
    - (:checkbox
      InteractionDisabled
      // Whitespace-independent nesting via () wrappers
      - Text("Hello there")
      )
    - Node { width: px(10) }
}

Advantages: Very terse indentation, no "empty" lines
Disadvantages: Nested hierachies a bit cursed, you cannot use negative values anymore bavy

karmic rock
# rare whale That is, the syntax `#name` binds the string `name` to the entity id, and that b...

Fwiw in flecs script that's done with variables and/or new expressions:

foo {
  bar {}
}

e {
  const a: foo.bar // assign named entity to local var
  const b: new { Position: {10, 20} } // assign new anonymous entity to local var

  Target: {front: foo.bar, back: b /* can reference variable, entity by name or use new expression */ }
}

a and b are scoped to the { } and don't have side effects outside of the script. foo.bar is visible outside of the script

#

Which also lets you do things like

template Something {
  prop val = i32: 0

  const a: match val {
    1: foo
    2: bar
  }
  
  e {
    // foo or bar depending on val
    Target: {value: a}
  }
}
rare whale
karmic rock
#

I still need to add support for refs (mut in flecs script) though. Const is more like Vue’s computed

silk lava
karmic rock
#

& because queries are observable, you'll be able to do this from a reactive (template) context as well

split harness
# rare whale That is, the syntax `#name` binds the string `name` to the entity id, and that b...

This actually largely already the plan. #Name will exist in "layers" in a way, with each bsn! scope being its own isolated layer / scope (and references to that #Name on the RHS of an expression can only happen in the layer it was defined). I believe the only difference between my plan and yours is that the "highest" / final layer will be instantiated as the Name component.

I can see the argument to make these separate concepts, but aligning them means people don't have to do both #Button and Name("Button") if they want to do both things. And it means we get shorthand for Name("Button").

Its a tradeoff, but it feels pretty good to me

#

When I've talked about it being "super-powered" sugar, thats the behavior im talking about

rare whale
thick slate
#

That's much more intutive to me

rare whale
#

Just throwing the idea out there

#

Part of the problem with names is that right now it's a free-for-all, and we don't have a lot of documented use cases except for animation

#

If we started to tighten up the semantics - like saying that names are unique within a parent scope - then I think it would be easier to identify potential use cases

#

Sander has talked about locating entities by path (I'm envisioning something like XPath: "foo/bar/**/baz") but this isn't useful if you can have duplicate names within a scope

lethal juniper
#

IIUC, every entity already has an unique ID: the entity id + gen itself, so what we need is a more friendly way to use this id inside the context of bsn!. I know in "scene time" there is no spawned entity, but this is like a Handle or a Promise, when I spawn the bsn, I'll have an unique id, that's fore sure.

The Name component should be for interacting with external references, where the #id isn't relevant, like animation bones or other things that will be imported in Bevy, so I don't think we should build on top of Name, it should be something for users to use to debug, to display on editor scene view or other things.

So, to sum up my point, the #id should be unique inside where the bsn is defined, it should be totally possible to have two #id's on different bsn declarations, but on the same, this should be a hard error.

copper dragon
#

@split harness I know you've been very busy with other stuff but I was curious if youve thought more about the pre-world ast like bsn stuff?
Particularly how individual bsn assets are put together during that stage?

loud mural
#

Maybe it’s the formatting on mobile but my dyslexia can’t parse the proposed angle brackets syntax at all. I don’t think it’s a novelty/familiary thing it would be permanently hard to read for me. I have no trouble reading html or xml but there’s something disjointed about the current proposed syntax.

lone sleet
#

It's weird how brains work very differently. For me <> is much more legible and that's despite (because?) almost never having used XML in my career. Before I saw that syntax I couldn't really understand BSN but now I think I understand it a bit better. Though I'm sure I could get used to whatever syntax. I do think some characters like ^ should be avoided since it's harder to type that on an ISO keyboard.

loud mural
#

It is indeed weird and interesting

copper dragon
copper dragon
#

They don't work well as a multiline item

#

Html gets by since they are encompassing a tag rather than the contents

split harness
# copper dragon <@153249376947535872> I know you've been very busy with other stuff but I was cu...

We parse BSN into an AST, which then gets converted to an in-memory ScenePatch implementation that relies on Bevy Reflect internally to patch fields. Inherited scenes are resolved in the AssetLoader (similar to what we do for shaders) and with the asset preprocessor we could "pre-resolve" scenes to make them cheaper to load up and spawn.
Feel free to ask more specific questions as I'm not quite sure what you're looking for here.

split harness
copper dragon
split harness
split harness
copper dragon
# split harness > declare bsn for the editor ui rather than them directly manipulat it, I'm not ...

In the past on the prototype we had the issue of plugins needing to change their UI and the queries to get the correct ui elements were getting ridiculously complex with tons of marker components to run around and track and plugins getting entities they werent wanting.
In this new api Ui management is a single crate's job and plugins "declare" a bunch of stuff to the editor like "I want this component fields to have xyz ui" or "I want to add a custom pane" and this crate will handle doing that and managing it.

The hope is to cut down on the amount of issues UI has in the editor. Ive been working on a prototype of it.

split harness
copper dragon
cobalt stone
#

(and I've done a lot of UI work in rust/bevy/etc)

copper dragon
# cobalt stone Wdym? I don't quite get it

Multiple of the same pane causing crashes, view port camera management, accidentally adding ui within ui elements cause 1 parent/child nesting off, heavy reliance on entityids to traverse hierarchy and hope you found the right thing
List goes on, the requirements of the editor cause a lot of issues normal bevy usage doesn't see

#

Well its more a ergonomic json format than a programming lang

karmic rock
#

Pretty much any modern (and not so modern) UI framework has one

#

This is not unique to Bevy

dapper sky
#

Scene notation is a pretty kosher thing to define for an engine, and ECS is not a well trodden field for this kind of thing

#

What sander said

karmic rock
#

React, Vue, Angular, Qt, yeah Flecs too

cobalt stone
#

Entity IDs to traverse hierarchy is only really needed because we don't have a reactive UI thing. Normally you don't need to manually query UI entities.

autumn bane
#

Mm I'd say that depends on the shape of the reactivity -- I find querying by ID super useful and quite easy in my own reactivity solution. But it seems like cart's preferred solutions have more implicit targeting. Either way, I'm really not sure there's much to be learned from unreactive Bevy with regards to editor design practices.

#

It's quite ugly in a way that basically any reactivity system necessarily solves. At least, that's how it strikes me.

cobalt stone
#

Agreed, hence why I stopped working on it

autumn bane
#

I hope by the way I'm not coming off as dismissive or anything! I just expect editor design issues to basically melt away as BSN and reactivity are introduced. While we certainly expect the editor to have complex UI, I think pretty much any non-trivial UI in games or apps will face the same problems. I'd hope we could come up with systems that work without lots of careful workarounds.

copper dragon
autumn bane
#

Why aren't reflect attributes sufficient?

copper dragon
#

Even if its a hard problem I think it'll create a more enjoyable experience over all

autumn bane
#

i certainly have use cases for arbitrary editor UI blobthink

buoyant venture
#

It's not just about UI, it's for any hierarchy of entities/components. UI just happens to be a case that needs it a lot.

rare whale
rare whale
# split harness Entity Paths are for runtime / already spawned hierarchies with Name components....

Agreed that entity paths are only useful for dynamic lookups of Name components. The point that I was trying to make was that, independent of BSN, we don't have a solidly representative sample of common use cases for Name, and I believe that the ambiguity around how Name is supposed to be used is partly to blame for this. This only impacts bsn because bsn conflates the #Name syntax with the Name component.

#

In my own particular case, I've been using Name incorrectly for a long time, my own code is littered with misuses of this. Specifically, I was using it as a way to display the entity's purpose in my debug inspector.

wooden vine
rare whale
#

I remember when C++ introducing angle brackets was considered controversial 🙂

#

Then again, I remember trying to mentor people who were having a hard time making the jump from K&R to ANSI C 🙂

wooden vine
#

(Okay so what if we just used /* */ for entities? And /* */* */... for lists of entities. /hj)

dapper sky
#

there's value in making something different enough to force people to re-assess their assumptions of what the markup is doing

rare whale
#

I'm not a fan of the angle bracket syntax but I can't think of a principled argument against it. While it's true that the way that angle brakets are used in C++ and in JSX are different from the way that other paired delimiters are used (for one thing, the items contained are always heterogenous and always determine type [yes, even in JSX], which is not true of []), this isn't distinct from the way cart is proposing to use them either.

#

I do worry that by sacrificing the child delimiters in the quest for less indentation, we may be kneecapping some important use cases (specifically various ways of composing child lists).

copper dragon
#

Less indentation isn't a good goal imho
If someone doesn't like the indentation they can just chop it up via multiple functions
That's exactly what happens in the webdev world, don't see why that's not acceptable here.

rare whale
# copper dragon Less indentation isn't a good goal imho If someone doesn't like the indentation ...

I kind of agree, although it's hard to make that argument for all the different domains that bsn is likely to be used in. OTOH, for bsn that is generated by machine by an editor, I really don't care if Children is spelled out in longhand or not. I mean, it should be concise from the standpoint of loading efficiency, but I'm not going to worry if the serialization algorithm puts in a few extra keystrokes.

quartz sleet
# copper dragon Less indentation isn't a good goal imho If someone doesn't like the indentation ...

Playing devil's advocate because I also don't mind the indentation, but the idea is to avoid how fast the indentation creeps up, not just how much there is. With the angle bracket proposal, I think you get one level of indentation between the components of the parent entity and the components of the child entity. With the old proposal, you get a level between the parent components and the child entities, then another level between child entities and child components. That means if you're splitting up files because you don't like all the indentation, you have to do it twice as fast.

copper dragon
split harness
# rare whale Agreed that entity paths are only useful for dynamic lookups of Name components....

Name is intended to be:

  1. The name that identifies an entity in the scene editor (useful for organization / navigation)
  2. The name that identifies an entity in entity inspectors (useful for finding the exact entity you are looking for / disambiguating between two entities of the same "shape" / type)
  3. The name that identifies the entity when dynamically querying the hierarchy at runtime (ex: EntityPath). For example, some theoretical animation editor in the Bevy Editor could produce animation assets that dynamically target entities/components via their EntityPath.

For similar real-world non-bevy scenarios, see Godot's "Node name", Unity's "GameObject name", Unreal's "game object names", and Blender's "object name"

#

When possible, it is worth either baking an EntityPath to an Entity, or skipping the EntityPath entirely in favor of marker components or something like BSN's "scoped #Name" functionality, as dynamically resolving EntityPaths cause overhead

#

And in theory, Names can change at runtime

split harness
#

(edited to be more representative)

#

And the proposed syntax for comparison:

Node
<
  Node
  BackgroundColor(RED)
>
loud mural
#

I’m not sure how helpful it is to compare the trivial case. It’s pretty easy to read either at this level of nesting and number of components. The real test is when there’s multiple children with 5-10 components and some of those children have children… unless that’s not how bsn is meant to be used that is. Html hierarchies get reasonable deep

split harness
#

Or you can look at the already-presented feathers.rs port and compare the current to the proposed syntax

loud mural
#

Not at my computer right now, but when I get home I’ll add those links to the discussion. Things get lost so easily in discord chats it would be good to have the complex cases easily accessible from the coordination point.

#

Would you mind pinning the discussion url message? I think only mods have that permission

#

Maybe it’s just the way that discord renders stuff on mobile vs github but looking at the gihub discussion more carefully I think I’ve come around to preferring the <> syntax lol

copper dragon
loud mural
#

The potential draw back I see there is there’s no way to easily find the beginning and ends like there is with opening and closing angle brackets

dapper sky
#

there's also no information between the angle brackets in the closed arrow case, not sure what the point is.

copper dragon
leaden dew
# split harness I think this is a pretty solid proposal (both `#()` and `#{}`). Retains most of ...

This is also notably how people think about html ids, which are filling essentially the same role (ex: <#Name Node> vs <div id="Name" />)
shower thought: I think the main reason for the "ick" many feel when seeing free-standing < on its own line is that we're overwhelmingly used to reading < as a prefix for some type of "element identity" and they never get separated in any XML flavor
for example, this is okay:

<div
    id="Name"
/>```
and this is not:
```html
<
    div
    id="Name"
/>

along those lines, given that bsn's #name is already "super powered" sugar because it's not just a Name("name"), couldn't we reify <#name as the "element identity" for a child entity in bsn?

bsn! {
    Node { width: px(100) }
    BackgroundColor(GREEN)
    // Anonymous child
    <#
        Node { width: px(10) }
        BackgroundColor(RED)
    >
    // Named child
    <#MyCheckbox
        :checkbox
        InteractionDisabled
        <#hello Text("Hello there")>
    >
}

this still suffers from points 2 and 3 in cart's replied-to comment, but none of the others and i think retains most of the benefits while adding a new one: skimming BSN markup would become easier as scopes can be visibly named at the delimiter, whereas otherwise you need to visually "enter" the scope to find a name (or read the components) to understand what a specific child's function is

torpid hemlock
#

with # it could even be something like

bsn! {
  Name("root") // if root entity needs a name 
  Node { width: px(100) }
  BackgroundColor(GREEN)

  // child 
  #{
    :checkbox
     InteractionDisabled
     #{Text("Hello there")}
  }

  // child with name
  #name { 
    :button 
    #{Text("Click me!")}
    on(handle_click)
  }

  // custom relationship 
  #[InInventory] { Item }

  // custom relationship with name
  #name[InInventory] { Item }

}
copper dragon
leaden dew
torpid hemlock
#

Ah right, I must've missed that one.

copper dragon
torpid hemlock
#

I wonder can Name have whitespace? Would you write it like #"With space" then?

split harness
loud mural
split harness
#

And loses the <>-as-entity-bounds property

split harness
#

One issue with <> is that Path parsing greedily consumes <> tokens as part of the path

#

And we use Path to parse SOME_TYPE_PATH{}

#

Solvable by writing a custom Path parser

copper dragon
split harness
#

vs

<
  Node
>
#

But I'll concede the point that < does feel "open"

#

But only marginally more so than { or (

#

The whole point is that they are "open" syntax for a context

copper dragon
#

personally my brain keeps wanting to parse those < as arrows and nothing more

split harness
#

I'll call out that real-world html / jsx isn't winning any beauty / legibility contests:

copper dragon
split harness
#

We could steal the "leave one on first line" formatting when it fits

<Node { ... }
  BackgroundColor(RED)
  <Node { ... }
    BackgroundColor(RED)
  >
>
copper dragon
split harness
#

We're going to recommend (and perhaps lint for) bsn! {}

#

The plan is to build a bsnfmt tool that IDEs can call

copper dragon
leaden dew
#

if rustfmt isn't touching bsn, another way to solve the double-indentation issue is to do something very common in javascript land:

Node [(
   Node
   BackgroundColor(RED)
)]```
#
Node [(
  Node
  BackgroundColor(RED)
), (
  Node
  Backgroundcolor(GREEN)
)]```
#

etc

split harness
#

Worth considering though!

leaden dew
#

the full example from the proposal in this style:

bsn! {
    Node { width: px(100) }
    BackgroundColor(GREEN)
    [(
        Node { width: px(10) }
        BackgroundColor(RED)
    ), (
        :checkbox
        InteractionDisabled
        [Text("Hello there")]
    ), (
        Node { width: px(10) }
    )]
}```
#

it's a bit icky

copper dragon
leaden dew
#

i'm not sure how bsn! handles those to begin with

copper dragon
#

rn i just slap () around each one

split harness
karmic rock
golden notch
#

just for fun, here's how i'd do it in clojure:

(bsn
  (node {:width (px 100)})
  (background-color GREEN)
  (children
    [(node {:width (px 10)})
     (background-color RED)]
    [(checkbox)
     (interaction-disabled)
     [(text "Hello there")]]
    [(node {:width (px 10)})]))

a more data oriented version using reader macros and implicit children:

(bsn
  #Node {:width (px 100)}
  #BackgroundColor :GREEN
  [#Node {:width (px 10)}
   #BackgroundColor :RED]
  [(checkbox)
   #InteractionDisabled
   [#Text "Hello there"]]
  [#Node {:width (px 10)}])
rare whale
# split harness Name is intended to be: 1. The name that identifies an entity in the scene edit...

The problem is that the three use cases you lay out are ambiguous / in conflict. If Name is intended to be for developer readabillity, then there can and should be duplicates within a scope. If OTOH Name is meant for entity path lookups, then there should not be duplicates. When I said that I had been using it wrong, I mean like automatically adding the Name Button to every button template so that it would show up in the inspector as a button. This makes it impossible to look up a button by name.

The consequence of this confusion, I think, is not that users use name incorrectly and run into trouble; rather, it's that they avoid using Name components entirely.

I'm strongly in favor of separating these two uses of name into separate components (like DebugName) a proposal which has been discussed elsewhere.

cobalt stone
#

just copy xml 🙃

#

It's well defined

copper dragon
cobalt stone
#

Several people are angrily typing...

silk lava
#

Name and EntityPath should be enough, one for debug supporting overlaps, and one for finding an entity supporting overlaps between different parents.

split harness
cobalt stone
golden notch
split harness
#

That syntax largely amounts to "structs that can nest inside of each other", which isn't semantically "enough"

wintry cape
#

I believe we can leave some of the less critical/non-core issues until after the bsn is released, allowing us to make improvements after more users have had a chance to actually experience it.

karmic rock
# silk lava lol looks like flecs

The other thing you can do is show the asset name/prefab in a treeview, so you don't have to explicitly assign a debug name. It'd just show up as "Button"

cobalt stone
rare whale
golden notch
#

i don't mind xml either and definitely fall into the camp of < > hurts my head for not being xml flavored, but also fully recognize that people would clown us for releasing an xml based configuration language in 2025

karmic rock
#

not that surprising though, it's basically JSON without the ""

#

and a bit more syntax for entities

split harness
cobalt stone
#
<Entity>
  <Node>...</Node>
  <Foo>...</Foo>
  <Bar>...</Bar>
  <Entity name="foo">
     ...
  </Entity>
</Entity>
rare whale
cobalt stone
#

(Special syntax for entities)

<>
  <Node>...</Node>
  <Foo>...</Foo>
  <Bar>...</Bar>
  <name="foo">
     ...
  </>
</>
split harness
rare whale
rare whale
karmic rock
#

I'm not sure that outweighs the cost of doing uniqueness checks at runtime
If you'd also support a hashmap for faster name lookups, the cost of the uniqueness check becomes zero since you can combine it with hashmap insertion

split harness
silk lava
split harness
karmic rock
#

Makes sense 👍 I was in the exact same spot a few years ago where I was fiercely defending my simple Name component which did nothing besides storing a string pointer :p

karmic rock
split harness
#

@rare whale I worked on the "spawn related scene list" stuff today. I believe I'll wrap up on Monday

karmic rock
#

Well that, and I landed a job where having unique names helped out a lot

rare whale
#

HTML doesn't complain if you have duplicate ids. The difference between HTML and Bevy, though, is that any tutorial on CSS or HTML best practices will tell you not to have duplicate ids, whereas Bevy is silent on the issue.

split harness
karmic rock
split harness
#

(forgive me for being cheeky)

silk lava
#

I dont think mixing free-names and unique-names is very rusty, reminds me of Event before it was split.

#

Then again, I cant complain too much, we are still missing a large part of rust in our ECS, the traits 😭

rare whale
rare whale
#

That is, when I contemplate writing code that uses name components, part of what I have to consider is the general character of the larger ecosystem of names. If that character is unknowable, then that's a strong incentive to use a different tool.

copper dragon
rare whale
karmic rock
#

I think it's better to not enforce it, but just provide an API that assumes it's unique (so you can do world.lookup("MyEntity")

silk lava
karmic rock
#

But overall better to not panic

silk lava
#

So if the #name syntax in bsn! were to add an Name, and if there are uses of #name as an reference in the bsn! then also add EntityPath derived from the Name, the EntityPath could be used since it will be unique, but from an user bsn! point of view though its simply #name. (Not sure if it can do forward-looking stuff like that)

karmic rock
silk lava
# karmic rock Why do you need a separate `EntityPath`?

Cause Name is non-unique but a descriptive name, and potentially not all entities will need an unique name to be used for lookup, but checking for an use in the bsn can atleast locally tell you if its needed, and if so add it seperately.

karmic rock
#

I have a lookup map per parent that only stores the name (so uniqueness is only enforced at that level)

#

Would EntityPath store the full path?

silk lava
#

From my thoughts of it, yeah would store the whole path, and would have to be updated when parent hierarchy's change.

#

Its equivalent to the ActorPath or whatever its called in UE, except no type at the end kek

karmic rock
#

The full path isn't that useful in many scenarios though, like

entity parent = world.lookup("Foo");
entity child = parent.lookup("Bar");
entity grand_child = parent.lookup("Bar::Hello");
assert(grand_child == world.lookup("Foo::Bar::Hello");
#

Also I imagine that if you're writing bsn and you want to refer to an entity, you want to refer to one that is in your current scope or a parent scope

silk lava
karmic rock
#

Yup

silk lava
#

So then I assume it has to lookup each entity in that path for the next entity?
With the full path you should always be able to look something up in one. Also you can reconstruct the full path given any hierarchy and their names.
So if you have access to the parent, and it has a full path, and you give it a name to look up as a child, then it just adds that name to its full path, and looks up as if you had the full path already.

karmic rock
#

Hm, so you'd always append the child name to the path of the parent 🤔 yeah that'd work. Bit expensive but simple

rare whale
# karmic rock I've been getting some pushback against it when flecs is used in editor scenario...

Yeah, I recognize that the conventional wisdom in software engineering is that everything not permitted should be forbidden. In the world of HTML/XML/JSX, however, id uniqueness isn't enforced, but only strongly encouraged. For example, look at the docs for getElementById: https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById

  • There is no getElementsById or any function to get multiple duplicate elements with the same id. You can, however, write a query using selector syntax that does this, but it requires pretty advanced CSS knowledge to do so.
  • The documentation doesn't say whether you get the first or last element if there are duplicates. It doesn't bring up the subject at all, it's effectively unspecified. It only says that element ids are "supposed to be" unique.
    In other words, there is a very strong bias towards uniqueness in the design of the API and the documentation, but it is not an absolute prohibition.
MDN Web Docs

The getElementById() method of the Document interface returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quickly.

karmic rock
rare whale
# karmic rock The other thing you can do is show the asset name/prefab in a treeview, so you d...

Unfortunately, we don't have prefabs yet. Because the widgets I have been building are effectively Rust functions, there's no way to access the function name at the template level.

It's certainly possible to make the editor or inspector have a heuristic that lets it identify the "primary" component. However, the developer should have the option to override the description in the editor, and this override should be separate from the identifier used to search for the entity by path.

tardy beacon
lime veldt
#

oh you wrote it nvm

tough trail
#

I feel like maybe putting the “name” on the same line as the < might help with diffing? It feels intuitive to me that having lines of code that don’t contain any semantics, and only contain syntactic tokens, will cause pain with diffing

#

I think this is a problem I’ve had with self closing XML-style tags for example, the closing part (/>) often confuses diffing algorithms

tough trail
#

Repeating the name on the closing line would also make it harder to see where the closing line is (without additional syntax)

tough trail
#

some more thoughts: I think the proposed <> BSN syntax only seems weird if you try to imagine it as being equivalent to this:

<Node attr1="val" attr2="val2">
  <ChildNode bgColor="red" />
  <ChildNode bgColor="blue" />
</Node>

but if you imagine it as being equivalent to this it's easier to accept:

<Node
  attr1="val"
  attr2="val2"
  children={
    <>
      <ChildNode
        bgColor="red"
      />
      <ChildNode
        bgColor="blue"
      />
    </>
  }
/>

The BSN equivalent could be something like this I think (?) which doesn't look that different to me, it's basically the same but with the redundant parts of the syntax removed:

<Node
  Attr(Val)
  Attr2(Val2)
  <ChildNode
    BgColor(Red)
  >
  <ChildNode
    BgColor(Blue)
  >
>

I would note though, the children={ part is only redundant because BSN only allows a single "slot" for child nodes to be inserted into (fwiw, I personally think that is quite a big limitation from a UI dev pov but that's not to say it's definitely the wrong decision for bevy)

buoyant venture
#

I think a part of me would like the closing /> in BSN but that's probably just my HTML experience bias

#

I do like this framing of comparing it to children={} it makes it easier for me to get it now

#

tbf, I never liked that when I was doing react 😅

tough trail
#

this is an aside but when it comes to react I think children={ actually leads to a much better mental model than the other style, even if it’s more verbose, but that’s for reasons that probably don’t apply in this context so not worth elaborating on too much

golden notch
split harness
#

@rare whale

Do I want my names to be unique or not? I don't know, because I don't know how they will be used or what systems will use them.

If you don't know if your names need to be unique, then you are at a point in your project where the question doesn't matter. If you need uniqueness, then provide unique names. I really don't see the problem here. Users can easily set the name of any entity they spawn (or have the Entity id for).

@karmic rock

Would EntityPath store the full path?

In my mind, EntityPath is a reference that you resolve to an Entity in the moment, not something you would typically store indefinitely (ex: in a component intended to point to some parent entity)

Also I imagine that if you're writing bsn and you want to refer to an entity, you want to refer to one that is in your current scope or a parent scope

My current plan for bsn! is for #Name (right-hand-side value, resolved during spawn) to only be accessible in the current bsn! scope. Within that scope, it must be unique (across levels of the hierarchy). Some parent / inheriting bsn! scope is arbitrary and unknown, and might alias the current scope's names. Anything making assumptions about the parent's name should use EntityPath and resolve at runtime, and that will use the final Name runtime components (and not the spawn-only entity mapping). In this way, it is ok for multiple spawned button scenes to have the same Button name, as the scene that spawns those buttons isn't explicitly defining a #Name, so it isn't in that bsn! scope. I think this lets us have "one" unified system that naturally behaves the way it needs to in most contexts.

split harness
#

@rare whale I just added spawn_related_scenes

#

/ pushed it to my branch

#
commands.spawn(Node::default())
  .spawn_related_scenes::<Children>(bsn_list! {
    (Node {width: px(200), height: px(200)} BackgroundColor(RED)),
    (Node {width: px(400), height: px(400)} BackgroundColor(GREEN)),
  })
rare whale
# split harness ```rust commands.spawn(Node::default()) .spawn_related_scenes::<Children>(bsn_...

I won't have a chance to check out the code for a day or two. I'm wondering, does it handle the issue I brought up previously about replacing existing related entities without a temporal gap? Specifically, a lot of my use cases involve spawning a list of entities that replaces the previous spawned entities; and I can't simply call despawn_related before calling spawn_related_scenes. The reason is that despawn_related happens immediately (well, at the next command sync), whereas IIUC spawning bsn scenes doesn't take effect until the templates have resolved, which may take multiple frames. This would result in an unsightly flash. What I need is some way to defer the despawning the old entities until the bsn scenes are ready to go.

split harness
rare whale
split harness
#

From my perspective, in most cases you generally shouldn't be calling spawn()on scenes that can't be spawned immediately

#

Ex: after some initial loading screen, everything happens immediately in the same frame

#

especially in the context of UI

rare whale
#

If the if-condition changes, I want to destruct the current branch and replace it with the new one, with no temporal gap.

#

This isn't just UI stuff either

rare whale
#

Consider for example a tab deck widget with 3 tabs. Each tab is a different bsn scene, or has some function that can yield a bsn scene. When you click on a tab, the existing content is despawned and a new bsn scene is evaluated to populate its replacement.

#

It would look bad if there was an interval where the previous tab's content had been destroyed but the next tab's content wasn't visible.

#

Instead, you would want to wait until the new tab's content was ready and then do an atomic swap.

#

I suppose there could be some "ready" entity event which gets fired just before the scene is spliced in, but this sounds a bit rube-goldberg-ish to me.

rare whale
slender lion
# rare whale It would look bad if there was an interval where the previous tab's content had ...

wouldn't the state of the art here be:

  • user clicks switch tab
  • temporarily nothing is shown (showing loading indicators too early makes interactions seem slow/etc)
  • if enough time passes for a "load" of the tab content, loading indicators are shown
  • content is shown (or possibly error state if loading failed)

so it would really be about being able to access the loading state of the bsn dependencies, either ahead of time for a pre-load call or after spawn.

#

for ex: if there was a long loading process, you wouldn't want to show the old content anyway, because that makes it seem non-responsive.

rare whale
# slender lion wouldn't the state of the art here be: - user clicks switch tab - temporarily ...

It really depends on how long of a delay we are talking about. If it's just a few icons being loaded from assets, and the delay time is only 1-2 frames, I would much rather delay the flip than put up a loading screen - a 2-frame load screen would be an even more unsightly flash.

Also, I want to stress that my tab example isn't some isolated corner case. I plan to use this kind of conditional logic everywhere:

  • dropdown menus
  • tree view node expansion
  • tab decks
  • popups
  • toolbar modes
  • scrolling lists (each list row is a scene)
    You generally don't expect toggling a tree-view expansion to put up a load spinner...
slender lion
# rare whale It really depends on how long of a delay we are talking about. If it's just a fe...

yeah that's why I mentioned step 2, which doesn't show a loading indicator for less than say, 100ms, of load time.

You generally don't expect toggling a tree-view expansion to put up a load spinner...

If it takes long enough it absolutely should. That's pretty critical user messaging for long load times or progress indication (which everyone hopes doesn't occur, but very easily occurs on the web, etc). regardless I think focusing on the loading indicator is a bit off the mark. Long load times require load indicators. Small load times don't (and shouldn't) show load indicators. We also can't expect "instantaneous loads" for anything that wasn't preloaded.

Back to the original point, even in the block-then-flip case you want to be able to access the bsn dependencies and pre-load them so the spawn goes through as expected; which seems to align with the "don't spawn bsn that isn't ready to spawn" comment.

Plenty of tab implementations solve for this by doing things like "spawn offscreen and move onscreen to switch", which is basically what you're talking about here, as long as there's a "SceneInstanceReady" style event being fired.

being able to access the load status of a scene seems to solve all of those cases: both blocking and not blocking (which actually aren't even different situations, because block-then-flip has to fallback to the other approach on long enough timescales). In both situations the loading state exists, in your example you want to not show that loading state to a user and swap content when everything is finalized.

rare whale
# slender lion yeah that's why I mentioned step 2, which doesn't show a loading indicator for l...

Maybe I misunderstood what you were saying. Your step 2 reads:

temporarily nothing is shown
By "nothing" I assumed you mean "show empty space" (which is what I don't want) - or worse, show no entity at all (causing flex siblings to collapse into the vacant spot). What I want is something that shows either the old view, the new view, or an intentional placeholder which takes up the right amount of space. It should never show "nothing".

#

These conditional scenes that I am envisioning will vary in size: a few very large subtrees with many asset dependencies that will take a measurable amount of time to load, and a very long tail of tiny conditional subtrees that have maybe an icon or two, icons that are likely to be already cached in the AssetServer, but even if not are likely to load quickly. Moreover, as the person constructing this hierarchy, I can pretty well predict how hefty a particular conditional subtree is - that is, I can intuit whether this conditional is large enough to warrant the extra effort of building a loading indicator, vs simply showing the old ui until the new one is ready.

#

My goal here is to re-write bevy_reactor, except instead of inventing my own templating language to use bsn everywhere. This means lots of bsn micro-scenes: a for-each loop will invoke a scene per iteration. But this plan will only work if the transition between old hierarchy and new hierarchy is seamless - which is something I think we want for bsn to have anyway.

#

I feel like we're going to eventually need to re-invent a lot of React's prior art for transitions and asynchronous rendering, but that's not in the MVP.

keen patio
# rare whale I won't have a chance to check out the code for a day or two. I'm wondering, doe...

You could do non-deferred spawning like this:

/// Synchronously build and insert a [`Scene`] on an entity and recursively spawn its related entities.
/// 
/// Returns an error if any of the templates fail to build.
/// 
/// Panics if an inherited scene is missing/not loaded.
fn spawn_scene_sync<S: Scene>(entity: &mut EntityWorldMut, scene: S) -> Result {
    let mut resolved_scene = ResolvedScene::default();
    scene.patch(
        entity.world().resource::<AssetServer>(),
        entity.world().resource::<Assets<ScenePatch>>(),
        &mut resolved_scene,
    );
    resolved_scene.spawn(entity)
}

/// Same as above, but for related scenes.
fn spawn_related_scenes_sync<R: RelationshipTarget>(
    entity: &mut EntityWorldMut,
    scenes: impl SceneList,
) -> Result {
    let mut resolved_scenes = Vec::new();
    scenes.patch_list(
        entity.world().resource::<AssetServer>(),
        entity.world().resource::<Assets<ScenePatch>>(),
        &mut resolved_scenes,
    );

    for scene in &mut resolved_scenes {
        scene.spawn(entity.with_related::<R::Relationship>(()))?;
    }

    Ok(())
}
rare whale
keen patio
#

It seems a bit excessive to store every single "micro-scene" as (in-memory) assets etc. So it would seem like non-deferred (or a bsn gen1 style static resolution) would be the way for many of these. I see your point though, some of these micro scenes may inherit from assets, which may not be loaded... In which case we also might want to reactively show placeholders until they are

#

It would be pretty neat to have a separation between SceneWithAsyncDeps and SceneWithNoAsyncDeps on a type level.
That way the non-async scenes could simply be spawned as is, while the async ones could be forced to use some <Suspense/>-like mechanism

rare whale
keen patio
slender lion
rare whale
#

More seriously, I think that we'll need some form of Suspense-like mechanism. What I am saying is that it shouldn't be mandatory. Devs can choose to use it or not.

split harness
# rare whale Instead, you would want to wait until the new tab's content was ready and then d...

If your bsn doesn't include references to bsn inside of an asset file (which therefore needs to be loaded), then your bsn can be spawned in the same frame. We've talked about having a static split between "deferred bsn" and "immediate bsn". This feels like another case that would benefit from that (as it would make the needs clear statically).

If you're dynamically generating "deferred bsn" based on runtime context, then theres really not much that can be done. The best we can do is let people plug in to the lifecycle (ex: via observers).

If the "if-statement template" has access to the conditional deferred bsn even when the branch hasn't been evaluated, then we could report those bsn dependencies as dependencies of the root scene, and we could load it all in one go, before presenting the UI to the user.

rare whale
split harness
rare whale
#

@split harness Getting this error, trying to investigate it now:

thread 'Compute Task Pool (6)' panicked at /home/talin/.cargo/git/checkouts/bevy-6dde41ac0c36136a/0c78073/crates/bevy_scene2/src/spawn.rs:99:59:
called `Option::unwrap()` on a `None` value
rare whale
#

I'm about to head out for the day, but it you want to repro yourself use https://github.com/viridia/bevy_reactor example effects. Update: I added a new "control_flow" example which provides a simpler reproduction of the panic.

cobalt stone
#

I will continue to shill dioxus-core

rare whale
#

@split harness So I've tried both the commands version and the world version of spawn_related_scenes: The call returns ok, but shortly afterwards I get a panic on this line in spawn.rs:

            AssetEvent::LoadedWithDependencies { id } => {
                let list_patch = list_patches.get_mut(id).unwrap();
                let mut scenes = Vec::new();
#

This appears to have something to do with the context in which I am calling spawn_related_scenes.

#

That is, if I call it from a startup system in a simple way, it works.

#

However, I'm calling spawn_related_scenes from within a custom command. The command executes successfully, but the panic occurs shortly afterwards.

copper dragon
#

So was thinking about file preview thumbnails.
When we make the asset format, it'd be really nice to be able to store a preview thumbnail in the metadata so the editor doesn't have to make new ones every load or store them separately.

copper dragon
#

quick syntax question

bsn! {
        :"scene://transform_1000.bsn"
        Transform { translation: Vec3 { x: 11.0 } }
    }``` 
This translates to "apply this component to the root of this referenced bsn"?
silk lava
split harness
#

I'll look in to it

#

Today and yesterday I've been working on #Name-as-entity-ref in bsn!

#

Ex:

bsn! {
  #Root
  [
    SomeChild {
      entity: #Root
    }
  ]
}
copper dragon
split harness
copper dragon
#

Mmn I see.

split harness
#

Ids won't change magically

copper dragon
#

Could this work cross functions?

split harness
#

They can be invalidated if the entity despawns

copper dragon
#

Passing a name into the bsn?

split harness
#

If you want to reference an entity by name (in a different level of inheritance), use an EntityPath

copper dragon
#

Hmm I see

#

I'll have to chew on this.
Been trying to think of how to orchestrate the editor ui resolution stuff, might be useful

silk lava
#

Perhaps there could be another use for prefixing entity syntax:

bsn! {
  // Contains:
  // bsn! { #root Transform::default() [ (#first Transform::default()) ] }
  :"scene://transform_1000.bsn"
  #new_root
  Marker
  [
    (#second Transform { translation: Vec3 { x: 11.0 } })
  ]

  // Entity-scope applies to the prefix-ed entity.
  #first( Transform { translation: Vec3 { x: -11.0 } } )
}
split harness
#

(different levels of inheritance)

silk lava
split harness
#

We've discussed it as something like "new_root/first" (as a string representation), so the syntax might be ?"new_root/first"

dark crater
#

is the plan to still have no line delimiters, or will there be commas or semicolons or whatever?

#

from the PR, it wasn't clear, since I don't think there was a response from cart

silk lava
#

If Path is a string representation then Name should be too 😛

dark crater
#

(in that thread)

split harness
split harness
silk lava
#

I mean could just do raw string "" not in a Rust context is either an Name or if it contains an / then its an Path 😂
Jk gotta be able to use those in the Rust contexts kek

dark crater
# split harness Although I'm still kind of leaning toward something like https://github.com/bevy...
    Node { width: px(100) }
    BackgroundColor(GREEN)
    [
        (
            Node { width: px(10) }
            BackgroundColor(RED)
        ),
        (
            :checkbox
            InteractionDisabled
            Children [
                Text("Hello there")
            ]
        ),
        Node { width: px(10) }
    ]
}```
> And here is the <> syntax:

bsn! {
Node { width: px(100) }
BackgroundColor(GREEN)
<
Node { width: px(10) }
BackgroundColor(RED)
>
<
:checkbox
InteractionDisabled
<Text("Hello there")>
>
<Node { width: px(10) }>
}```
why is the extra level of delimitation from the square brackets in the first example not necessary?

split harness
#

why is the extra level of delimitation from the square brackets in the first example not necessary?
Because in the proposal we'veI've decided to make that implicit when you specify children

silk lava
#

Two changes were made there, ()-><> and any entity <> not inside of an relation [] is implicitly in an Children relation.

dark crater
#

I'm definitely a fan of that syntax much more than the parentheses

split harness
#

Within a given entity <>, if you see a type name, its a component on that entity, and if you see a <>, its a nested child

dark crater
split harness
#

Like a different relationship?

#

Or a floating entity?

#

For other relationships, see the proposal doc

#

Floating entities aren't allowed in bsn!. There is always a single root

dark crater
# split harness Like a different relationship?
    Node { width: px(100) }
    BackgroundColor(GREEN)
    [
        (
            Node { width: px(10) }
            BackgroundColor(RED)
        ),
        (
            :checkbox
            InteractionDisabled
            Children [
                Text("Hello there")
            ]
        ),
        Node { width: px(10) }
    ]
    Something_Else
}```
whatever this would be? Though I'm not sure exactly what relationship that would indicate, would it just not be allowed?
split harness
#

Something_Else would be considered a component on the root entity

#

Same in the new syntax

#

Although we are likely to disallow that ordering for clarity's sake

dark crater
#

and it's one bsn! invocation per root entity right?

#

or is it possible to declare several sibling entities from a single invocation

silk lava
#

bsn! has one root entity, so anything at the root-level is put on the root-entity it creates.
bsn_list! creates multiple root entities, meaning every entity is wrapped with <>, and it will create those multiple root entities.

bsn! {
  #root
  Node
  <#child>
  RootMarker
}
// vs
bsn_list!{
  <
    #root
    Node
    <#child Node>
  >
  <
    #another_root
    <
      #child 
      Node
      <#grand_child Node>
    >
  >
  <
    #third_root
  >
}
dark crater
#

ok yeah that makes sense, thank you!

river geode
rare whale
rare whale
proud citrus
#

hello, is LSP completion inside the bsn! macro possible ? for example completing component fields, like Node { .. }

somber rivet
proud citrus
somber rivet
#

"Support the scenarios above, while still feeling "at home" alongside normal Rust code. This includes playing nicely with Rust Analyzer for autocomplete, go-to-definition, documentation-on-hover, etc." in https://github.com/bevyengine/bevy/discussions/14437

GitHub

Preamble My vision for Bevy UI is largely a vision for better Bevy Scenes and an improved Bevy data model. The general angle is: Embrace the "Bevy data model" for both Scenes and UI. Fill...

split harness
#

I just pushed "entity name references as values" to my branch. So this is now possible:

fn root() -> impl Scene {
    bsn! {
        :base
        #Root
        SomeEntity(#Child)
        [
            (
                #Child
                SomeEntity(#Root)
            )
        ]
    }
}

fn base() -> impl Scene {
    bsn! {
        #Base
        OtherEntity(#Child)
        [
            (
                #Child
                SomeEntity(#Base)
            )
        ]
    }
}

Which produces:

entity_0
Name("Root")
OtherEntity(entity_1)
SomeEntity(entity_2)
Children [
  (entity_1 Name("Child") SomeEntity(entity_0))
  (entity_2 Name("Child") SomeEntity(entity_0))
]
#

Accessing #Name as a value in a closure is not yet possible, and will require a bit of additional magic

#

It is only currently accepted in places that expect an Entity template in field position

split harness
split harness
#

Also note that the root entity has both #Base and #Root in different scopes, which both resolve to the same final entity

rare whale
#

This has a couple small bugs and missing features (besides the panic) which I need to work on.

#

For one thing, I need to write a non-feathers example showing how to use popover and headless menu components

split harness
rare whale
rare whale
#

@split harness I'm thinking about how to organize the bsn and non-bsn versions of the feathers widgets.

  • We've already discussed the idea of using struct templates vs. functions: Button vs. button(). I generally like this approach.
  • However, having two identifiers that only differ in case is a bit dodgy. Another alternative is button_bundle() for the non-bsn versions. A bit more verbose, but users who access feathers via bevy_immediate won't know the difference.
  • A third possibility is to refactor things so that the non-bsn widgets are in their own Rust module.
copper dragon
#

Question about the bsn "scene://..." References to other bsn.
When I call load on a bsn that has a reference to another, does the scene system automatically resolve loading it? Or does the referenced bsn need to be loaded prior?
If I have multiple references to one, and I call spawn on the referencing bsn, does that cause multiple of the referenced to be spawned or only one?

split harness
split harness
split harness
copper dragon
copper dragon
# split harness Yup!

Side note is there any helper functions to create those strings from a given bsn or do I need to have the reflection api receive them?

#

I saw you have free will to specify the path at load

split harness
copper dragon
#

I think it was Alice that told me to try find a solution that worked with the macro as well as the asset format

split harness
#

(ping me in #editor-dev if you want to make the case there)

#

@rare whale I just pushed the fix

#

(and merged your pr)

rare whale
rare whale
split harness
#

When it comes time to upstream we can break things apart and review the feathers port separately

#

(and the feathers additions)