Skip to main content
934

September 3rd, 2025 ×

We Built a Real-Time, Local-Data, Competitive Coding Game

or
Topic 0 00:00

Transcript

Scott Tolinski

Welcome to Syntax today.

Scott Tolinski

I'm talking deep dive into my Hack Week project, which is the SynHacks competitive coding game. This thing is going to be useful for us when we do our CSS battles. We can, code live in UI battles. We can have an audience watch us do it in real time and vote and all these great things. And I built this project on a stack that is going to change how I build apps, I think, forever because I I was so efficient with this, and I was so able to knock out so many things so quickly and iterate and build and have this thing be so fast and good. I wanna talk all about it. I'm gonna scream it from the rooftops, this stack here, because I I had such a a good time building this thing. So we're gonna do a deep dive in that. But before we get going, let me introduce my two wonderful esteemed cohosts today. With me, as always, is Wes Bos and CJ Reynolds.

Wes Bos

Hello.

Wes Bos

What's up? Excited to hear about your project. This is something that we very much needed, and it's amazing what you have built. So let's get into it. Thank you. Can you say any other nice things about me while we're Node nice things? That's about it. I've I'm not sure if you could see the picture I just drew of you on my Kapoo project, but,

Scott Tolinski

that's that's about as nice as I get. Okay. Speaking of pictures here, folks, this is going to be best consumed on video. There I'm not gonna say, look at this. Look at that. There will be things to see here, and there there will it will be a better video than it will be audio, but you will get a lot out of it if you are listening to, like, technical choices and things like that. I I'm a make sure to at least talk all about that kind of thing. So the general idea for this project and, keep in mind, this project was built for the century dot I o hack week. Century is the perfect place to track all of your errors Look at this ad read. Fun things and and just, like, make sure your stuff's working. And Sanity JS producing all kinds of really great features. And if the Hack Week JS any, vision into the future, the future of Sentry is very bright. I mean, even the immediate future of Sentry is very bright because they've been dropping new features left and right, like the, new SEER feature that allows you to fix and solve problems, get to the root of the cause of things with AI, and it is very good.

Scott Tolinski

And they have a pretty cool logo that CJ used in his Hack Week project. Okay. Head on over to century.i0/syntax.

Scott Tolinski

Sign up, get two months

Guest 2

Node freeze, and the coupon code tasty treat, all one word, all lowercase. That's right. I'm talking today, folks. Synhax.

Scott Tolinski

This competitive coding platform. It's built in SvelteKit.

Scott Tolinski

I'll talk maybe a little bit about the tech in a second. I just wanna maybe talk about the platform first. It's a competitive, coding platform where you can do a CSS battle, and it's a UI, HTML, and CSS where you code. The idea here is that you code on your own local machine in your own text editor, and you could see those updates happen in real time on the site. Audience can watch as things are being built in real time. When it's over, they can vote on who did the best or whose code they like the most. There's even a referee view so that you if you have, like, let's say, a producer named Randy, he could go ahead and manage the flow of battle. He could control the timing of things. He could give it over time. Typically, when we do these CSS battles, if you haven't watched those videos, give one of our CSS battles a watch. They're super fun.

Scott Tolinski

CSS battles are not practical UI. We're writing shapes.

Scott Tolinski

We're seeing who can do it in the least amount of code or the fastest. And that pretty much always leads to bad code, whether that is code that we're just squishing to be really small, impractical code, hacks of the platform, little things here and there. And, like, sometimes Wes lose just because the renderer JS like, I don't Node, you don't get a 100%. So I set out to solve all those issues and, build a platform where, you know, it's a little less, I don't know, a little bit more like let's build stuff. Like, Wes and I, we did a video where we were trying to code this button, this keycap button that you see on screen here.

Scott Tolinski

And that button had interesting interactions, whether that was animations or, active state or those types of things. And, like, that could never happen in the current CSS battles flow. So I took it upon myself to build something that would have allowed us to do that there.

Scott Tolinski

So what did I do? What did I choose to build it in? The stack itself uses Postgres as a database.

