Use Script Kit to Automate Your Daily Workflows
with John Lindquist
Script Kit is an open source tool to optimize developer workflows. Creator John Lindquist will teach us how we can use it to boost our efficiency.
Resources & Links
Captions provided by White Coat Captioning (https://whitecoatcaptioning.com/). Communication Access Realtime Translation (CART) is provided in order to facilitate communication accessibility and may not be a totally verbatim record of the proceedings.
JASON: Hello, everyone, and welcome to another episode of Learn with Jason! Today on the show we've got John Lindquist back. How you doing, John?
JOHN: I'm doing great, Jason. Thanks for asking.
JASON: I'm happy to have you back on the show. I'm really excited because this is a show that's about a different thing that we talked about last time that's actually the same thing that we talked about last time. But before we talk about that, let's talk a little bit about you. So, for folks who aren't familiar with your work, you want to give us bit of a background?
JOHN: Sure. I spent decades consulting, doing development work. I was like project lead on HBO.com for a while. Anyway, that's a long, long time ago. Founded Egghead.io with Joel Hooks. And that's been the past decade. And for the past couple years, been working on Script Kit. It's been back when we originally, it was you and I showing it on stream a year and a half ago? Something like that?
JASON: Yeah, yeah.
JOHN: Yeah, it was a CLI tool. Then I was isolated in my room for a year and a half. And now it's this full-fledged, you know --
JOHN: You know?
JASON: I feel like we all responded to the stress of just... all of it. Differently. Right? And my -- my stress response is always to just like stay occupied with work because I'm like, what else am I gonna do? Sit and panic? And it sounds like you have a similar stress response.
JOHN: Yeah. I was a workaholic before and I just doubled it, yeah.
JASON: Oof, yeah.
JOHN: So, here we are.
JASON: So, the last time that we tried this, it was still experimental, right? You were writing this stuff, writing Node scripts to control a computer. I thought it was a fun idea. When I say "Control a computer" not in the traditional sense of we write Node or build web servers or processing. You were actually modifying web servers on the screen and modifying Mac. That's a fun thing to do. At the time I don't think it was called Script Kit. I think it was just a thing you were playing with. So, how has it evolved?
JOHN: It started as I called it Simple Scripts for a while. Then I started to think, like, what is this that I'm build something
JOHN: Well, it's a kit for scripts. And people ask me, what's the tagline for a script kit? Well, it's a kit for scripts, but script kit --
JASON: Script Kit, or kit for scripts --
JOHN: Exactly. That's pretty much, nail on the head name. So, once I got that, it evolved from like the original idea is that Bash is not very fun to write scripts in. And a lot of people struggle with the configuration, with variables, with like anything in setting up a Bash script. And for me, it's how can I take that experience of I want to write a script for something, a build script, a deploy script, a script to control Windows, a script to control home automation. Like they all -- we can do all those things. How can I remove all the friction around that?
JOHN: And make it a wonderful developer experience. Because I'm extremely passionate about all those -- all that tooling and everything around it. So, just heads down finding -- because I write a lot of scripts.
JOHN: And one of the goals of Script Kit is I have an idea for an automation. I -- in the past, I had all these hurdles in the way where I wouldn't do it. Now I have a few minutes, I'm just gonna do it.
JASON: Right. I mean, that's actually -- this was -- you bring up a really good point, which is that I think a lot of times what we have when we start is an idea. And that idea is something that we get really excited about. We're like, oh, I could build this and that would allow me to do X, Y, and Z. And then when we start actually digging into that idea, we find the hurdles. It's like, ah, well, that would mean I would have to figure out how to dig into the internals of this thing or work around the limitations of that thing. And we hit this critical mass of hurdles where we go, that idea is not worth it. And I think one of the things that's been really hard for me, at least, in my job now, I just don't have a lot of free time. I don't have the ability to do the plumbing work, right? So, if I have an idea, if there's not a clear path, like I can use this tool to accomplish this goal, I'm almost always not gonna be able to take that thing on because I don't have time to build the plumbing stuff. So, what I like about this is, you know, I have written Bash scripts. If you look at my dot files, you can see, I've got a few in there that I use to automate different parts of my workflow, mostly around like Git and stuff like that. But I don't write very many of them because they're challenging. It's not a language that's particularly -- I don't consider it to be particularly human-readable. It's very like, there's some magic and some stuff you got know. Where did these arguments come from? Oh, they're just there. You have to know to reference them. There's a lot of complexity in Bash scripts that I think just makes them not approachable. And every Bash script I've ever written contains at least 50% copy-pasted code because they didn't understand how it worked or why.
JOHN: To that point, actually, the -- the lightbulb moment for a lot of people is when I explained it how Netlify gives you this experience of here is a function -- here is a folder that says "Functions." Drop a bunch of files in there and then they'll all run on the server. The -- and that comes with a ton of benefits. And one of them is you can copy and paste the code from one function from someone's example, demo repo, whatever, into yours and just deploy it and it's good. How can I take that experience and bring it to the desktop? Where Script Kit treats a folder that has a folder called scripts in it. And treats it as scripts you can run, you can copy and paste it, tweak it how you want. Because you're never gonna find the perfect script for the thing that you want to do.
JOHN: Maybe the script is re-sizing something to 50 pixels. I needed it at 49. Like how do I tweak that?
JOHN: So, or how do I combine a couple script ideas? Like developers, it's all about copy from that, copy from that, mesh it together. And hopefully it works. And that's that huge goal of scripting things and the developer experiences. How can I make it like Netlify's functions folder? Let's do a scripts folder? Everything in there is a script.
JASON: Yeah. You bring up some of these small hurdles. If you want to write on your machine using Node, you can do that right now, you can create myScript.js and you can write Node. But there's a few things you have to know, how to set the environment variable to use Node instead of Bash. You've got to figure out how to set the file as executable in your file system. There's all these little things that need to -- that need to happen. But are all things you can learn. And they're fine. Like, you know, we're developers. We can learn how stuff works. But when you're trying to do something quickly, you don't want to have to learn all the lower layers of why a thing works. I have an idea. I want to be able to grab a random picture to drop into any markdown that I'm writing with one command. And I don't want to have to go learn how to, you know, configure files locally or all these other things. I really just want to, go to Unsplash, write the API, spit that out on to the screen. That's all I want. And what I'm excited with the little bit from what I have seen back when we did the original episode and I got a little sneak peek yesterday when we made sure that it runs on my machine. And what I like about what I'm seeing is you've basically taken that and, you know, like I had questions about what if we did this? What if we did this? And you're like, oh, that's too fast because it's just a little helper function. Instead of here is how you go get the device and this other thing. Each of those little things is like it's just one more tiny stumbling block that prevents me from doing work that I care about.
JOHN: Yep. And that's -- to that point as well, Script Kit, if you take a clean brand new machine and how can I go from there to working on my projects? Like the big idea of Script Kit is it can run all those scripts. You don't -- like Script Kit handles Node, handles installing npm packages. It handles all the things ancillary to doing work and getting things done. If you can imagine someone set up a Dev someone, install Script Kit and then Script Kit can launch your web Dev project. It can deploy your stuff, check in repos, do all this and you would never have to run -- never have to open the terminal to run those commands or configure environment variables or do all those things.
JASON: And so, that -- you never have to open your terminal. That sounds like something different than maybe what we were talking about originally. So, how do you -- like what is Script Kit? It's an app?
JOHN: Script Kit right now is an app around an SDK.
JOHN: So, the SDK is a Node package which provides helpers which launch little UIs. Any time you want to get input from the user, you can launch a UI and then that can pass it along to, you know, exec whatever you want or npm packages or any -- anything else. If you think of what a script is, versus like a web project, a script is a step-by-step, one at a time, line-by-line thing. So, it's like at this point, prompt the user for which directory they want to pick. Then copy all these files. Then prompt them for what they want to name something. Then rename the files. Like there is human-computer, human-computer, human-computer. And typically you would write CLIs, you would do like install tools or set up your own tools for this. Script Kit is meant to handle all that have in a shareable, copy-pastable way.
JASON: But functionally, the experience is kind of the same. I'm gonna hit a hot key to open up Script Kit and type the thing I want too and it goes and does that?
JOHN: Essentially. If you've done the -- is it 300x50? Have you done that course?
JASON: Yeah. I think that's a -- the idea of it being sort of an inversion, I think, is interesting. Because it's -- it's a different tool for different sets of needs. And like Joel in the chat is saying right now, that like Joel still uses Alfred to launch apps. And is using Script Kit to do work. Which are, you know, so they can be complementary tools.
JOHN: Right. And that's the challenge of explaining Script Kit is that it encompasses so much.
JASON: What can you write with code?
JOHN: Right. It's familiar. Because people have used -- what are the drop down menus called? People have given them a specific name. Command palettes.
JASON: Right, right.
JOHN: People have used command palettes. So, it's familiar in that sense. But the idea that at any time I can add a command to my command palette just with a few key strokes. That's totally unfamiliar to people. Because it's usually, clone this repo, set up this bundle, compile and ship it to someone else. Whatever. This is, type a few characters and you're writing your own command.
JASON: Yeah. That's a good -- and for anybody who is not familiar with what a command palette is, you've probably used one. But we did an episode with CommandBar which is one option for building one of those for your site. You can also on the Learn with Jason site, if you hit command K, it will open up a command palette that's powered by Algolia that Sarah Dayan built that's awesome. So, very familiar in terms of we've all probably one of these at one point or another. And what I find really fascinating about this is that it's sort of like there are web-ish things that you can do with it. Like I was talking earlier about, hey, I need to go get a random image. I'm going to use the fetch API, make the call, get the response, do something with it. But then we can do these really other interesting automations where we're dumping the windows on the screen, we're touching the configuration of the computer. All this really fascinating stuff that gives a lot of extended power.
JASON: And so, CJ in the chat says it sounds like Script Kit really shines with more complex tasks. Does that feel -- I don't know, does that feel accurate?
JOHN: I wouldn't describe it that way. I mean, what makes a task complex? So --
JASON: So, maybe a reframing of that is Script Kit really shines when the thing you're doing is custom. Like Alfred is gonna give you built-for-you, one size fits all solutions. Script Kit is where you would go if you want to make it yours.
JOHN: Yeah. I like that a bit better. Like there is a bit --
JASON: Still don't like it, though.
JOHN: Yeah, it's... [ Laughter ] It's -- like going back to that analogy of a Netlify functions folder. Does a serverless function shine better in complex scenarios?
JASON: That's it. That is a fair point. And I guess -- this is the major challenge of code in general is like how do you fit code into a box? Like what does -- what can Node.js do? And the answer is a lot. And it can be good for highly-complex and bespoke things. And also --
JOHN: The deep end...
JOHN: You got to sing the tildes. [ Laughter ]
JASON: New rule, you heard it here first. But yeah. So, I think that's definitely -- that's fair. So, yes. It heavily depends, and I guess would come down to how do you want to solve your problems? Like can you find something in Alfred that's solving your problem exactly? Or do you want to be able to just open up a little thing and say, all right, Node, I know how to use you. We're gonna build this. Maybe it's a one-liner. Maybe it's something super-complex.
JOHN: Right. And we can even go over your snippet example. We can write a snippet that takes parameters. And we can compare. I'm happy to take that approach as well.
JASON: Okay. You know what? Why don't we take this as a good opportunity to switch over and start building some stuff. Give things a try. With that, I'm going to switch over to the pair programming view, oh, OBS is open on the wrong window. Pull it over here. So, now we're looking at... this. All right. So, we're gonna swing over to the home page of Learn with Jason where you can find the live captions that are being provided by Amanda today from White Coat Captioning. Thank you so much, Amanda. And that's made possible through the support of our sponsors, Netlify, Nx and Backlight all kicking in to make this show more accessible to more people. And we're talking today to -- that's the wrong window... let's get into this window. John Lindquist. Spelled it right on the first try. Look at me go. I'm going to drop a link there. And if you want to follow along with the captions, you can always find those on the home page of the site, learnwithjason.dev. We're talking about Script Kit. I went ahead and installed this ahead of time. Anyone who has been watching this shows knows that I do all sorts of chaotic thing on my machine. I get unexpected behavior that's wild sometimes. If I'm installing an app, I want it to work. We did an install session yesterday to make sure it works.
JOHN: Little install session.
JASON: Yeah. If I open up Kit. And I hit... let's see here. What is it? Command semicolon?
JOHN: Yeah. So, the icon's in the menu bar. It's like one of those hidden apps. That only shows up when you hit the shortcut.
JASON: And so, now I have Script Kit. And I can --
JOHN: Yes, sir.
JASON: Drop this browser down so we can actually see what's going on. So, this is Script Kit.
JOHN: So, when you --
JASON: Command semicolon to pop it open.
JOHN: And the major point, like the inversion you see right away is that it's showing you code. It's right in your face. You're about to run code. So, for any of these, it's just right there. And on any of the scripts, you can hit command O and it will open it. And you can start Editing. Like it's just... it's just right there.
JASON: Here it is. So, I can mess with this and say like...
JASON: Okay. Save it. And now it's right there. Right up at the top where I made my change.
JOHN: And that script is uninteresting. It opens an editor with that content. That's a cheat sheet. Script Kit ships with things like an app launcher and a file browser. Some things you're familiar with from other tools.
JASON: And to be clear, all I did to install this is I -- I'm on an M1. So, I downloaded the silicon build. And then I dragged that into my applications folder. So, that was the whole install setup for anybody who is following along at home. And with that, we can start -- let's start messing with some stuff. What's a good first thing to do. We edited the cheat sheet command. Looks like we've got a couple options here of things that are being...
JOHN: Yeah, actually let's just tackle the snippet expander.
JASON: Okay. Let's do it.
JOHN: Do you have the -- so --
JASON: I do have the snippet, yeah.
JOHN: Okay. If you look at -- there should be a -- if you type "Snippet" in there. So, if you look at the code in there, just like copy and -- or you can duplicate that one, actually. So, command D. Or yeah. Or the command --
JASON: I just hit the right arrow. Which gave me a whole bunch of options. So, I'm gonna hit duplicate or command D. I have a new one.
JOHN: Yeah, name it Jason-snippet or something.
JASON: Yeah. Call it blog image. That's really what I --
JOHN: So, these things can be run from the terminal. So, you can run it in the app or the terminal. So, yeah. Perfect.
JASON: Blog image. All right. So, now I've got a blog image.
JOHN: Yep. When you duplicate it, it strips out the name and the snippet and edit it.
JASON: Gotcha, gotcha. What I want is -- we'll call this a blog image. The snippet, is that what the expander is?
JOHN: Yeah. So, you can type any text and it will watch for you to enter. And just make it different than your other one so they don't run at the --
JASON: Yeah. I think what I have for this one is -- yeah. So, this is my... my Alfred workflow which apparently I didn't break.
JASON: And caption, we've got alt text. And so, then I get this --
JASON: This is my figure, right?
JASON: This is how I put an image in my blog.
JOHN: So, surround that in a string template. And let's grab out the variables.
JASON: So, we would need -- should I just set them up as like caption?
JOHN: Perfect, perfect, you got the idea. And say await arg for -- to prompt the user to enter an argument as await arg.
JOHN: Yeah. You can pass in a string as a place holder to say, enter a caption. Sure.
JASON: Okay. Something like that. And then we've got a credit. So, we can do the same thing. We'll have a credit link. We will have the alt.
JOHN: You're cruising, look at you.
JASON: And then we'll have the source. And that's our whole thing. So, we can take these. And let's... let's do credit. Who owns this image? And then we'll do another one for the link. Link to... whatever. Do another one down here for the alt. Describe the image. And finally, we have the source. All right. So, that should get each of our pieces.
JASON: And then we have our template. And then I would just --
JOHN: So, instead of keyboard type, you'll want to say, set selected text. Because you don't want it to type out that whole thing. Set selected text does a -- a copy and paste sort of action. Not -- sorry, not question board sets, sets --
JASON: Oh, here we go.
JOHN: Yeah. And then pass in the template. Then get rid of that one. And there you go.
JASON: That's the whole thing? Okay. Let's try it. So, now I'm gonna go into let's open up code. And I'll create a new window. Make this -- get the sizing right here. There we go. And then I'm going to set this as markdown. Or it's not markdown, is it? It's something else. That's okay. So, I'm going to write image. Okay. Your caption is not your alt text. A sample image. These... and then we can do like -- we can assume we have one.
JOHN: There you go.
JASON: Look at that, y'all. We -- and this is the sort of thing that it took me a long time to get this running in Alfred. Not because Alfred is bad. But if we look at Alfred -- how do I --
JOHN: Yeah and I -- like I really, really hesitate to critique a tool that I've loved and used. I love Alfred. Absolutely adore it.
JOHN: Let's play with that one a bit more just to show some fun stuff.
JASON: Okay. Got my image, right?
JOHN: Yeah, just search for command -- you can remove the comments. They're just about the security and privacy and accessibility stuff.
JOHN: So, say, for example, on your caption, or on your credit, you have a few people you typically want to credit like a common list of people. So, the next argument in arg would be an array of strings. And that will pop down that search list.
JOHN: Yeah. So, now you've changed the script. And when that pops up, that will give you a list of users to pick from.
JASON: Nice. Okay. Let's go into code again. And do another one. Nice. And if I want to put in a custom one, oh, I can't.
JOHN: You can. I can show you how if you want.
JASON: Let's do it.
JOHN: So in, in that first argument, we're gonna change that from a string to like a config. Pass in an object. Place holder was that previous string. And put strict to false. That's the one that limits the user to picking from a list.
JASON: Nice. So, yeah, that's pretty. And all feels pretty much approachable here. Where we've got, you know, I know what an arg is. And this is -- so, this is kind of interesting. Are you wrapping these with something? Because this is, you know, top-level await. Is that -- what's going on here?
JOHN: Yep, top level await is just available. The Script Kit directory where these scripts are stored, if you look at -- if you go to the menu, the menu bar. And go to the reveal kenv finder. So, your scripts are stored in here in that scripts directory.
JOHN: And all the set up around it is like all the Node modules and all that stuff is in there.
JASON: Got it.
JOHN: So, that's a kenv is like a portable kit environment. Kind of like Ruby environments and Python environments and whatever.
JASON: So, I could if I wanted to put this into like my dot files and make this portable between machines or something like that.
JOHN: Yep. You can version this. You can share environments.
JASON: How does it work -- I see Node modules here, I probably don't want to commit to GitHub. Does it have a ignore in it?
JOHN: I think so.
JASON: If I save this in my .env, open up on another machine, it knows to install all of that.
JOHN: Yes. So, yeah. We can get into some of the npm stuff too. Yeah. Anyway, I was going to say a kit environment is essentially a directory with a scripts folder in it. And as you add more scripts, other folders and things will be created on demand. A lot of Script Kit is just in time sort of actions.
JASON: Gotcha. A feature request from David in the chat which is actually a great idea. If you made that into a promise.all, then you could open these up as a form.
JOHN: Yeah. You could definitely have -- so, there is a -- an await form that you can use. But it's one of those things that requires writing all the HTML for it.
JASON: Okay. So, like if we -- a potential feature request for someone else who wanted that would be able to kind of extend the kit to have form?
JOHN: So, here's the thing about forms is that if you look at how easy it was to add a list of users to pick from, and to restrict it, or to restrict it to that list, that was very -- that was trivial here. In a form, writing that in HTML like turns into a chore.
JASON: It's a lot, yeah.
JOHN: So, while I agree with forms -- forms are wonderful. This gives you so much more flexibility. Say, for example, you wanted to pull Jason, John, and Marissa from an API, that instead can be an array an async function that returns an array.
JOHN: These give you the full power of customization -- what's that word? Procedural enhancement? No.
JASON: Progressive enhancement?
JOHN: Progressive enhancement, thank you. I start with arg. You don't even have to pass in a place holder. And than as I want to add more and more to it, I want to add previews to when I highlight a individual person, I want to show their individual image. Or I want to add descriptions to each of them. Like you can keep on adding more and more to it. The developer experience with forms no one has figured out.
JASON: Fair, fair.
JOHN: I'm just gonna say it that way.
JASON: Fair. Yeah. But I do think this, you know, this -- this is a -- it is a problem that you could solve in userland, right? It's the sort of thing that you can go and build out because if I remember correctly, I can also just like put anything I want in into a Script Kit.
JOHN: At the end of the day, this is -- it provides these global helper functions. But you can do whatever you want. I'm not gonna stop you from writing your own code.
JASON: Okay and so, there are a few things in the cheat sheet here that are kind of interesting. I've got just a bunch of keys here. So, if I hit semicolon, now I'm in a --
JOHN: You're in traditional app launcher land.
JASON: Yeah, yeah.
JOHN: It's kind of like the hello, world, of command palettes.
JASON: I can go into any file browser and go to my downloads or whatever. And what else do I have?
JOHN: If you hit command zero from the main menu. You moved around the initial ones. You see it like herky-jerky. It changes positions of windows.
JASON: I moved a bunch of stuff.
JOHN: If you move it again, it won't go from main window. Sorry, that was bugging me.
JASON: Go in here, and like ls, right? Lots of options. Clipboard history, boy am I glad I didn't have something in here they shouldn't have. I just realized as I pushed that button.
JOHN: Yeah, that's a dangerous one to do live. Now, it does its best to ignore while 1Password or security apps are open, it ignores security stuff going on there.
JASON: Now, with a scratch pad like this, does this -- this is basically a file that I can edit --
JASON: And I've found this with the comma here in Scratch Pad. I'm just kind of going down this list. And that I just push comma and it opens this up and I can say whatever I want. Right?
JASON: Don't forget, right?
JOHN: And you can look at the bottom. It's updating the file, users blitz.sticky.
JASON: There it is. I hit escape, save. Go back out here. Let's see what else I got. File search.
JOHN: Is that a dangerous one for you?
JASON: Should be okay. These are some images I share for like speaker shots or whatever. Come back out here. We've got --
JOHN: And you can like from that you can drag and drop out and you can take action and show in the finder and all those sorts of things. Like that's what -- in general, like the challenge I gave myself and the challenge others gave me is that Script Kit has to be able to emulate the features that other apps have in a scriptable way. Like all of those are scripts. And you can look at the source of all of those. So, anything you see happening here searching for files and everything, those are all things that you could do in your own scripts. Right? This isn't some custom hidden away thing. So, any of those can give you ideas for potential things that you could hook together as little components and everything.
JASON: Nice. Okay. So, if I hit the apostrophe, I get a list of my snippets. Come back out, I could hit this square bracket and there's a template. What's the difference between a snippet and template?
JOHN: The snippets use the snippet metadata that you saw and they are grouped together there.
JASON: Okay. Did I use this wrong? This should have been a template then?
JOHN: No. That's still a snippet. Because it uses the snippet metadata at the top.
JASON: Okay. I think I am confusing myself, then. So, template.
JOHN: It's a way of categorizing a script. A snippet is when you type text into the keyboard, it will trigger the script. So, when you typed semicolon image, I can't remember what the snippet was.
JASON: Oh, oh, okay. I understand. So, if I go in here and I run this, it's going -- like I'm triggering that directly. I'm not entering like a thing that will be auto-expanded when I type it.
JASON: Got it.
JOHN: Snippet are like text expander things.
JASON: Gotcha, I gotcha. Okay. What else we got in here?
JOHN: Word API is fun.
JASON: Word API.
JOHN: Just type "Boop," I don't know.
JOHN: Boopsie doodle!
JASON: Boop this is fun. It's got to rhyme?
JOHN: The data mesh API is what this is looking into. The data me is an Open API for doing word stuff. And you can --
JASON: Cool. Got my system commands in here. DevTools...
JOHN: If you've ever just wanted --
JASON: Now, is this the DevTools for Script Kit?
JOHN: It's a spawned window of just DevTools. Chrome does like a global DevTools. Anyway.
JASON: Gotcha. So, I can just use that to sort of run a console real quick.
JASON: And so, running this is... oh, nice. Rapid emoji picture. That's good.
JOHN: Because the OS -- because Max 1 is so reliable.
JASON: Yeah, that one is hard for me to use for sure. Google suggest. So, if I go in here and just type one of these, I and just type whatever. And it pulls up some options. So, let's click... those -- oh, this is tool too. Check this out. So, I've got all these options. And then if I come over here... so, it's so handy. Like unbelievably handy.
JOHN: That's nice.
JASON: All right. What else should we be looking at? Did I miss anything else?
JOHN: You can run -- corgi is a fun one. I don't know how many time -- 45 minutes.
JASON: We have 45 minutes.
JOHN: We can talk about widgets where it's a whole other concept -- it's a silly way of saying this, but a UI-backed script. So, it's a script with a UI that you can send data to and it will send events back. You may think that's what apps are. And I would agree with you. But essentially, Script Kit, you can like build these little apps that are little standalone things.
JASON: Okay. So, let's look at how that works. So, we've got a -- a widget.
JASON: And that's an image.
JOHN: So, yeah, the widgets use the Vue -- there's a vue-tiny or something version of Vue.
JOHN: Because of the syntax. It needs to be a templates syntax framework so you can send objects and it will update the template. It would have been very strange to do in React with set state and hooks and everything.
JASON: Yeah. So, we've got our update image is an async function that hits the dog API. And then we just get to update that URL with whatever we get back from the API. And then we actually call the function.
JASON: and when you click... it updates the image. That's fun.
JOHN: And that's like an -- you could call that an app. I don't know if I would sell that in the App Store.
JASON: Yeah. But you can also see how quickly this becomes like really beneficial. Because, you know, I'm thinking about, I don't know. We could do a lot of things with this. We could show the next episode of Learn with Jason using my API. Or we could get the current time in whatever place and just have a little widget on the desktop at all times that shows what time it is in London. Which would be useful for me because I have people on my team in London.
JOHN: Sure, let's do that. Yeah, the thing with Script Kit, let's stop talking and let's start doing. [ Laughter ]
JASON: I love it. Okay.
JOHN: Just start typing "Time in London."
JASON: Wow. Okay.
JOHN: Hit enter. Say "Await widget." Pass in some HTML.
JASON: Let's see... how do we want that to work? It's gonna be a --
JOHN: Usually want to do back ticks. Because they're gonna be multi-line almost every time.
JASON: Let's go with the -- we'll just set up a div. And inside this, I'm gonna have a -- the current time in London is... and then we'll put in another one that has -- oh, how does this work in Vue? Is it --
JOHN: Just do the curly braces. Double curly braces inside the -- yep. Perfect.
JASON: Okay. And then down here I need a async function load time. And that's gonna be a -- let's see. Can I do this from memory? New date. And then I want... oh, gonna do it. Local -- it's gonna be time.set time zone?
JOHN: I've done this. So, good luck.
JASON: Let's go. We can do it, we can do it, we can do it. Time zone UTC... offset? No. Crap. Okay. Time zone. Time zone offset. To locale time string, to time string, we've got the locales in gb, oh, boy. Can I set the time zone? TimeZoneName -- I have to look that up. I don't remember what the London timezone name is. So, London timezone name. For date. Timezone... timezone offset. That's not what I want. I want locale. Time string. And we get... as we get our date and I want the options to be... that stuff is all fine. But I really want to see setting the timezone. Using locales, I get that part. Using options, show me timezone, UTC. Okay. We can just set timezone to UTC.
JOHN: With Script Kit, you can copy and paste that stuff.
JASON: Yeah. Easypeasy. Let's just grab this bit.
JOHN: I like to encourage copy and pasting.
JASON: The time and here. Right? And then that should give us our time. And so, what we are after, then, is we want to do widget.setState.
JOHN: Not widget set State. Await widget above returns the widget. So, it's called clock or whatever.
JASON: Okay. So, clock. And then we'll do clock.setState. And inside this, we want content to be equal to local.
JASON: So, then I want to run loadTime. And then it was clock update? What was it?
JOHN: So, are you gonna do a timer? Or are you gonna do a set interval?
JASON: I probably do need to set the interval. And then update it. So, okay.
JOHN: Yeah, I was thinking you just do it.
JASON: Set interval. And every what? 1 second we'll update it.
JASON: Okay. So, that sets it. And then to display it... I need to...
JOHN: Yeah. It looks good. You're doing clock set state every second in the function.
JASON: That will update it? I don't need to do anything else?
JASON: Okay. Let's try it. Neat! Look at it go, y'all! That is -- that is super-fun. And very cool. Also, I see that Cassidy absolutely solved my timezone problems far before I did and I didn't read the chat. Thank you, Cassidy.
JOHN: So, a couple things you can do here. If you go to -- if you open the script again. The second argument of the widget function is a config. So, if you pass in an object here, you can do like always on top. You can set that to true. You could do transparent. As true. And when you do transparent as true, you almost always want to do hasShadow as false. Otherwise it gives it a weird drop shadow action. And the widget also ships with tail wind classes if you want to make it look bigger or anything. If you want to do class text for Excel or something.
JASON: Like this? oh, in the HTML.
JOHN: In the HTML.
JASON: For xl?
JOHN: I think it's text-4xl. Now try running it again.
JASON: Okay I have to do that. Close that -- I'm just hitting escape to close these for everybody. Time in London. Current time in London. Great. It's doing something interesting where it's kind of like...
JASON: It's selectable. But it also like pops up to the pop.
JOHN: Yeah. So, it tries to re-size and get out of the way. Otherwise it will cover up too much. You can always drag it around, re-size it. And then command L on a widget will lock it so that you can click through it. If you think of like a Switch pop-up or something. Now you can keep on working and you should be able to select stuff underneath it.
JASON: Let's see... yep!
JOHN: So, you have to -- to get rid of this now, you either have to go to -- what's the three finger swipe up called? Mission control? Click on it. And command L again to unlock it. And now you can resize it and stuff.
JASON: Got it.
JOHN: And any of the -- so, if you have a long-running script like that, so, yeah, just leave that there. You can do a bunch of them and cover your screen in London time. In the menu bar, because this is like a -- you could consider it like a process orchestrater. If you think of Script Kit as something that's launching processes based on what the user enters. You can see a running process list. And any of those you can go down and terminate or open logs and that sort of stuff.
JASON: Got it. So, I can go here and terminate and there it goes. And so, then in here... this is -- this is great. How -- if I want to add padding, is it like P --
JOHN: P-4 or --
JASON: Okay. Let's try that.
JOHN: I don't know how visible that would be since the window is transparent.
JASON: What I was wondering, it feels like right now it's kind of like smashing up against the top. So, I was thinking about --
JOHN: Oh, I see it.
JASON: I was thinking that might give it a little less smashy. It did not. But mostly that's because I don't know Tailwind.
JOHN: Well, it smashes up against the top. It does a browser window measurement thing. So --
JOHN: It should respect the padding.
JASON: Got it. Okay. What I'm not gonna do, chat, is get stuck in the CSS.
JASON: So, that's pretty good. This other one is less good. But it's okay. Okay. We'll leave that on. That's gonna be great. So, then we have -- what else can we do? I feel like you had other ideas here?
JOHN: Yeah. So, if we want to do something really fun, let's scrape a website.
JASON: Yeah, let's do it.
JOHN: So, create a new script, call it scrape and resize.
JOHN: So, when you're naming things from here, they don't have to have dashes because it will automatically convert it. When you're duplicating, make sure there's no name -- anyway. So, if you await scrapeSelector. And pass in learnwithjason.dev. May have heard of it, really great website. Really handsome people. And the next argument is the element you want to scrape. So, what we're gonna scrape is the image as in image. Because we're getting the -- you used SVG images.
JOHN: So, we're scraping those. And then the next argument is we're gonna yank off the -- this is gonna be a function. Say like E, then a fat arrow. And return the el.href.baseVal because this is a SVG animated. This is just because if you look at the source of the site, you'll see SVGs surrounding those image tags. This is -- if you look at the source of Learn with Jason. We're essentially setting up a selector to grab images of people.
JASON: Yes. And we're looking at these images here. Which are set up as -- because I'm doing some --
JOHN: Click path stuff.
JASON: Yeah, click path stuff. And also so I can do these animated transitions, right? I couldn't figure out how to do that any other way. And both Cassie and Sarah have taught me how to do a lot of SVG animation. So, that was a thing to do that I probably couldn't do again today.
JOHN: All right. So, what we're gonna do here is this is going to return an array of all of those images. So, let's just do a Dev -- just to kind of inspect the result. Put Dev and then pass the response. You can call it image URLs or whatever response is fine. All right. Now if you run this, something interesting is gonna happen. It's gonna prompt you to install Playwrite. Now, this is one of the only tools in the Script Kit SDK that will prompt you to install an npm package. But whenever an npm package is requested to install like this, it will make sure like, you know, it's been downloaded this many times, this is the name of it. You can click on the link to get more info. Like I don't want people like you don't want to install something that has one download unless you know what it is. So, this is the number one reason I added the terminal view is because npm's output is all over the place as far as showing progress. Playwrite is a rather large package. It may take 30 or 40 seconds. I essentially tried really hard to hook into the stream of npm outputting text and showing progress bars and that sort of stuff. And I'm like, you know what? It would be easier to build a terminal from scratch in the app than to handle a stream of text and show the progress bar. Like this is familiar, right?
JOHN: And so, once this is done, again, for me it took -- I have a super-fast machine. Or the Internet connection. Mine took 40 seconds. 50 seconds is normal for Playwrite. Others will take --
JASON: Weird flex, but okay. 40 seconds. Yeah, well, mine took 52 and I'm streaming.
JOHN: Yeah, that's a good point, that's a good point. I yield. You win.
JASON: Okay. But so now we should be set, right? So, if I command enter to continue script. So, I'm gonna do that. Oh, wait, select the window first.
JOHN: Make sure it's focused. So, it's scraping and if you look in the console, you'll see we grabbed all of the images.
JOHN: All right pop so, the neat thing about the way it installs npm packages is it will never prompt you familiar again. It's installed and now it will just grab Playwrite whenever you request it.
JASON: Yep. And there it goes. And it's taking a little while because we have to load it and then get all that stuff and then return. So, there's like the latency.
JOHN: The Playwrite -- the scraper launches headless Chrome window which launches the site. That's gonna take a couple seconds regardless.
JASON: Yeah, Playwrite is definitely -- it's so powerful. But it's a hefty boy.
JOHN: It generates open graph images and all is that stuff. Anyway. So, let's open back up. We saw -- open the script back up.
JOHN: And now instead of Dev, let's just map those into a -- an HTML page.
JASON: Okay. So, we will imageUrls.map.
JOHN: And the URL, and map them to image with source. Yeah, just strings. You can see where I'm going. Yep.
JASON: And then for this. I don't know how to do that. So, we'll just -- in a production script, I would do something like figure out what the alt of these images is as well and pull that in. But for the purposes of this demo, I'm not gonna take the time to figure out how the HTML structure works. And --
JOHN: And go ahead and join those.
JASON: Okay. .join. And are we doing like the standard MP?
JOHN: Yeah, standard MP. And then so, that's -- now we could do await div. And pass in page. Actually, let's wrap that with like a flex wrap or something. So, pass in a string. Do like a div with a class of flex.
JASON: Is this -- you're gonna have to walk me through how Tailwind does this.
JOHN: Yep, spacebar flex -- and done. And drop the page.
JASON: Those. And that's the whole thing?
JOHN: All right.
JOHN: So, now we have --
JASON: Oh, but we squished -- that's because we have different sizes. So, we've got our top line here of like featured episodes and then we've got the smaller ones of recent episodes in different categories. And that's why this got wonky. Is that --
JOHN: I see a question, can you remove npm packages? Yes, you can. So, if you can open Script Kit again. Go over to the kit tab. Just tab, tab. And type npm. Hit enter. Stay uninstall package. And you can uninstall Playwrite. There it is. All right. So, open your script again. Let's keep going.
JASON: Scrape. Open.
JOHN: And now let's -- so, wrap those images with an a tag.
JASON: Okay. I'm gonna do a little bit of cleaning up here. So, we want a tag.
JOHN: And the href of this a tag is going to be submit: And then the image. Or the dollar sign, yeah, interpolated. Perfect. Now in any div that you use, this kind of goes along the line of like creating pages and selecting things on a visual page. You can use A tags and the submit portion of the URL means that when you click on that, submit that as the result of the div. So --
JASON: Okay. So, I'm gonna just for the sake of making this easier, let's do a -- we'll just grab the first nine. And that they we don't have to deal with the fact that those smaller ones are getting wonky. So, save that.
JOHN: Go back to div, though. Sorry. Go back. And so, from the div, you'll return a selected image.
JASON: Selected image?
JOHN: Before await div.
JASON: Before await div.
JOHN: Yeah, say const selected, or whatever. Equals await div.
JASON: Oh, I got it.
JOHN: Because we're submitting the image. And you can go ahead and let's download this. Okay?
JOHN: So, await download. And just pass in selected. Now let's create a place to download it to. So, if you -- yeah, you can either do it this way. We're gonna do it a little differently. Just say, like, const filePath. And use home as a function. And then you can just do like home and pass in downloads. And then comma. And then a string. We'll name the file -- let's grab the file name from selected. Are you familiar with using path and base name?
JASON: Yeah. So, we -- is it just here? Like this is the whole thing? Or do I need to run like path on it?
JOHN: Yeah, just say path.basename and then path is selected. And that will grab the file name off of --
JASON: Okay. And then I'm gonna pass in the filePath. If I can spell it. And that should do it.
JOHN: That should do it. Yeah.
JOHN: So, this should...
JASON: It shows me a list. Here's my list.
JOHN: Click on David -- David was watching.
JASON: Yes. Click on Cassidy's face.
JOHN: Cassidy's watching too. And now in your downloads folder. I don't know if you want to take your downloads folder off screen either.
JASON: This is the downloads folder. So, did it do? Oh, we gave it a folder name, not a file name.
JOHN: Yeah, that's what the download utility takes. A folder.
JASON: Yeah. So, here -- so, we don't actually need this part, right? Because it will set the name?
JOHN: So, keep it for now.
JOHN: So, the way I would -- we're gonna do this now, is if you remove the filePath from download, this returns a buffer. And with a buffer, we're gonna do -- we'll do await -- or sorry, const sharp equals await npm and then Sharp. We're gonna grab and install Sharp. We're gonna await Sharp -- yep. Await Sharp. Pass in the buffer. And dot resize. 2020, I don't know 40, 40.
JASON: Yeah, 20, 20 is not going to be visible.
JOHN: And then say toFile at the end of that.
JOHN: And by passing the filePath.
JOHN: You can go ahead and run this now.
JASON: All right. Now what we did last time is we ended up with a folder that is downloaded directly. So, let's click on David. And I'm gonna install Sharp. Oh, so that's how that works. When you that npm, it doesn't automatically do it. It's saying -- I get it.
JOHN: Did you do command enter?
JASON: I did do command enter. And now we can see David's face. And if I go do my downloads folder up here, that's the resized image, love it.
JOHN: Yeah. So, if you look at the script... the -- like the core value of Script Kit is you should be able to read a script and know what it's doing. So, hopefully like when you look at this and read through the steps of it and, okay, I'm scraping that page, creating that page. Submitting that. I'm downloading that file. I'm resizing it and I'm saving it. Like hopefully that comes across in the scripts you write and it's not some sort of hodgepodge Bash script that you copy and paste and you have no idea what it's doing. And if you were to summary this with somebody else that they could customize it however they want. They could pass in their own URL. They could pass in the filePath they want to save it to, the file name and the sizes. And at any point in any of these, if you wanted to change filePath to awaitPath like a path picker.
JASON: Oh, yeah.
JOHN: If you wanted to change the file size to await arg and give them file sizes to pick from. At any point, like in the template before, you can pull out little pieces and turn them into variables that could be user input rather than just an automatic thing.
JOHN: Yeah. It's -- you can use VIM.
JASON: Okay. So, how would one change their editor here?
JOHN: So, if you exit out of that, you can kill those processes. That's just the list of running processes.
JASON: Just get out of here. Get you out of here.
JASON: That was the opening. Okay. Here we go.
JOHN: So, if you go into the Kit tab. And go to type editor, I think, is it's somewhere in there. Change editor.
JASON: It's already just built in.
JOHN: Yeah. It should -- that should still work. It's not one of those they test. And it's -- built it a long time ago.
JASON: Okay. I just changed mine to code in hopes that when I go to -- let's go to scrape and I'm gonna hit open and -- bam!
JOHN: Wabam! Yeah!
JASON: This is great. It just -- it just works. And I love when things just work. So, let's change the editor. I'm gonna go back to Kit. Yeah. This is -- like this is just very slick. I like the way that this feels.
JOHN: So, like a challenge for you would be like with what we've learned in the past 20, 30 minutes, like scraping images and display it in the widget. And then when you click on the widget, it changes the user you selected. And like as a developer, with these tools in your hands, wait a second, I could do that.
JOHN: And wait a second, I don't need to set up anything. I don't need to configure anything. Let me just copy and paste these two things, mash them together. And we have a widget of people's faces I can click on.
JASON: Yeah. Yeah. I think that's great. Well, very cool. So, I -- let's see... we've got like 15 minutes left on the clock. Do we want to call this one -- I'm sorry, somebody is calling me over and over and over again. So, give me just one second in case something is wrong.
JOHN: Yeah, let me check the chat. Oh, I didn't have Twitch open for the chat. Yeah. Time to spend -- can you hear me right now? I don't know if I was muted. [The captioner doesn't know either...] Can anyone hear me? Are we back?
JASON: I'm back. I'm so sorry about that, everybody. That was an important call so I'm glad I took it. But yeah, everything is great.
JASON: My partner is at the doctor. That's why I had to take that call.
JASON: So, yeah. We're in good shape here. And I am super-pumped. I did turn your mic off.
JOHN: That's okay. Yeah, I was trying to say stuff.
JASON: How do I do this? Okay. So, my car warranty, Social Security benefits -- yeah. Good. Good, good, good.
JOHN: You can DM those to me. I'll take care of them.
JASON: All right, y'all. Okay. So, we got about 13 minutes here. Do we want to go for one last thing before we -- before we wrap?
JOHN: Sure. Why not? Let's hit that Learn with Jason API that you have.
JASON: Okay. Great. So, I have -- if we look at here we have the Learn with Jason.dev and API and hit the schedule.
JOHN: Let's switch over to the other view.
JASON: What view am I looking at? Let's go to this view. Here's how this works. We've got learnwithjason.dev/API/schedule. And this is an open thing there. And so, now we can hit an API. And this will give us back JSON. So, we can do whatever we want with this.
JOHN: Let's create a script. Show schedule. Whatever is -- however you want to name it.
JASON: Let's go with show-next-lwj-episode.
JASON: So, I'm going to get my response, which will be a await --
JOHN: Fetch and get, yeah.
JASON: Copy-paste this one in. This one in and then that --
JOHN: And then on the next line do response.data so you don't have to await the statement. Or destructure, however you want to do it.
JASON: All good, all good. So, then we've got our -- I guess we can call this the schedule.
JOHN: That's an array. Say await arg. Lists of episodes. Pass in the schedule.map.
JASON: Map. And in it we have episode. And we can dot ep dot --
JOHN: Let's do some objects here.
JASON: Oh, okay.
JOHN: So, yeah. Return -- return an object where the name is the title of the episode. So, ep dot --
JASON: Dot title?
JOHN: I can't -- is it dot title?
JASON: Which one of you is -- let's see... description? Title. Yeah, title.
JOHN: And description is ep.description.
JOHN: And do value is the ep. So, it will return -- that's what it will return when you hit submit. I think you have an extra param at the bottom. Yep.
JASON: I was short one. I had the arg.
JOHN: Got it.
JASON: The map and then my wrapper. Okay. Great. So, now that should give us back the episode.
JOHN: Yeah. And let's just run it and make sure it's working.
JASON: Okay. Wow!
JOHN: Now you can search all your episodes. It will search both the title and description.
JASON: And that's --
JOHN: It took 10 seconds, right?
JASON: Oh, it's got the fuzzy search! That's amazing.
JOHN: When say I have an idea for a script, stop talking, start writing, it's like...
JOHN: And I'm not -- again, not like to compare what that would require in other tools. But...
JOHN: So, let's do -- go back to the script, since we're short on time. Underneath the main line, do -- write a comment that says "Shortcut" at the top. Like the name comment. These are some of the metadata. Say shortcut, say command one, or cmd then space 1, something like that. I think the plus will work. I just do it without. Yeah, exactly.
JOHN: And let's do...
JASON: Oh, shut up. [ Laughter ] Okay. All right.
JOHN: And go back, and from await arg, do const ep equals wait arg. And now let's do set selected text so you can paste the markdown link with the title and the URL and stuff. Whatever format you want to share an episode with somebody.
JASON: Okay. So, this would be the title and then this would be the -- like HTTPS. Dev, and then it would be ep.slug.current I think is the format that --
JASON: Is that right? Ep.slug.doesn't. So, then we get one of those. And then that should be the whole thing. So, we'll save that. And then I'm gonna run command 1, magic, and then we'll get a link to this. And then I'm just gonna paste this directly into the chat. And oh, that didn't work. What went wrong?
JOHN: It tried to paste it where the cursor was.
JASON: It tried to paste it. I thought it was gonna do the command thing. Let's try that one more time. Command 1. Ah, that's cool. Okay. And I have a typo in my code. So, we want to close our markdown so that it's valid. And... do -- whoops. Do command 1. And away we go. Valid markdown in what? 3 minutes? 5 minutes? That's pretty excellent.
JOHN: So, yeah. Like it's a -- I don't know. I think -- I think developers should be able to write the tools that they need for themselves.
JASON: Yeah. I mean, and it really does feel that way, right? Like this is the sort of thing that we're seeing. And then I see Joel is saying you can just write copy as well.
JOHN: Yep. That will put it in the clipboard.
JASON: So, do one of these, do one of these. And then I can just paste it as many times as I want. Dang it, this feels like magic. Like this is -- like this is just extremely cool. And, you know, the fact that I was able to throw a shortcut in so fast that we can go in and tweak things the way that we want. And like it also looks like, you know, I can edit this because now it's not necessarily the next episode, it's like show upcoming.
JASON: Or, you know, get MD Linked title of -- something like that. You know? And I can out here, lwj and it describes what it's doing and this is just extremely cool stuff. Bam!
JASON: Really cool.
JOHN: That's my tagline for Script Kat: Bam!
JASON: I think that's about as far as we're gonna get today. I can see a lot of really, really cool opportunities here for what else this can do. And, you know, there's a bunch -- you wanted to show -- we mostly stayed in like my style of automation, which is Templates and grabbing things from APIs. But that's not all you can do, right? There's a lot more you can do. Where would somebody go if they want to just learn more? The Script Kit link again.
JOHN: Yeah, so, the community scripts are great for what people are actually building. The docs are relatively new because if you go over to -- like a lot of people don't know a whole bunch of the features that it can do. Like it can schedule scripts to run on cron jobs. It can watch files. And like when a file changes, it can run a script. Like there's basically whatever you want. The docs are still in progress. They're finally in a place where I start to get adding things easily.
JOHN: But if you look through there, they're progressing well. Discuss is a great way to -- to hit me up, post something on there. Ask me a question. I would be happy to help you write whatever script. And walk you through anything. If you DM me, I invite you to our Discord. We're just barely getting Discord set up to chat about that.
JASON: Nice. And this -- so, this is the number of downloads of Script Kit, right?
JASON: As everybody goes and installs this, you can see the number go up. Which is cool.
JOHN: It's a fun little pat on the back every time I see this.
JOHN: Thanks for having me.
JASON: Chat, stay tuned. We're going to find somebody to raid. We will see you all next time.
JOHN: Bye, bye, now!