WEBVTT 00:00.000 --> 00:13.400 Now, I have the pleasure to welcome you, Seth, who was also cognizant of this devroom and 00:13.400 --> 00:14.400 Nick. 00:14.400 --> 00:21.320 They will talk about blocknote, prosmeagall, and YGS version 14, versioning, and track changes. 00:21.720 --> 00:24.120 This way, come then, there's a round of applause. 00:30.120 --> 00:31.720 Nice, thanks. 00:31.720 --> 00:40.000 Welcome, so we're Nick, and I'm YSF, together we work on blocknote, which is like a notion style 00:40.000 --> 00:45.320 of rich text editor that makes it like tries to hide away all the annoying rich text editor 00:45.320 --> 00:49.720 stuff and tries to make it easy to add a modern rich text editor to your app. 00:49.920 --> 00:55.920 For that, we built a lot on top of YGS, well, I don't need to introduce that anymore. 00:57.120 --> 01:02.720 I do need to introduce Kevin, like of course, we all rely on a lot of his work for YGS, 01:02.720 --> 01:09.920 and in this presentation, we'll introduce the work that we've been prototyping in November 01:09.920 --> 01:17.520 and December, together with Kevin, and it's our honor to also share a lot of the work he has been doing. 01:18.520 --> 01:24.920 Unfortunately, for him, he's out on the slope skiing, well, we are having fun at Boston. 01:24.920 --> 01:29.520 So he's certainly could make it, but he definitely says hi. 01:29.520 --> 01:39.520 This work has been sponsored by Zendis and Dinam, so these are respectively initiatives in Germany and France 01:39.520 --> 01:45.520 to advance our digital autonomy, so they're building a product that's called last week's docs, 01:45.520 --> 01:51.520 and they're building it in-house, which is like a new software for public servants to collaborate together 01:51.520 --> 01:56.520 and reduce the dependency on big text software. 01:58.520 --> 02:05.520 Quick overview of what we'll be going through, so I'll explain what we're working on, 02:05.520 --> 02:12.520 there will be a short demo, we'll do an architectural overview, and then Nick will dive deep into, 02:12.520 --> 02:17.520 what does that mean in terms of like the new APIs that we're bringing to YGS, 02:17.520 --> 02:24.520 that unlock all these kind of things and the new things in lock nodes and Y pros mirror as well. 02:28.520 --> 02:29.520 So what are we talking about? 02:29.520 --> 02:34.520 There's two main subjects that we're trying to add to make possible within the new versions. 02:34.520 --> 02:39.520 It's suggestions, track changes, so if you know you're in a doc style document, 02:39.520 --> 02:46.520 and you enable suggestion mode from that on everything that it becomes a suggestion and not an added to the original document, 02:46.520 --> 02:54.520 and attributions and attributions is like metadata with which you can get detailed version history, 02:54.520 --> 03:00.520 so not only compare to versions, but really also see who did what in which version of the document. 03:09.520 --> 03:16.520 It should be a video here, it's not loading, but everybody knows how I'll just walk through it. 03:16.520 --> 03:23.520 So you probably know the Google Docs style track changes suggestions, so once one user proposes a change, 03:23.520 --> 03:27.520 it turns up and green, if you remove some text that turns up and red, 03:27.520 --> 03:34.520 and then the author of the document, for example, can accept and reject certain changes. 03:35.520 --> 03:41.520 You can also hover changes and see who made that change and who did it when. 03:41.520 --> 03:44.520 And the demo was showing it within block node. 03:44.520 --> 03:46.520 We're intended to change. 03:46.520 --> 03:51.520 I'm not sure whether it's not set setting up, but I'm glad we got this screen connected at all, 03:51.520 --> 03:55.520 so I'm not going to be bothered by the diving in further. 03:55.520 --> 04:00.520 So once it's talk a little bit about the architecture of how we want to make this possible, 04:01.520 --> 04:07.520 like a very naive approach might be, okay, you enter suggestion mode, and from then on everything that you type, 04:07.520 --> 04:16.520 we just store as something instead of marking something as bold that you type, we mark it as an insertion that's like pending. 04:16.520 --> 04:21.520 Now we don't want to do this, so this is like, okay, we consider that a better idea to store it in a document, 04:21.520 --> 04:28.520 just have, hello, as the original thing, the mark something as deleted and the mark something as inserted. 04:28.520 --> 04:32.520 Now why do we not want to follow that architecture? 04:32.520 --> 04:35.520 First of all, we want to do this in a secure way. 04:35.520 --> 04:41.520 So if you do it like this, the suggesting user, the user who is making changes while suggesting mode, 04:41.520 --> 04:44.520 would need to make these changes in the original document. 04:44.520 --> 04:51.520 But maybe you want to add support for suggestion only users, so those are users who only have permissions to make suggestions, 04:51.520 --> 04:57.520 but not the permission to edit the underlying the original document. 04:57.520 --> 05:09.520 So that's an important reason, and the other reason is, in general, we don't think it's a good concept to think that suggestions are part of the original document. 05:09.520 --> 05:19.520 And to really decouple this, it also unlocks a lot of innovative use cases, novel experiences in which users can collaborate. 05:20.520 --> 05:26.520 Maybe also worthwhile to point to some of the research done by InConswitch and Peter Steam. 05:26.520 --> 05:31.520 I think mostly in the patchwork projects. 05:31.520 --> 05:37.520 The authors are right here also, who show, okay, we can think about collaboration in different ways. 05:37.520 --> 05:44.520 But if you want to unlock that, you do need to separate these concerns and really have different versions of these documents, 05:44.520 --> 05:52.520 and then decide how you want to present that to the user. 05:52.520 --> 05:55.520 So, how do we make this possible? 05:55.520 --> 06:01.520 The architecture that we are going for is to model things similarly to get branches. 06:01.520 --> 06:08.520 So suggestions are like get branches, so you can imagine, okay, instead of everybody working in the same documents, 06:08.520 --> 06:16.520 you use the who starts suggesting kind of like branches and new YGS documents and starts making the edits there. 06:16.520 --> 06:22.520 Now there's a couple of changes, if you, differences, if you compare it to get. 06:22.520 --> 06:28.520 When you're in a suggestion mode, you also want to see what happens to the original document. 06:28.520 --> 06:35.520 So it's kind of like the base, the changes from the base are continuously streamed in to the fork that you're working on. 06:35.520 --> 06:37.520 So that's a third one. 06:37.520 --> 06:40.520 Then there's also like different user modes. 06:40.520 --> 06:43.520 So you can have a user that's suggesting changes. 06:43.520 --> 06:48.520 Well, that's fairly easy, you just made all the edits that that user make. 06:48.520 --> 06:54.520 Go to the fork, so to the other new fork YGS document. 06:54.520 --> 07:01.520 If you turn suggestions off, it's also easy, you just, all your edits go to the original YGS document. 07:01.520 --> 07:05.520 So you're working on the base branch, so to say. 07:05.520 --> 07:09.520 It gets a little bit different in the more difficult in the third scenario. 07:09.520 --> 07:11.520 I'll explain that in a bit. 07:11.520 --> 07:15.520 Because now what happens, this is what I just explained. 07:15.520 --> 07:20.520 So okay, changes made, if you're looking at the base document, just go here. 07:20.520 --> 07:29.520 Changes from the base are continuously synced to the branch, because you want to make sure you want to have that live feeling and see also what you're suggesting. 07:29.520 --> 07:38.520 Not on a previous version of the document, but on the actual live latest base document. 07:38.520 --> 07:45.520 But you can also have the edit view where you're making suggestions and you see both at the same time. 07:45.520 --> 07:50.520 Now it will depend if you're the original author. 07:50.520 --> 07:54.520 The system needs to know where should that change go. 07:54.520 --> 07:56.520 Should it go to the base document or to the branch? 07:56.520 --> 08:02.520 If you work in a way that, okay, if you edit in hello, it will commit that to the base branch. 08:02.520 --> 08:06.520 But if you make a change to Brussels, that word actually doesn't exist in the base branch. 08:06.520 --> 08:11.520 So the update will feel there and when it feels, it will actually make it to the suggestion branch. 08:11.520 --> 08:14.520 So that's how we recognize where to make these changes. 08:14.520 --> 08:17.520 And why do you have handles that internally? 08:17.520 --> 08:21.520 Soon. 08:22.520 --> 08:28.520 Then attributions, so hold off on suggestions and instructions for a moment. 08:28.520 --> 08:30.520 So we're also working on attributions. 08:30.520 --> 08:37.520 And this is the reason for this is, okay, we want to go back in time in the document and be able to see who did what went. 08:37.520 --> 08:42.520 And as you might know, in YGS, every character can be uniquely identified. 08:42.520 --> 08:47.520 And attributions basically are a character level metadata. 08:47.520 --> 08:54.520 So, yeah, you can attach metadata to specific ranges of YGS. 08:54.520 --> 08:56.520 YGS IDs. 08:56.520 --> 09:03.520 For this, Kevin has worked on a more efficient data structure to store this kind of these ranges and to map that with your metadata. 09:03.520 --> 09:06.520 So we go set an ID map. 09:06.520 --> 09:09.520 But the metadata itself, it can be application defined. 09:09.520 --> 09:12.520 So it's not tied to author information or timestamps. 09:13.520 --> 09:17.520 If you like, you can, like, I don't know, as a user is typing, 09:17.520 --> 09:19.520 store the current weather information. 09:19.520 --> 09:26.520 And I'm sure if you look at my stuff that I write, my write, write something better when the weather is good. 09:26.520 --> 09:28.520 And maybe I get very depressed. 09:28.520 --> 09:36.520 I don't know, whatever is relevant for your application. 09:36.520 --> 09:40.520 Yeah, now, okay, let's have a look at what makes this possible. 09:40.520 --> 09:45.520 So to make this possible, we've been able and Kevin, and Nick, particularly, 09:45.520 --> 09:51.520 they've collaborated a lot on making this possible in YGS and Y prosumerer. 09:51.520 --> 09:57.520 And Nick will go through the different changes that you can expect in YGS 14. 09:57.520 --> 10:05.520 Yeah, so, as you said, men's in Kevin has done the bulk of this work, obviously, 10:05.520 --> 10:09.520 and it's an honor that I'm able to present it. 10:09.520 --> 10:15.520 So to put this in perspective, YGS 13 was cut six years ago. 10:15.520 --> 10:20.520 And Kevin has anxiety, every single time he pushes the release button, 10:20.520 --> 10:25.520 because it affects millions of applications. 10:25.520 --> 10:28.520 And there's so much impact to this project. 10:28.520 --> 10:35.520 So with YGS 14, there's a number of large updates that have been made. 10:35.520 --> 10:44.520 And so this is an overview that I'll go through as we talked about it. 10:44.520 --> 10:55.520 So one of the changes that we've made with YGS 14 is, as we were working on the code base, 10:55.520 --> 11:04.520 we realized that, and I'll say we, but this is all Kevin, it's just easier to say it. 11:04.520 --> 11:11.520 So we realized that what it turns out is that all of the underlying operations 11:11.520 --> 11:15.520 were operating on the same sort of data structure. 11:15.520 --> 11:20.520 And you can actually represent most of the data structures that YGS supports, 11:20.520 --> 11:24.520 so anything that's basically in a JSON sort of format. 11:24.520 --> 11:29.520 You can map them one to one to some sort of an XML. 11:29.520 --> 11:35.520 So for example, you have this Y text that is just a non-named XML fragment, 11:35.520 --> 11:40.520 that has no attributes, and it has children as plain text content. 11:40.520 --> 11:45.520 And array is just a number of items within that same sort of fragment. 11:45.520 --> 11:50.520 A map is some sort of a key value attribute pair. 11:50.520 --> 11:54.520 And an XML element is the full blown thing. 11:54.520 --> 11:58.520 It has a name, it has attributes and children inside of it. 11:58.520 --> 12:02.520 So it was a huge simplification to the code base. 12:02.520 --> 12:08.520 It was beautiful to see the GitHub PR to see that thousands of lines were deleted, 12:08.520 --> 12:10.520 and only a few hundred added. 12:10.520 --> 12:15.520 So we were able to completely remove all of the other types. 12:15.520 --> 12:21.520 And now there's just one type that is based on this XML structure. 12:21.520 --> 12:28.520 And you can define a schema to your YGS document that will actually differentiate between these types, 12:28.520 --> 12:30.520 so that you still know what's inside of. 12:30.520 --> 12:35.520 So this is, there's a strong schema that defines a YGS document now, 12:35.520 --> 12:43.520 rather than it just being a grab bag of whatever values happened to be set at the time. 12:43.520 --> 12:48.520 So now that we have this one unified Y type, 12:48.520 --> 12:53.520 we need to have a way to describe changes to the type. 12:53.520 --> 12:57.520 As part of the work for suggestions and attributions, 12:57.520 --> 13:04.520 it became clear that we needed a universal way to describe these changes, 13:04.520 --> 13:09.520 and Kevin has always been a fan of the Quill Delta format. 13:09.520 --> 13:13.520 And this is based on that format. 13:13.520 --> 13:19.520 So what, how we can describe a transformation from hello world to hello with the next formation point, 13:19.520 --> 13:30.520 added, is you can describe it as, as though you were, as though you were user interacting with it. 13:30.520 --> 13:35.520 So what you do is you move the cursor five, five characters over, 13:35.520 --> 13:38.520 you delete the world at the end of it, 13:38.520 --> 13:41.520 and then you insert the actual new character. 13:41.520 --> 13:48.520 So you're describing a change as all of the operations that you would do on the document. 13:48.520 --> 13:54.520 So with this ends up being, is that there's a literal array that describes all of the changes. 13:54.520 --> 14:01.520 This is a very similar to OT for those that are familiar with this. 14:01.520 --> 14:09.520 But what ends up happening is that we have a transaction log of all of the changes that have happened to a document. 14:09.520 --> 14:13.520 So you can do a lot of things with this transaction log. 14:13.520 --> 14:21.520 So not only do you can apply this to a Y type to get the output to actually apply, 14:21.520 --> 14:27.520 and do that in a way that is obviously CODT based and using the Y adjust data structure. 14:27.520 --> 14:32.520 But you can also operate exclusively on these operations. 14:32.520 --> 14:38.520 So you can merge several operations together to get one change. 14:38.520 --> 14:40.520 You can re-base operations. 14:40.520 --> 14:46.520 There's a whole bunch of new functionality that we can do. 14:46.520 --> 14:51.520 So getting back to suggestions and attributions here. 14:51.520 --> 14:56.520 This is a little bit about how the attribution manager works. 14:56.520 --> 15:02.520 I didn't want to go into the details of how this is actually represented, 15:02.520 --> 15:07.520 like in the data format using IDSats, ID maps. 15:07.520 --> 15:14.520 So I wanted to just explain this in a way that it's a little bit more palatable for the average developer, 15:14.520 --> 15:17.520 but please ask me more about this later. 15:17.520 --> 15:31.520 So what I did here was explain a YJS update as there's the actual content of what has actually changed within the update. 15:31.520 --> 15:36.520 So for example, this is an addition of hello. 15:36.520 --> 15:41.520 Normally this would be a character level and this describes a range of updates and they're merged together. 15:41.520 --> 15:44.520 But this is a simplification. 15:44.520 --> 15:47.520 And then there's also a number of ID metadata. 15:47.520 --> 15:50.520 So I'm referring to it as a content ID here. 15:50.520 --> 15:54.520 But it's think of it as some sort of a version identifier. 15:54.520 --> 15:59.520 This is the version that was applied to the YJS document. 15:59.520 --> 16:03.520 It can get complicated to explain CRDT things. 16:03.520 --> 16:10.520 So I feel like it was just easier to describe the attribution manager as essentially a map between those versions, 16:10.520 --> 16:15.520 which technically describe multiple changes. 16:15.520 --> 16:23.520 You can describe ranges of changes, mapping those versions to actual arbitrary metadata. 16:23.520 --> 16:29.520 So I have that it's attributed to Nick and some sort of timestamp. 16:29.520 --> 16:34.520 It can be any sort of Json representable metadata. 16:35.520 --> 16:45.520 So then once we have that in the attribution manager, this attribution manager is meant to be stored in a secure way. 16:45.520 --> 16:52.520 So for example, this might be stored on a central server if this is your off model. 16:52.520 --> 16:58.520 It could be some sort of a peer-to-peer system, some sort of trust model, whatever it is. 16:58.520 --> 17:03.520 The point is that it's a separate store of this attribution metadata. 17:03.520 --> 17:08.520 So that you can be sure and confident in what's inside of it. 17:08.520 --> 17:17.520 So you can't have in personation of users or anything like that to say that who made what update at what time. 17:17.520 --> 17:20.520 That's essentially what this store is meant to do. 17:20.520 --> 17:27.520 So once we have that store of data, then there's we have a lot of flexibility on how we actually read out that data. 17:27.520 --> 17:29.520 We can ask for specific ranges of versions. 17:29.520 --> 17:36.520 We can ask for what content is what is attributed to what. 17:36.520 --> 17:42.520 So for example, you could say that like, okay, this range of characters is owned by Nick. 17:42.520 --> 17:48.520 Yes or no, whatever, and you can pull out that data from the store. 17:48.520 --> 17:55.520 So one way of pulling out that data is through this concept of a content renderer. 17:55.520 --> 18:02.520 And this gets more to the level of what I actually got to work on. 18:02.520 --> 18:06.520 So for example here, we have two documents. 18:06.520 --> 18:22.520 Now what we can do is the content renderer's job is to take external sources of data and represent them in a way that it can still. 18:22.520 --> 18:25.520 You can still modify the source documents. 18:25.520 --> 18:34.520 So it's using, for example, you can take the diff between two documents and you can show what was actually changed. 18:34.520 --> 18:40.520 So this would be represented as you get the entire document content as a delta. 18:40.520 --> 18:43.520 And then you dip the two deltas to see what is actually changed. 18:43.520 --> 18:50.520 The content renderer is what is responsible for saying this portion of content was deleted. 18:50.520 --> 18:57.520 This portion of content was added between these two versions. 18:57.520 --> 19:02.520 Another use case for the content renderer is this attribution view. 19:02.520 --> 19:07.520 So what you can do is using the attribution manager that we showed before. 19:07.520 --> 19:15.520 You can take a range of content and figure out who was attributed to this content. 19:15.520 --> 19:23.520 Then on top of that you can do additional things such as dipping and attribution at the same time. 19:23.520 --> 19:33.520 So you are not only able to do a difference between the documents but see what was the attribution for that content. 19:33.520 --> 19:35.520 So this is very important. 19:35.520 --> 19:38.520 This is the core of what a track changes like feature is. 19:38.520 --> 19:42.520 We have separation of the content data sources. 19:42.520 --> 19:48.520 We have a separate store which is the attribution manager to store this all security. 19:48.520 --> 19:51.520 Okay. 19:51.520 --> 20:02.520 So then we have Wi-Pro's mirror which is Wi-Pro's mirror is we have Pro's mirror as a rich text editor for editing documents on the web. 20:02.520 --> 20:07.520 It's an industry standard and is what a document is based on. 20:08.520 --> 20:12.520 Wi-Pro's mirror is a binding between the Wi-JS document. 20:12.520 --> 20:18.520 That's in data and the Pro's mirror document that is in memory. 20:18.520 --> 20:24.520 So Wi-Pro's mirror's job is to then synchronize the changes between these two documents. 20:24.520 --> 20:33.520 So if a change comes in from a remote then that changes the editor state or you make a local change to your document. 20:33.520 --> 20:38.520 That sinks it back to the Wi-JS document and it sinks to other clients. 20:38.520 --> 20:41.520 So this is where everything pretty much comes together. 20:41.520 --> 20:48.520 We have the Delta format for actually being able to describe what those changes are. 20:48.520 --> 20:52.520 You have the content renderer for displaying those changes. 20:52.520 --> 20:57.520 And we have to completely rewrite the Wi-Pro's mirror binding. 20:57.520 --> 21:01.520 And with that there's a number of improvements that we've made. 21:02.520 --> 21:08.520 And one of them is to bring this content renderer functionality into that. 21:08.520 --> 21:16.520 And as part of that you would need to like be able to pause and resume sync because if you're in a dipping mode you don't expect to actually properly edit the document. 21:16.520 --> 21:19.520 If you're looking at like static versions. 21:19.520 --> 21:25.520 So there's a number of improvements that we've made. 21:25.520 --> 21:26.520 Thanks. 21:26.520 --> 21:27.520 I think that though. 21:33.520 --> 21:35.520 Thank you very much. 21:35.520 --> 21:36.520 You said a link. 21:36.520 --> 21:38.520 We will take questions in the room. 21:38.520 --> 21:39.520 Please raise your hand. 21:39.520 --> 21:40.520 All of you now. 21:40.520 --> 21:41.520 No harm any questions. 21:41.520 --> 21:43.520 We have one question. 21:43.520 --> 21:44.520 Two questions. 21:44.520 --> 21:45.520 Three. 21:45.520 --> 21:46.520 No. 21:46.520 --> 21:49.520 I may be not a question but a clarification. 21:49.520 --> 21:52.520 Like most of those features were already possible. 21:52.520 --> 21:56.520 But the way how they were implemented to permanent user data. 21:56.520 --> 21:58.520 This is how this features call it. 21:58.520 --> 22:11.520 VGS is that it's far from ideal starting from the fact that this is all data part of the data is part of the document itself. 22:11.520 --> 22:15.520 But now where the cabinet's work it will be much more powerful. 22:15.520 --> 22:20.520 And it will allow to have more features on top of that basically. 22:21.520 --> 22:25.520 I totally deferred to Bertosh for anything. 22:25.520 --> 22:26.520 Why did you just relate it? 22:26.520 --> 22:28.520 Is that any question in the room? 22:28.520 --> 22:30.520 More questions. 22:34.520 --> 22:35.520 Okay. 22:35.520 --> 22:36.520 So we can wrap it up. 22:36.520 --> 22:39.520 But I'm not sure if you want to add something. 22:39.520 --> 22:40.520 No, yes. 22:40.520 --> 22:45.520 Only that the largest 14 preview is available. 22:45.520 --> 22:48.520 But there's still a lot of this to quite some. 22:48.520 --> 22:54.520 It's like I would say alpha versus so we expected to be available later. 22:54.520 --> 22:55.520 This year. 22:55.520 --> 22:57.520 And then. 22:57.520 --> 23:01.520 Yeah, the then we'll also release the layers on top of it. 23:01.520 --> 23:04.520 So why pros mayor for the binding to raw pros mayor things. 23:04.520 --> 23:08.520 And then block notes our vision is to really provide a high level API. 23:08.520 --> 23:13.520 So really to abstract as much of this away for you and just say okay. 23:13.520 --> 23:15.520 Enter suggestion mode. 23:15.520 --> 23:17.520 And there will be a little bit later. 23:17.520 --> 23:21.520 But also hope to release that somewhere this year. 23:21.520 --> 23:23.520 Okay. 23:23.520 --> 23:25.520 Thank you very much again. 23:25.520 --> 23:27.520 Thank you. 23:27.520 --> 23:31.520 So.