Scott Tolinski

It uses Drizzle as an ORM.

Scott Tolinski

It uses zero sync for the local data. And I've been able to connect those two. I can even, like, show some of that where, like, typically, what you're doing with, like, a schema is that you have to write a schema and you have that schema in Drizzle. Right? I was able to write the schema ESLint Drizzle and then use a really wonderful package, that connects Deno to Drizzle. So instead of having to write multiple schemas, I'm writing a schema once. You run a script, and that spits out, the zero sync schema. Now there's, ignore this permissions right now that says anyone can do anything because, I'm just sweeping down under the the rug right now. I don't need permissions. We don't need permissions.

Scott Tolinski

What that package allows you to do is just slurp up your Drizzle schema, and it generates you Node, and then it Bos it out as a schema that's ready for zero sync to use. So this is a generated one. I didn't have to manage this. I didn't have to type this at all.

Scott Tolinski

So that was really nice. One schema to rule them all. Right? If I need to make modifications, then I need to make modifications.

Scott Tolinski

And it also gives me types where I can just bounce the client side types right out of here. Mhmm. And and these are the client side types rather than the,

Wes Bos

database types. Can you show it at, like, actually working just so we can get a visual of of how it works? Which part would you Wes? Talking about tech. Like like, the actual battle part. You know? Like, I'm curious about, like, what is even being stored in the database. Yeah. But, like, let let's I wanna see it before you Wes. Before you talk about the the the choices.

Scott Tolinski

I'm talking about the DISH tech behind it. Okay? Alright. I'll talk about it in just one second when we talk about how it works. Okay? Because I think it's more important when you when we're looking at it to talk about how it works. The authentication is done with BetterAuth, and it uses GitHub OAuth. The UI is done with SvelteKit.

Scott Tolinski

And the, APIs that are interesting is the file system API, which is how we're managing to do that file stuff. I'm gonna spend a lot of time on that, because that's, like, a core part of this thing. Building a strategy. First things first, I build a read me, and Wes did a whole episode where I discovered planning. I wrote this read me by hand. This is this is not done with AI. I wrote this, and this was just like, what do I want it to do? What does a general schema look like? What are the even some of the routing structures? And this might not even be up to date. But I wrote this whole thing by hand before I wrote any Node, and that led me to be able to another thing I did, which I don't typically do, is I built the entire functionality, like the HTML and the JavaScript, the entire functionality, like the HTML and the JavaScript before ever writing a line of CSS.

Scott Tolinski

No CSS.

Scott Tolinski

No even thought to where things are gonna go in the UI. Just dump it on the page. The flow of the app should work. It should take you. It should do all the things you need to do, and then, I can get into the UI. So very two different strategies for me. I planned and I did, logic first. So, Wes, it's now time to see how this thing works. So, typically, what you would do in this app, you come in, you select a battle. There are sound effects. You guys probably can't hear them, and it would give you an option to select a battle. Now these Yarn, again, are just database records. You click a new, new battle. What it's doing is it's creating a record, for a battle.

Scott Tolinski

And inside of that battle, right now, there are no participants. So there's battle participants.

Scott Tolinski

So this is the Sanity view, the referee view, and you have the option of making a public or a private match. If it is a public match, then there's a watch link here ready for you to just share with other people where they could watch the battle as it's happening. There's options for a timed match will count upwards where when you submit your final code, the person who finished the fastest would be their time would be saved. And then there's the one I anticipate us using more, which is the timed match, which is how long this thing can be. So, like, if we're gonna do a battle that's twenty minutes, you could have this be twenty minutes. It puts twenty minutes on the clock here. And it shouldn't let me start this battle, but since this isn't grayed out, that means, maybe there's some missing logic there. But right now, there's zero participants locked in, so you have the battlers themselves, which are then going to be users. So from here, I would just click invite, gives me a link, and I head to this link. And this is the if you are a battler, somebody who's going to be competing in this, this is what you see here.

Scott Tolinski

Man, I got some CSS issues here. I should tune that up.

