Dan Abramov 0:00 Can anybody hear me? 0:04 Okay. 0:07 Hi. 0:13 I couldn't find the water. 0:14 So today it's going to be Coke. 0:20 So hi. 0:21 My name is Dan Abramov. 0:22 I used to work on Bluesky for a little bit and on React for a little bit before that. 0:31 Right now I'm just doing random stuff. 0:34 And so I— you know, some projects you start because you have, like, a real problem that you want to solve. 0:40 This is not one of those projects. 0:43 So this is one of those projects where, like, I just had this idea that, you know, I know React pretty well and, like, I know how components work. 0:51 And I also kind of know it at this point. 0:55 And I just had this idea, like, what if you put components on it? 0:58 And I just couldn't like kind of get rid of this idea. 1:01 And at some point I decided, okay, I just need to try and see where that leads. 1:06 So I vibe coded a prototype like a couple of months ago in one week. 1:12 And it kind of looked like this. 1:14 I ended up spending the next 2 months completely rebuilding it like properly. 1:19 But I'll just show you the prototype first and then I'll kind of show you how it works. 1:25 So what you see here is I guess it's kind of like It's kind of like a Bluesky profile page. 1:31 So I'm just using that as an example. 1:34 It has different tabs. 1:35 It has the replies tab and the media tab. 1:40 It has pagination. 1:42 It has this circle component. 1:45 There's this third-party website that has this feature that lets you see social connection and jump between people. 1:54 And see who kind of interacted with whom recently, which I think is a really nice kind of thing you can do when the data is open. 2:06 But one frustration for me with a lot of apps, like with app paradigm in general, is that things like this have to live somewhere else. 2:17 There's really no point in continuum between here's a one-off tool that I throw away that lives on some URL somewhere that is not discoverable, And here's like a whole app. 2:28 And there really isn't much like in the middle. 2:33 And so I thought it would be interesting if there was a way for, you know, people to kind of prototype features like this in a place where you can find them. 2:42 And so maybe let's have a look at how this actually works. 2:45 Because so far, you know, it just looks like kind of like a worse browser. 2:50 But one interesting thing we can do is I can click. 2:54 Inspect on it. 2:56 And it kind of opens up a little bit. 2:59 You can see, you know, that actually, like, what I've been looking for is kind of like a tree. 3:07 Kind of like a React tree. 3:08 Except each of these things is actually a Proto record somewhere. 3:13 So these are different components that could be implemented by different people. 3:17 Could live in different places. 3:19 And so on. 3:20 And maybe let's— I'm just going to pull it out a little bit. 3:24 So this is my profile header. 3:26 And this is profile posts. 3:30 And profile posts is probably, you know, you wouldn't be surprised that it's a list of posts. 3:39 And a post itself, you know, it has, like, avatar and handle. 3:45 Yeah. 3:47 We need to go deeper. 3:51 Yeah. 3:51 So, okay. 3:52 So, what, you know, what can we do with it? 3:56 So, one thing I want to do is I'm actually going to open this as a different user. 4:03 So, I have like another browser here. 4:07 Let's take this profile header. 4:11 So, I'm now logged in not as Dan Abramov but like as another user. 4:15 And I have this remix button here. 4:17 So I'm going to press Remix. 4:19 And I hope that it works. 4:21 And so this opens up sort of an editor. 4:24 So this is the profile header. 4:26 And you can see there's a bunch of something that looks like JSX here. 4:29 But, you know, really it's JSON. 4:31 That's what JSX has always been. 4:35 And I can actually look at— like, another way to look at it is just on PDSLS. 4:40 So I'm going to open PDSLS. 4:43 And I have this inlay component collection. 4:46 And I have this profile header. 4:49 And so this stuff that you see here, like there is like a stack with like avatar and like title and caption and like all of that jazz. 4:58 And like the COVID is actually like you can also see here that this is this JSON structure, which is just like a UI tree. 5:08 And it imports from some DIDs, which are this is like the built-ins, this is the design system, and these are actually like my other components. 5:16 So it's kind of like DITs act kind of like packages. 5:20 And here it says that this component can act as a kind of a view of the profile collection. 5:27 So it's like a thing that can render a profile, at least one of those things. 5:32 And so I'm going to remix this a little bit. 5:33 I'll, I think I'll get rid of the COVID And actually like maybe, you know, maybe I'll get rid of the avatar too. 5:42 And instead I'll add a, I'll add a circle component. 5:46 So you've seen the circle before. 5:49 So I'll just, I'll just throw that in here so that it's easy to find. 5:53 I think I'll actually, let me put it here. 5:57 And I'll make this a row instead of, yeah. 6:01 And maybe, maybe I'll add some inset. 6:04 Okay. 6:05 So this is like my take on what a profile header should be. 6:09 So there's already a profile header component, but I'm going to publish another profile header component from kind of my perspective, from this user's perspective. 6:20 And so this doesn't change what we're looking at here. 6:23 But actually, I can switch between them. 6:27 So here's the new profile header component from my other user. 6:32 And, you know, you can see there are like all these different ways to look at the profile. 6:36 Right? 6:37 Like what makes a profile a profile. 6:40 Even like something like— like BDSLS shows it. 6:45 And so, okay. 6:47 So, I made this profile header. 6:48 But this profile component written by somebody else, it doesn't use that header. 6:53 Right? 6:54 But what I can do is again I can click Remix here. 6:57 And so, now we're going to— Wait, is it going to the wrong thing? 7:02 I think it's going— let me just refresh just in case. 7:07 Yeah, it went to the wrong thing. 7:09 But here's the— so here is the profile component itself that contains— you can see it has the profile header. 7:17 It has the tabs with like posts and replies and kind of delegates to those. 7:23 It has the Circle tab. 7:25 I'm not going to need that because I'm I've moved the circle into— and I guess Paul doesn't listen to music, so it doesn't have till FM plays. 7:34 I'll just get rid of that too, actually, for now. 7:42 Yeah. 7:42 And so— but now we have two versions of the profile header, right? 7:45 There's one by Dan Abramov, which is the original one. 7:48 It's here. 7:49 And then there's profile header by my user, which is just created. 7:53 And so what I'm going to do is I'm going to slide this a little bit up so that it takes precedence. 8:00 So now the profile header is going to refer to the version that, you know, that I remixed from my user. 8:06 So this is kind of like a low-stakes way to, like, play around with, okay, this is what I think a profile page should be. 8:14 So I'm just going to, you know, I'm just going to publish this as profile. 8:18 And again, the, you know, it's— It's just an option here. 8:22 So now we can see that this is my take, you know, my user's take on what a profile page could be. 8:39 Okay. 8:40 So, of course, we don't want to always create everything from scratch. 8:43 Unless you're using LLMs. 8:44 I— this project is like very caveman mode, I'm sure. 8:48 There's like a way to get LLM to do this as well. 8:50 And I don't know if it makes sense. 8:52 But I'm just showing you kind of the vanilla version. 8:57 And so canvas, you know, this thing I'm calling it like a canvas, right? 9:02 It's just like this thing where you can kind of jump around and kind of see different things and pull them apart. 9:10 But one problem— that's my first prototype. 9:13 But I realized that, okay, like how do you actually discover these components that other people create? 9:17 And that's, you know, I made the editor, but then the question was, where do you find them? 9:22 So I realized I needed something like a browser too. 9:25 That's kind of like, I guess kind of like PDSLS, right? 9:29 So we could say, you know, if you've ever seen PDSLS, you know this interface where like you select the user and then you select the collection type. 9:42 And you can just, like, navigate between records, right? 9:44 So, this is kind of PJ SLS inspired. 9:50 But maybe you can, like, register these, like, other ways to view the same data, right? 9:56 That are, like, more human friendly. 9:59 And I'll just show you, like, the process for what, you know, what it feels like to create one of those. 10:05 So, I'll say I'll go to profile. 10:08 And again, like just a profile record, like looks like this. 10:12 This is a built-in component. 10:14 I'm going to create a new one. 10:15 Gives me this template with like stuff that's available. 10:20 And I'm just going to say, okay, like let's say I want, I want an avatar and it knows that, oh, like there's already a did here. 10:28 So it pre-fills it. 10:29 And I want like a, you know, I want like a title. 10:35 With, let's say, like Paul's display name, right? 10:38 So we put display name here. 10:40 And let's make this like a— oops, oops, oops— a row. 10:47 Okay. 10:47 So I'm gonna publish this as like profile example. 10:54 Okay. 10:54 So here's my profile. 10:56 Where is it in the list? 10:58 I don't see it in the list for some— oh, there it is. 11:01 So here's my profile example component. 11:03 Let's check that it appears in my other user's BDSLS. 11:10 So there it is, profile example. 11:14 You can see the, the tree and stuff. 11:17 So there are 3 types of inlay components. 11:21 So this kind of component is called a template component because the, the actual JSON for how to— for the UI lives directly inside the record. 11:31 So, you know, if Inlay dies, you can, you know, you can just interpret the same data and kind of bring it back to life. 11:41 But it's very limited, right? 11:42 Because I can't have— this is not JavaScript. 11:44 This is just like a JSX editor. 11:46 It's just like— it could have been like a block editor or whatever. 11:50 But it doesn't have like loops. 11:51 It doesn't have conditions. 11:52 It doesn't have like any fancy— you can't like hit another app view, another service or whatever. 11:58 So it's a bit limited. 12:00 But one thing we can do is we can eject. 12:02 I really like this feature. 12:04 I build it into everything. 12:07 Okay. 12:07 Wait. 12:08 I can't eject from this one because I haven't created token. 12:11 Let me use— let me just do the same example from my user where I already connected. 12:18 So there is this thing called valldown. 12:22 I don't know if you— Let me delete this. 12:27 Call this profile example. 12:30 Yeah. 12:31 So there's this thing called Valtown, which is like a kind of simple coding environment for publishing some server code. 12:40 Kind of like REPL for, you know, that lets you like run a server. 12:44 So when you press eject on a component, what it's going to do is it's going to hit the Valtown API, which is for some reason taking like 5 seconds. 12:54 And generate what they call eval. 12:56 So eval is just, you know, it's just a server. 13:00 And I made some helpers for this thing. 13:03 And like these are lexicons. 13:04 So it like gets type checked. 13:08 But this is, you know, this is my component. 13:10 Like I just moved it from here. 13:13 Now I can like call it. 13:14 So it's an xRPC call to that component, which means that I can, you know, I can treat it as code. 13:21 I could make, like, different, you know, API calls here or whatever. 13:28 And let's see. 13:30 Yeah. 13:30 You see it updated. 13:32 So it works. 13:36 All right. 13:39 Now I need to drink. 13:46 So, let's build another fun little component. 13:49 So, let's go to this— what is it? 13:55 No. 13:57 The you and me connection thing that everybody's been using at the conference. 14:01 Well, spoiler, I already made it. 14:05 Well, let me just delete it so I can demo it again. 14:11 Where is the— why can't I delete it actually? 14:14 Is it from a different— oh, I made it from a different account. 14:17 Wait one second. 14:18 I'll delete it. 14:19 Don't— close your eyes. 14:23 So that you haven't seen it. 14:25 And then I'll just make it again. 14:27 Okay. 14:27 It's gone. 14:28 It's gone. 14:29 So, we're going to make a little component. 14:31 You know, like, when you look at the PGSLS version of these connections, it's like what is going on here? 14:36 Subject did. 14:38 And so on. 14:39 So, let's see. 14:41 We're gonna create a little component that we're gonna take the DID of myself, you know, from the record. 14:49 And let's show maybe like an AVI handle. 14:55 Maybe it's not a bad idea. 14:57 And then let's take the DID of the subject and maybe also show an AVI handle. 15:02 And maybe let's like just just do some emoji like high five. 15:09 And yeah, so, and we're, and let's say we still add a timestamp. 15:17 Okay, so we're gonna publish this as a connection. 15:21 So now you can see, you know, you can see what's been going on. 15:24 Yeah, let's see, let's see who I said hi to. 15:34 Yeah. 15:36 Okay. 15:36 So, this is working. 15:39 Let's go back to the— let's go back to the profile. 15:48 So, I kind of have this playground where I can, you know, kind of just play with different components, kind of riff on them. 15:56 It is a bit tedious sometimes. 15:58 Like if I want to— like maybe I just want to change something globally. 16:01 Right? 16:01 Like in npm, like the model so far I'm following is similar to npm. 16:04 But like each component has dependencies. 16:07 And so like if you want to change something, you fork that component. 16:09 And then you kind of have to fork upwards the dependency chain. 16:13 But for example, in npm, there's this feature like resolutions at the top where you can just say, you know, for everything, I actually want to globally make something different. 16:22 So for example, like let's say, you know, like yesterday Paul was showing this example with removing the handles and just showing the display names. 16:34 Way ahead of you. 16:35 Well, the truth is I actually haven't built a handle component. 16:38 So I just literally can't make the handle work. 16:42 But I have a different idea. 16:43 So I kind of want to remix this Ivy handle thing. 16:49 Specifically, you know, I want to democratize education. 16:57 So I want to make us all PhDs. 17:01 So I'm just going to put PhD here. 17:05 And I'm going to publish that. 17:07 But now the problem is, okay, you know, like you want things to be predictable. 17:11 So you don't really want like everything to just fall apart because like you change one little thing. 17:17 So you kind of want to be like intentional. 17:19 About like do you want to like override something. 17:23 And so I'm not gonna like fork all the way to the top. 17:26 Instead, I'm gonna use something slightly different. 17:29 So I have this like stack feature here, which is kind of like a global resolution mechanism, which has like first, you know, you go through whatever the component author specifies. 17:40 And then you can fall back on like my versions of components if some are missing. 17:44 I can actually drag that up and say— whoa, wait. 17:50 Okay. 17:51 That was not intentional. 17:53 But we can pretend that this didn't happen. 17:55 So, you can, you know, you can say that I want to prefer this version that I, you know, of any component. 18:03 And so, when I drag this thing above, it means that it will prefer my versions of a component throughout the whole tree. 18:10 So this is why everyone is a PhD now. 18:15 Great. 18:22 Okay. 18:24 We're going to run out of time soon. 18:26 I just want to— I want to see why this broke, because I kind of wanted to show this. 18:30 So connection, resolve type connection. 18:42 So is it called— did I not save it? 18:47 Oh, it has a different NSID. 18:49 I created it from a different user. 18:53 OK, I'll just publish it from— yeah, I did not anticipate this. 19:02 One second, let me delete this. 19:03 And this is published by— it's not easy to be two different users at the same time. 19:14 Let me just delete this as if it didn't exist. 19:18 And I'm just going to create this again from my real user because that's what I'm already hardcoding somewhere else. 19:27 So this is my connection component. 19:30 Okay, cool. 19:31 And the— yeah, so the other thing I wanted to show here is— so feeds, right? 19:39 Like in feeds, we— like feeds are another area where there's like some providers of like the actual like feed content. 19:49 But the format of the feed itself is determined by the app. 19:52 And you can't really experiment with like what goes into a feed if you're not an an app author. 19:58 So, something, something I wanted to show here is that actually, like, if you look at the post list component where I'm— that is responsible for showing, you know, this list of posts. 20:11 If you look at its source, which is here, like profile posts, for example. 20:20 So, if you look at its source, The way it works is that it hits some JIT with a query. 20:28 Right? 20:28 So I'm calling this like get profile post page. 20:32 And I have this, you know, in my val town, I have— like I have a service running that is— wait. 20:42 Then this is not the one. 20:43 This one. 20:46 So this is the thing that generates the profile page. 20:51 The profile post. 20:52 And you can see that it hits the Booska API and then it just returns UI components. 20:57 Right? 20:57 So this is how— this is how we see, you know, like this stuff is coming from here. 21:04 And similarly, the media tab where we see a grid of those images, like it's not like hardcoded. 21:12 It's also like it's just a component hidden, a list of get profile media page. 21:16 And here it's like a bunch of blobs that are getting clipped as squares. 21:22 Or like get Teal.fm plays on— well, again, Paul doesn't listen to music, but if you go to my profile, yeah, you can— it's like everything is a little browser. 21:38 Yeah, if you go to my profile and look at plays, you see like it's— this is Teal.fm plays. 21:45 And it just, you know, this is how it works. 21:47 It just fetches the collection and renders an array of chillplay components. 21:54 But, you know, what if you want to experiment with the content of those feeds themselves? 21:59 And so actually each of these, you know, like I provide these endpoints here. 22:04 But these are also dynamically bound. 22:07 So the way it actually works is that in my pgsls. 22:11 There's an endpoint collection that says to get, you know, get profile posts page gets resolved to a service running here, which is, you know, this code. 22:25 And so this is how it renders an array of posts. 22:28 But what my other user does, so my other user has— also has an endpoint record for the same endpoint. 22:38 And it says, actually, let's hit this other, you know, let's hit this other service. 22:43 And this other service is— here it is. 22:49 So this is a different implementation of the get profile posts page. 22:53 And here it fetches the posts. 22:55 But it also fetches the you and me connections. 22:59 And, you know, and the element is just like a connection, the connection component that I created earlier. 23:07 And it kind of just interleaves them. 23:09 And so this is when, you know, when I prioritize— sorry, in here, when I prioritize my other stuff in the stack, then this is why it's going to just— yeah. 23:22 Like it's just going to show them inline. 23:24 So this is something that you can also experiment with. 23:26 Yeah. 23:32 And, you know, this is— This is just a prototype. 23:35 Like, I don't know if it's— I made, like, I've coded, like, a Swift UI client for it. 23:39 So I said there are 3 types of components. 23:44 There's template components that are the UI lives in the record. 23:48 There's external components, which are, you know, the ones that are ejected, which hit, like, a service or, like, a Val or your own server or whatever. 23:57 And the third type is built in. 23:59 And so when you looked at the— you can see the red ones are overridden from the stack. 24:09 So it's like, I want to do something different here. 24:12 So you can see that here, these are the built-ins. 24:17 So they don't have any implementation on the protocol. 24:21 This is something that the design system implements. 24:25 And I have my own design system that is what I'm using here. 24:29 All this row, caption, avatar, all this stuff you've seen. 24:32 But in principle, you could make, you know, you could fork my— I just open sourced Inlay, so it's on Tangled. 24:40 Or is it Tangled Inlay? 24:43 Yeah, there it is. 24:45 So the app is also open source. 24:49 So, you know, you can fork it, you can make your own version. 24:51 You can decide to have a different set of primitives and to I made these primitives to be cross-platform, so you could make a SwiftUI client for them or something else. 25:03 But you could make them closer to HTML if you want. 25:05 And yeah. 25:06 This is just an idea I'm kind of throwing out. 25:08 I'm probably not going to maintain this forever. 25:11 But it's on the protocol. 25:13 So, in some sense, it is maintained forever. 25:15 So, thank you. 25:21 Oh, I forgot. 25:22 Yeah. 25:22 It's called inlay. 25:24 It's like inlay.at. 25:26 Yeah, this is how you find it. 25:29 OK, sorry. 25:29 Bye.