Scott Tolinski

Either way, if you are logged in to this app, you're a battler, you can join. Clicking join just creates another record, and that gets you in the lobby.

Scott Tolinski

So you'll be seen as the referee JS a participant, but not locked in, so you don't show up here yet. So you can be, like, potentially in the lobby, and then you could leave or join again. And then you could lock in, which allows you to essentially be in the battle.

Scott Tolinski

Now the interesting technical stuff when you lock in is that you'll notice here, there is code right here. It has an app already, which in the code itself, when you click lock in, what that's actually doing is it is accessing your file system, and it is creating a folder. If you do not have permissions at that point, it will prompt you for permissions to say, what is your your your your code here? That that prompting will also happen when you first log in to the app because this app does need your file system access. There is no editor interface in this thing for you to use. Otherwise

Wes Bos

I'm so excited for that because, like, we're every time we're using CSS battles, we're like, Emmett, don't have my shortcuts, you know, and I'm hitting all these random Scott it's it's so much better when you're, like, in your own editor and, like, comfortable, or you can just focus on the actual

Guest 3

Node and and getting the result out. It'll be much easier. I mean, this might be cheating, but we could use AI too because we have AI. AI too. Yeah. And it, like, like, pnpm HTML files. By the way. Yeah. So this is great. I think this is one of the things people want for CSS battles, even for, like, Node Warp. All these competitive coding platforms, you have to use their website.

Guest 3

This this is great. This is, like, the killer feature here, I think. I hate typing in a a GUI online.

Scott Tolinski

And so the the file system access checks for people who are interested in the code for how that works is that when the main layout after you are logged in Node, this is a layout file, I'm running a files dot check.

Scott Tolinski

Files is a custom Svelte state.

Scott Tolinski

So I'm running this function just whenever this file runs, and it just simply checks to see if you have access.

Scott Tolinski

And this is a big, old, giant, complex state object here. So, that check is really just saying, first, try to restore directory access.

Scott Tolinski

If that has not been restored, yeah, set the status to you or if it has been restored, then set you have access, and that will then not prompt the user again. Otherwise, set status to no access. And then, because that automatic access check, the browser does need user interaction before writing files.

Scott Tolinski

So it will prompt you to repermission it if you want to have access to writing files.

Scott Tolinski

And that restore directory, handle, the file system access is stored in a next DB outside of Deno sync. It is stored in a just its own pnpm DB because the you can't store that in local, storage or anything like that. I just have the the handle for the file system, being stored in an IndexedDB.

Scott Tolinski

I check to see if that's there. If it's not there, then I I re prompt and say, check for access to it if that fails. So, yeah, query permission. If the handle, has query permissions and the permissions are granted, then go look for the files themselves.

Scott Tolinski

Otherwise, then you are going to then request permissions at that point, and the user's gonna be prompted to say, alright. Let me let me give them access.

Scott Tolinski

So the file system stuff's interesting because, ultimately, what I'm doing is I am storing the the project folder handle, and then there's the individual project handle. The individual project handle is the mini folder. So I'll show you. There is what this does is like mini games or mini apps. What it does is it has a folder that stores all of the files for that game.

Scott Tolinski

And this is no different than that. It stores all of your battles in one folder, whatever folder you give it. And it does them based on the name of the battle themselves, which could be changed. It could be an ID or something like that. Sorry. We have two code bases here. So this is the file state, and it it gives you access. And so when you lock in, it creates a folder in the folder that you've given it access to, like the keycap button Node, and it and it has created these files if they didn't already exist.

Scott Tolinski

Okay. So it gives you you get a CSS file and an HTML file? Yes. And there's no head or anything like that. You don't have to link them because I wanted to reduce the amount of bloat here, especially if we're doing this in a battle. I wanted this to be like right now, this is actually interesting. I'm not sure right now if I change this, if it'll update live.

Scott Tolinski

Okay. It won't. I'm not pulling for this yet. Cool.

Scott Tolinski

Simultaneously, Wes, what it's done is it's added this code to the database.

Scott Tolinski

So it not only has a file system access, but it has the string of this HTML and CSS added as a string into the database.

Wes Bos

Okay. So that's that's what I was wondering is is how this all works. So you have your file system access, which is the the the browser is monitoring your local files for changes.

Wes Bos

And then when those changes happen, that's getting thrown into that's getting mirrored to zero sync, which will then, as quickly as possible, will then sync it up to the cloud or to the database.

Scott Tolinski

Yes. So let's say we wanna start this battle, and I can show you that in action. So we have Scott.

Scott Tolinski

We have the battle. I can click start, and the battle started.

Scott Tolinski

You could see automatically, I didn't have to do anything. It redirected the battle screen for the Node. And this over here on the right is the referee view.

Scott Tolinski

So I can I can hide the referee view for now or at least move it over here and focus on the coding view? The coding view just shows you the code, the target. This is the target, what we're trying to build, and this is the code that is active.

Scott Tolinski

So if this works right now, you can see when I click save, it immediately updated real time here. And the way this works is I'm simply pulling to check for file changes.

Scott Tolinski

So I'm saying, hey. Did CSS, did CSS change? If it changed, then update the database record, not update the UI. Update the database record. That updates the database record, which then in turn triggers a Deno sync,

Guest 2

update.

Wes Bos

And it changes the UI.

Wes Bos

Right. Which just happens automatically. Yeah. And you don't have to worry about like, I I immediately I was like, oh, but Node, like, do you send diffs of the HTML? Only a stuff that has changed. But the zero sync takes care of that with the crudites. Is that true?

Scott Tolinski

Yes. So there it it does it does, but, like, you gotta think about it this way. Since it's just a string, I'm not, like, breaking these out into individual components. It is sending that whole string over. But, like, it's it's minuscule, the amount of stuff we're changing. Right? We're not we're not building a whole app in here. So it doesn't need to send that much information.

Guest 3

Yeah. And I guess to to also take a step back, because you talked about the tech stack, but that that's why you chose XeroSync JS you basically get real time for free, you get diffing for free, you get reconciliation for free.

Guest 3

You're using their framework to automatically sync what the user is doing to the cloud, which means you could have a spectator view, you could have an admin view. Everyone else can see what everyone else is doing because of

Scott Tolinski

the zero sync architecture. Is that accurate to say? That's accurate to say. And, like, this is what the audience is seeing. The the UI could use a little bit of work, but the audience JS then able to see not only my code, but any of the other battlers' code.

Scott Tolinski

And as I'm coding itself, this again is all being propagated real time.

Scott Tolinski

Oh, there it goes. It's just slow. Yeah. There it goes.

Scott Tolinski

And, so that way, they could see in real time as I'm coding it, not just the UI, but they could see the code itself as we're typing it.

Scott Tolinski

And then they could actually click and use this thing as we're actively building it. So, again, like you said, yeah, it is it is just pulling that file. Because what we can't do is we can't check for partial file changes, so it's not going to update as I'm typing. So I can type here, and this isn't gonna update. But the moment I hit command s and the file saves, it happens. So it happens, like, automatically.

Wes Bos

I wonder if you could use Versus Node save without formatting on key up because, like, you don't wanna you don't wanna save every single second because then your your linters and everything rerun, but you you kinda do. Or even, like, the Versus Code has, like, a where you just, like once you stop typing for a second, it will save it.

Scott Tolinski

Yep. Yeah. You could solve all those in different ways if you if you don't wanna hit command s, or you might be the type of person who, like, doesn't want,

Wes Bos

try to save when it's in a broken state. Oh, it's true. Yeah. You don't want you don't wanna hit save until you, like, are happy. Otherwise, you send up broken changes.

Wes Bos

I love that.

Wes Bos

That's so simple.

Scott Tolinski

It's so simple. The whole thing ended up like like I said, the the tech choices and, like, I thought about this stuff for a bit. And when I had some of these epiphanies, I was like, oh, man. This rules. And then the fact that it just all worked out was, like, really super nice.

Scott Tolinski

This should also work too. I'm gonna try this here. I also made a breakout view. One of the things that we hate about debugging this stuff is that you don't get access to your dev tools.

Scott Tolinski

Because these are done in sandbox iframes.

Scott Tolinski

Okay. So we got a hydration mismatch error. Let's see if this works because this should work. We're gonna see if I type in here, if this updates in here.

Scott Tolinski

The hydrate it worked. It was slow. I don't know why it's slow, but it is slow. I'll have to figure that out. But you could you could then break it out and not have to debug it within an iframe.

Scott Tolinski

This is just straight just your CSS battle code and only your CSS battle code.

Guest 3

Can I just mention something that's a little bit confusing? And I think it's because you're using Scott.

Guest 3

I can't see your URL unless you hover over it. Because right now, it looks like every every single tab is local host, but this this is like a unique URL with the state in the URL. Is that accurate to say, like, this URL Correct. Points to the render view of player one, which is getting rendered in that little frame, but in this case, you're being able to see it full screen?

Scott Tolinski

Many times people would approach this as creating this URL and then using that URL in this iframe is the way people would often do it. But I'm actually assembling that iframe in a different way. So I'm assembling the iframe by getting the, HTML from the, database.

Scott Tolinski

And then where's the blob? And I'm creating a blob. Oh, no. Sorry. I'm using I actually changed the idea. I was using a blob at some point. All I'm doing is passing in the code.

Scott Tolinski

I'm running it through a processor here using a Svelte derived. So I'm taking the HTML and CSS.

Scott Tolinski

I'm deriving it into the final code, and I'm passing it as a source doc.

Scott Tolinski

Because of that, I can then use that again in another route using the SvelteKit kind of route groupings. That's a blank route that is simply just doing a query, deriving it, and then outputting it as code. So nice and simple.

Wes Bos

And when there's a change, that preview, it just refreshes the whole page, or does it I guess you could just replace the entire CSS.

Scott Tolinski

When there's a change, it's just treating this as a reactive value, and it's just rendering it with the add HTML reactive value in Svelte. It's recognizing a change here. It's rerunning this code. So what it's doing is it's recognizing a change to the hack itself. So hacks right here. Yeah. It's recognizing a change. It is rerunning this query, which is grabbing the current hack, and it is outputting it here.

Scott Tolinski

And then that gives me just the HTML and CSS as a string. I'm able to derive the full on HTML directly from that. So reruns this, reruns this, reruns that. Can I check for understanding? Like, initial page render,

Guest 3

server side render because it, like, loads the code and spits that out.

Guest 3

After that, line 34 is like a live query. Like, that code JS sitting in the browser, and if z.current.query.hacks changes, that just updates in real time in the browser with JavaScript. Is that accurate to say?

Scott Tolinski

It is not because there's no server side rendering.

Scott Tolinski

And this only reruns yeah. When does this rerun? Yeah. Z XeroSync knows when the hack has changed and that that chooses to rerun this.

Scott Tolinski

What's so great about Xero is that I set up all my relations.

Scott Tolinski

So, like, I I did it so you can get any data from anything at any point, and it's all become super fast. So I can say, give me the battle where we're getting the ID from the params. Give me only one of them, obviously.

Scott Tolinski

Give me the related referee, all of the related participants, and then give me the related users of those participants, and then give me the target itself. Mhmm. And then it just spits us all out into a view big old beautiful object here that we can,

Wes Bos

UI. So Man, I I love the simplicity of just using the browser to render HTML and CSS, because I'm thinking, like, oh, maybe you could hook up, like, Vite virtual modules. But I don't think that you need that. No. Because, like like, CSS support is is so fantastic in all the browsers Node. And, of course, we'll be using the the latest one. Right? You can use all of the

Scott Tolinski

features. I don't think you'd need, like, a bundler for any of those. You can use whatever CSS you want to that's being supported in the browser that you're working in. It just needs file system access is the only limit here, is that you need that file system access.

Wes Bos

And this is being done with highlight JS, by the way. They just just that. Yeah. As we're developing this, right, like, you wanna have a a pane open to watch it as your your thing. Is it is that fast enough to be to, like, see your your real time changes, or would it be better to, like, run a, like, a Vite server locally to just see your changes as well? You tell me.

Scott Tolinski

So here, we have, like, the background. I'm gonna change this background to green. I'm gonna do command Wes, one, two, three, command s. It's instant.

Scott Tolinski

Yeah. Because, ultimately, what this is doing, Wes, the reason why it's instant JS because, yes, this is persistent. Yes. If I refresh, these will save. Right? But what it's doing is Wes I click command s on this, it's pulling. It's looking 10 times a second for changes on this thing. Okay. If it sees a change, then it saves it immediately to IndexedDB.

Scott Tolinski

It doesn't go off to the database elsewhere. This is gonna be just as fast if you were running this on a server. Is local first. You don't care about the database. It's saving its IndexedDB and then updating your your queries using, just a a Svelte state using zero sync. So there's there's no reason why this shouldn't be instantaneous. Right? This should be as fast as as possible, the moment you hit command s. I had it as, like, a a four times a second polling, and that even felt instantaneous too. So, like The other way to talk about this is a optimistic UI. Right? So the Yes. Locally, when you click command s, that's just you see your changes instantly.

Guest 3

There's some process to sync to the back end zero sync, but you don't care about that because you're seeing your changes instantly.

Guest 3

The only hiccup would be someone who's in the, the viewer Node. But even then, we saw it's, like, maybe two seconds just to see the latest updates.

Scott Tolinski

Totally. And that that yes. Exactly. And so that that yeah. That's pretty much the main crux of the difficult things about this. Everything else is just treating that zero sync as a source of truth for the state for the entire app. You had mentioned server side. This app is like running server side code, but the only time it's really running server side code is in the better auth stuff Wes I'm getting the current session and passing it into, server side stuff. And then I am using that in some routes to do some auth checks.

Guest 3

Oh, sorry. There's the server side is equal to false. Yeah. I am doing it for auth check server side. There's a whole admin section of this. Mhmm. So for that, I I kind of brings up for me questions about how to use zero sync because I haven't used it before. So, like, that page that was rendering the hacks,

Scott Tolinski

the code to query Deno sync is code that would only ever run on the client. Is that accurate? Is it that's not server side code? Correct. Yes. Okay. Yeah. K. Yeah. Pretty much anytime you're doing data querying at all with Xero, it is client side. Your or SSR equals false for any component that's touching. Otherwise, you're gonna have a bad time. That's for sure. Yeah. If you wanted to do server side stuff, would that actually just be writing to a Postgres database, or or is there a server side component of the of the XeroSync library as well? Well, the cool thing is that I do have Drizzle. So I would use Drizzle for that. Yeah. And I I have Drizzle ready to go. Data loading and all that stuff is is yeah. It's, it's all handled via these queries. And this is using my own Xero Svelte library, but it is. Every single time I wanna get data, it looks like that as the query, regardless of what it is. Yeah. Sweet. And this is reactive automatically right here. Yeah.

Wes Bos

Probably need to run it through, like, a Dom Purify.

Scott Tolinski

Yes. Yes. People could people could put a script tag in there. Right? Let me tell you. There's a number of things. There's a number of reasons why this isn't public right now.

Scott Tolinski

The DOM purifying stuff is one of them that I haven't gotten done. Another one JS, like Wes had mentioned earlier, if you go inside of permissions permissions, anyone can do anything, which is a nice little helper that Xero gives you. Permissions code in Xero is super easy. I am passing the correct information into this. I just haven't written this code yet, which is checking server side auth roles and things like that, IDs, just because, I wanted to get the whole thing done and working. Other things that are interesting about this is the countdown clock is really just, like, constantly checking if the battle end, which is stored in the database.

Scott Tolinski

If the battle ends at is, greater than right now, then the battle's over. Otherwise, you know, just update the countdown, and that's that's pretty much it just at a a a interval.

Scott Tolinski

Once the battle is over, it automatically updates the database, which, again, the way XeroSync works, you update the database. Everything else happens reactively. So that way, I can do pencils down, modals take over. It gives our producer a chance to say, yes. This battle is over, or the, we need to extend this into to overtime.

Scott Tolinski

So that's how that works. I'll show you a a battle that we had completed so that's so we don't have to wait for this one to wind down.

Scott Tolinski

So past battles, this one has all three of us in here.

Scott Tolinski

This is a a these are real users, so this is what this wasn't, like, faked or something. These are are real users. I just made you guys user accounts that can't log in but update the picture.

Scott Tolinski

And there are two views for this. This is the recap view. Again, this one's gonna be much better if you are watching this. But if you are somebody who's in the audience, you will see something that looks like this, where you could see their Node. You could see the app that they built. You could try it out. And then we can come in here and say, alright. Scott's gets three stars.

Scott Tolinski

It is, not feeling so good, and it's not accurate at all. And that does some fun things. It updates the score, which is just an average of all three of these, and it changes my profile photo to be angry. The profile photos are based on the place that you've landed. So first place is laughing, second place is sad, and, last place is angry.

Scott Tolinski

So, there's also some neat stuff. You can see that the numbers get bigger. I thought that was, like, a fun little touch. Like, if you're in first place, your score is the the largest.

Scott Tolinski

So I was trying to go for, like, video game UI with a lot of this stuff.

Scott Tolinski

Right? Yeah. And and there's a nice little animation, that happens, of course. And then in addition to that, the, battlers can also rate the battle on how they felt like it was fun or whatever. But, again, this all happens in real time. So theoretically, there could be a ton of chaos that comes from a bunch of people voting on this all at once. Because right now, what you're seeing is, like, the average of, you know, one voter Scott. But, really, this number would be changing constantly, and these photos might be, like, changing constantly, which I think would be a lot of fun.

Wes Bos

Man, even I'm just thinking, like, when we go to conferences and do, like, a live syntax, this would be perfect to throw up on the projector.

Wes Bos

And, we could all be hacking on our own. Yeah. Let people vote in real time.

Guest 3

This is great. All you need Node a GitHub account. Yeah. And it's a perfect way to let the audience see something interesting because it's always hard when because you guys have tried to do live coding before, but it's like, you're too busy coding and, like, you're not interacting with the audience. But, like, you could have a commentator that has this public page up and is basically live commentating what the people coding are doing JS and,

Scott Tolinski

getting audience reactions and stuff like that. One cool thing too is that with user's permissions, this doesn't work completely yet, so I don't wanna show this off. But with user's permissions, it generates these Sanity photos from your GitHub profile picture.

Scott Tolinski

And there's a simple prompt that gets that I found it to be very reliable.

Scott Tolinski

And one thing that you may have noticed is that there was no loading time between any of these pictures, and it's not done via preloading.

Scott Tolinski

It's just done via a very, smart way of loading those images. I think they're in static. It's just a four pane image.

Scott Tolinski

So the the emotions are in four different panes in one image. So I'm just changing the position of the image to show the different states. So it only has to load one image for each other. Sprite. I was gonna say. I made a sprite. Yeah. You made sprites just like me. Yeah.

Scott Tolinski

I did not do sprites in my project. Does the AI generate it as four pane, or you assemble that? Oh, okay. Yeah. Awesome. Yeah. So I just have a prompt that's been very reliable in terms of giving me the emotion, the four panes. I mean, I I use the same prompt for, four of these. So there's Wes. Although it gave Wes glasses. I'm not sure why it did that. I need to say something about and then I also did this one, which is the unknown faceless user for oh, this mouth is crazy. I didn't care about this because I'm only ever using the unknown user as their this face, this top one Wes they're because that's used before someone has joined the battle. Like, before they're in the battle, there's, like, a grayed out version of this. Yeah. This is scary.

Scott Tolinski

Sorry about that, folks.

Scott Tolinski

Yeah. That's all I got. I did, stuff you couldn't hear, like, animations and, sound effects and stuff in this thing too. Obviously, there's some CSS things, permissions things. Like I said, the data structure, everything is straightforward. You just have a node process for the app, or you can throw it on CloudFlare.

Scott Tolinski

It would work fine on workers, and then you need a a node process for Deno sync, and that's it.

Wes Bos

Man, and the the database is Postgres.

Wes Bos

Yep. So what do you think you're gonna gonna do? I Wes, because you use, does XeroSync has to be Postgres. Is that true?

Scott Tolinski

Yes. Yeah. Okay. Yeah. Yeah. I I just yeah. Just to have some basic Drizzle commands, throw it up somewhere, change the URL, push those commands, and then that's good. As far as dependencies go, you might all be surprised to know I am not using very much. I did use Wes Awesome for the stars component, and I used it for this tab component, but I'm gonna move it back to Svelte because, man, web components do some weird stuff. Like, this is being cropped right here, and there's absolutely nothing I can do to give this, height to get it to fill this space unless the I don't I don't I couldn't tell you why it doesn't fill the space. I've, like, gone nuts trying to figure that out. But other than that, yeah, I used a I'm not using this. I used a split pane thing for the split panes, zero svelte for zero svelte, svelte highlight for the highlight, Node ID, drizzle zero.

Guest 3

I had to use dot e n v because, I think BetterAuth uses that. And then I use tan stack table for the admin stuff. And then are you storing images in s three? I will be. That's why this is here. Last question I have is how do you create new battles, and what does a new battle consist of? Like, is it an target image and then, like, example files?

Scott Tolinski

So you would create a a new target JS the language.

Scott Tolinski

So a new target only is possible for admins right now. So if you were not an admin, this wouldn't even show up. That brings us into the admin section, which we don't need to spend a lot of time on. But, theoretically, the way this was built is that a target could be an image.

Scott Tolinski

In that case, you just give it a URL.

Scott Tolinski

It could be a video, which I would like to have hosting as well. So, like, the button that we had, Wes and I were doing, had a scrubbable video. That would be perfect to to throw them here as a video.

Scott Tolinski

Or it could be code, in which right now it's just paste code snippet, and that's a pain. But I would like to have a better way to do this Wes you would actually be able to have a target as code that is not revealed to the user so that way they could physically interact with the target as code.

Scott Tolinski

And then the image URL's a a thumbnail preview image that would just be generated.

Scott Tolinski

Again, yeah, targets exist here. You create a target. You update them here. This is what they're looking like currently. And, again, I have this whole admin section, even with fuzzy, searching.

Scott Tolinski

Like, I've I built a lot for this thing. It it's pretty crazy. What you can get done in a week. I I know that you killed yourself for a week, but it's like Yeah. It's a full ass app. It's a full ass app for sure. So, folks, this will be available to use at some point Node too long because I I don't think the things are like, a lot of it's UI stuff here and there and and flow, but I would love to get this in the hands of people and uncover, like, what needs work on it. I think we're gonna at least use it for a CSS battle or two here first.

Scott Tolinski

You know, hopefully, those go successfully, and then we can open up to the wider audience. We can add more targets to this thing so that way there aren't just these two targets. I built a lot of components for this, even like the UI components. Again, I know I use no UI libraries. I just used my own two hands.

Scott Tolinski

Scott of stuff. Cool. Well, that's it. I hope you guys found this interesting ESLint. Let me know what you wanna see inside of SynHacks because, again, there's so many things to do here, and, I have been so able to rapidly iterate on this thing that I feel like I can knock out all kinds of stuff. I even have a to do list doc, the, AI avatars Node to get finished, some styling stuff. I would like to have revealing too. Maybe they can use the code without knowing who wrote it first.

Scott Tolinski

A lot of interesting stuff. Cool. Well, that's all I got for you, folks. Hope you found this interesting. Leave comment below. Let me know if you wanna try it. Yada yada yada.

Scott Tolinski

Alright. On that note, we'll catch you in the next one. We dive into Wes or CJ's project.

Scott Tolinski

Peace.

Share