<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Stefan Bohacek</title>
    <description>The latest articles on DEV Community by Stefan Bohacek (@stefan).</description>
    <link>https://dev.to/stefan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1328%2F98dd96e7-7a3b-465f-b137-f3ea0b1f3c71.jpg</url>
      <title>DEV Community: Stefan Bohacek</title>
      <link>https://dev.to/stefan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/stefan"/>
    <language>en</language>
    <item>
      <title>Making a trivia quiz chatbot on Mastodon</title>
      <dc:creator>Stefan Bohacek</dc:creator>
      <pubDate>Mon, 06 Mar 2023 13:36:45 +0000</pubDate>
      <link>https://dev.to/botwiki/making-a-trivia-quiz-chatbot-on-mastodon-17l0</link>
      <guid>https://dev.to/botwiki/making-a-trivia-quiz-chatbot-on-mastodon-17l0</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm15aqv1e6n8exokza1nc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm15aqv1e6n8exokza1nc.png" alt="A screenshot of the bot posting a country flag and me responding with the correct answer, followed by the bot acknowledging the answer and posting the leaderboard" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TLDR: &lt;a href="https://glitch.com/edit/#!/what-capital?path=bots%2Fwhat-capital.js" rel="noopener noreferrer"&gt;Here's the finished code&lt;/a&gt; | &lt;a href="https://stefanbohacek.com/contact/" rel="noopener noreferrer"&gt;Get in touch if you get stuck&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;I made the original &lt;a href="https://botwiki.org/bot/what_capital/" rel="noopener noreferrer"&gt;@what_capital&lt;/a&gt; bot, which lets you play a trivia game where you identify capitals based on a country's flag, about seven years ago, for a &lt;a href="https://stefanbohacek.com/blog/how-to-make-a-twitter-bot-with-node-js-and-cloud9-and-openshift/" rel="noopener noreferrer"&gt;tutorial&lt;/a&gt; that you'd no longer be able to follow. For one, the web-based IDE I used was sold to Amazon, and I'm not sure you can easily use it for free. Second, the hosting service I used seem to no longer offer a free plan. And finally, Twitter, whose API I used, &lt;a href="https://botwiki.org/blog/twitter-shutting-down-free-access-to-their-api-on-february-9/" rel="noopener noreferrer"&gt;is in disarray&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Yes, seven years is a really long time on the web.&lt;/p&gt;

&lt;p&gt;But as some technologies and platforms disappear, new ones arise. And one that I am particularly excited about is the &lt;a href="https://en.wikipedia.org/wiki/Fediverse" rel="noopener noreferrer"&gt;fediverse&lt;/a&gt;. It's an open standard for making a better social web with roots going back to 2008. And the way many folks are being introduced to it is via the rise of &lt;a href="https://en.wikipedia.org/wiki/Mastodon_(social_network)" rel="noopener noreferrer"&gt;Mastodon&lt;/a&gt;, both a social media site, and software to make your own version, that's built on this standard.&lt;/p&gt;

&lt;p&gt;And a fun way to explore the fediverse is using Mastodon's API to re-create my bot.&lt;/p&gt;

&lt;p&gt;And for that, I am going to use my &lt;a href="https://stefanbohacek.com/project/creative-bots/" rel="noopener noreferrer"&gt;Creative Bots&lt;/a&gt; project. You have a few options how to host it, but for this tutorial I am going to go with &lt;a href="https://glitch.com/" rel="noopener noreferrer"&gt;Glitch&lt;/a&gt; for its ease of use. Note that you don't need an account to follow along, but you will need a &lt;a href="https://glitch.com/pricing" rel="noopener noreferrer"&gt;paid plan&lt;/a&gt; to keep your bot running after we're done.&lt;/p&gt;

&lt;p&gt;First, you will need to &lt;a href="https://botwiki.org/resource/tutorial/how-to-make-a-mastodon-botsin-space-app-bot/" rel="noopener noreferrer"&gt;set up an account for your bot&lt;/a&gt;. Any Mastodon instance will do. Note that the popular &lt;a href="https://botsin.space/" rel="noopener noreferrer"&gt;botsin.space&lt;/a&gt; instance has a manual review process in place, so you might have to wait a bit if you decide to go with that one.&lt;/p&gt;

&lt;p&gt;Once we have our account ready, &lt;a href="https://glitch.com/edit/#!/remix/creative-bots" rel="noopener noreferrer"&gt;let's make a remix&lt;/a&gt; of the Creative Bots Glitch app.  &lt;/p&gt;

&lt;p&gt;Next, we'll update our &lt;code&gt;.env&lt;/code&gt; file (see the sidebar on the left) and add the following variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WHAT_CAPITAL_BOT_MASTODON_API_URL="https://botsin.space/api/v1/"
WHAT_CAPITAL_BOT_MASTODON_ACCESS_TOKEN="123456789-abcd"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv60hyfmswxvtdg7luhrw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv60hyfmswxvtdg7luhrw.png" alt="Screenshot from glitch.com showing how to add environmental variables" width="800" height="335"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Replace botsin.space with the name of your bot's instance, if you're not using that one. For example, if your bot is on &lt;a href="https://mastodon.social/" rel="noopener noreferrer"&gt;mastodon.social&lt;/a&gt;, you will use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;WHAT_CAPITAL_BOT_MASTODON_API_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://mastodon.social/api/v1/"&lt;/span&gt;
&lt;span class="nv"&gt;WHAT_CAPITAL_BOT_MASTODON_ACCESS_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"123456789-abcd"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So far, so good.&lt;/p&gt;

&lt;p&gt;Now, back in the sidebar, open &lt;code&gt;bots/reply-mastodon.js&lt;/code&gt;. This is a simple example of a bot that replies to messages sent to it, and we will expand on it to make our bot.&lt;/p&gt;

&lt;p&gt;But before we write any code, we will need to prepare some data. Using the sidebar again, add a file called &lt;code&gt;data/capitals.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F65sv6xu8n48bpzhed7iv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F65sv6xu8n48bpzhed7iv.png" alt="A screenshot showing how to add a new file in Glitch." width="800" height="219"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can get the contents from the &lt;a href="https://glitch.com/edit/#!/what-capital?path=data%2Fcapitals.js" rel="noopener noreferrer"&gt;finished project here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Note that the JSON object with answers also contains description of each flag. More on that in a bit.&lt;/p&gt;

&lt;p&gt;Now, let's update your bot's code to use the correct access token and API URL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mastodon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;mastodonClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
   &lt;span class="na"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WHAT_CAPITAL_BOT_MASTODON_ACCESS_TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;api_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WHAT_CAPITAL_BOT_MASTODON_API_URL&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, you can already try speaking with your bot. Go ahead and say hello!&lt;/p&gt;

&lt;p&gt;After you have a bit of fun with your new bot, let's get back to writing some more code. All that's next will come before the &lt;code&gt;module.exports&lt;/code&gt; section.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://glitch.com/edit/#!/what-capital?path=bots%2Fwhat-capital.js" rel="noopener noreferrer"&gt;Here's the finished code again so that you can check your progress.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To start, we will need to load our &lt;code&gt;capitals.js&lt;/code&gt; file, so let's do just that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;helpers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/../helpers/helpers.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;capitals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/../data/capitals.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;mastodonClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/../helpers/mastodon.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that I also added the &lt;code&gt;fs&lt;/code&gt; module. This will be useful to keep track of a leaderboard, to make the game a bit competitive.&lt;/p&gt;

&lt;p&gt;Note that the &lt;code&gt;.data&lt;/code&gt; folder, which we will use, is a &lt;a href="https://help.glitch.com/kb/article/22-do-you-have-built-in-persistence-or-a-database/" rel="noopener noreferrer"&gt;built-in way for Glitch to store data for your app&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;savedDataPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;__dirname&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/../.data/what_capital.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;savedData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;country&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;capital&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;existsSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;savedDataPath&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;savedData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;savedDataPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;saveData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;savedDataPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;savedData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updateScores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;savedData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasOwnProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;savedData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;savedData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;savedData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;saveData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great. Now we'll need a pair of functions that will handle picking a new question and verifying the answer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pickNewCapital&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;capital&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;helpers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randomFromArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;capitals&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;flagUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://static.stefanbohacek.dev/images/flags/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;capital&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sr"&gt;/ /g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;.png`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;savedData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;capital&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;capital&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;capital&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;savedData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;capital&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;saveData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;helpers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;flagUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;imgData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;altText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;capital&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flag_description&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;capital&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flag_description&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;altText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;capital&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flag_description&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nx"&gt;mastodon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postImage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;What is the capital of this country?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;imgData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;alt_text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`An unspecified country flag: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;altText&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;checkAnswer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;answer&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;normalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;NFD&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\p&lt;/span&gt;&lt;span class="sr"&gt;{Diacritic}/gu&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;correctAnswer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;savedData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;capital&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;normalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;NFD&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\p&lt;/span&gt;&lt;span class="sr"&gt;{Diacritic}/gu&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;correctAnswer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the really tricky part. People will likely include words that are not part of the answer in their message, like "Hmm", or "I think...". And some city names may contain special characters. To make a bot that's fun to interact with, we need to account for all the possible ways people will talk to it.&lt;/p&gt;

&lt;p&gt;We could actually go a step further here, and use an array with acceptable variations of each city's name, maybe even the translation in its native language. There's an idea for a future update.&lt;/p&gt;

&lt;p&gt;And going back to the code above, you will notice that I am using the flag description as an alt text for the image. This way your bot can be &lt;a href="https://stefanbohacek.com/blog/creative-bots-and-accessibility/" rel="noopener noreferrer"&gt;enjoyed by everyone&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;altText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;capital&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flag_description&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we're ready to bring this all together inside the &lt;code&gt;reply&lt;/code&gt; function of our bot object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;fullMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visibility&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;public&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
  &lt;span class="nx"&gt;fullMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visibility&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unlisted&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;checkAnswer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;messageText&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;updateScores&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Yes, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;savedData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;capital&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is the capital of &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;
      &lt;span class="nx"&gt;savedData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, correct! &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;getLeaderboard&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;pickNewCapital&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;That doesn't seem correct, sorry! Or perhaps a new flag was posted?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Sorry, do you mind responding publicly?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;mastodon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fullMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And there you have it, your very own interactive game bot, running on the open web.&lt;/p&gt;

&lt;p&gt;Feel free to browse more examples of bots I've made &lt;a href="https://stefans-creative-bots.glitch.me/" rel="noopener noreferrer"&gt;using my starter project&lt;/a&gt;, and you can find even more resources for creative botmakers over at &lt;a href="https://botwiki.org/" rel="noopener noreferrer"&gt;botwiki.org&lt;/a&gt;, and join the &lt;a href="https://botmakers.org/" rel="noopener noreferrer"&gt;botmakers.org&lt;/a&gt; Slack group.&lt;/p&gt;

&lt;p&gt;I hope you find this tutorial fun. If you have any questions or suggestions, feel free to &lt;a href="https://stefanbohacek.com/contact/" rel="noopener noreferrer"&gt;reach out&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Until next time!&lt;/p&gt;

</description>
      <category>bots</category>
      <category>mastodon</category>
      <category>mastodonapi</category>
      <category>chatbots</category>
    </item>
    <item>
      <title>Introduction to Mastodon bots</title>
      <dc:creator>Stefan Bohacek</dc:creator>
      <pubDate>Fri, 07 Sep 2018 12:55:40 +0000</pubDate>
      <link>https://dev.to/botwiki/introduction-to-mastodon-bots-hfn</link>
      <guid>https://dev.to/botwiki/introduction-to-mastodon-bots-hfn</guid>
      <description>&lt;p&gt;&lt;strong&gt;2022 UPDATE:&lt;/strong&gt; Glitch &lt;a href="https://botwiki.org/blog/glitch-banning-use-of-pinging-services/" rel="noopener noreferrer"&gt;no longer allows a method that’s been used to keep bots running on their free plan&lt;/a&gt;. While I work on an updated version of this tutorial, here are some useful resources to check out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://botwiki.org/resource/guide/the-definitive-guide-to-creative-botmaking/" rel="noopener noreferrer"&gt;my general guide to making creative bots&lt;/a&gt; which also has a few Mastodon-specific tips&lt;/li&gt;
&lt;li&gt;my &lt;a href="https://stefanbohacek.com/project/creative-bots/" rel="noopener noreferrer"&gt;Creative Bots starter project&lt;/a&gt; that lets you make bots for Mastodon, Twitter, and Tumblr&lt;/li&gt;
&lt;li&gt;the Coding Train’s &lt;a href="https://www.youtube.com/watch?list=PLRqwX-V7Uu6byiVX7_Z1rclitVhMBmNFQ&amp;amp;v=sKSxBd56H70" rel="noopener noreferrer"&gt;Mastodon bot video tutorial series&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://botwiki.org/bot/?networks=fediverse&amp;amp;opensource=true" rel="noopener noreferrer"&gt;open-source bots on Botwiki&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And as a bonus, &lt;a href="https://botwiki.org/blog/catching-up-with-the-creator-of-botsin-space/" rel="noopener noreferrer"&gt;here’s my 2018 interview with the creator of botsin.space&lt;/a&gt;, a Mastodon instance dedicated to bots. Be sure to also follow Botwiki-related Mastodon accounts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mastodon.social/@botwiki" rel="noopener noreferrer"&gt;@botwiki@mastodon.social&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://botsin.space/@newonbotwiki" rel="noopener noreferrer"&gt;@newonbotwiki@botsin.space&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://botsin.space/@botwikirandom" rel="noopener noreferrer"&gt;@botwikirandom@botsin.space&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And you can find me at &lt;a href="https://stefanbohacek.online/@stefan" rel="noopener noreferrer"&gt;@stefan@stefanbohacek.online&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;It's been a few weeks since the &lt;a href="https://botwiki.org/blog/twitterbots-the-end-or-a-new-era/" rel="noopener noreferrer"&gt;big exodus&lt;/a&gt; of creative botmakers from Twitter, mainly due to the recent changes to the platform (and, well, &lt;a href="https://techcrunch.com/2018/09/04/twitters-ugly-incentive/" rel="noopener noreferrer"&gt;other reasons&lt;/a&gt;). Some of them gave up on making art bots altogether, but many tried to find a new home for their bots. And some of them ended up on Mastodon.&lt;/p&gt;

&lt;p&gt;If you haven't heard about Mastodon before, it's a social networking software that lets anyone host their own social network site. (There are similar projects, for example GNU social). All of these sites can be connected in what is known as the fediverse. (You can head to &lt;a href="https://en.wikipedia.org/wiki/Mastodon_(software)" rel="noopener noreferrer"&gt;Wikipedia&lt;/a&gt; for a more detailed description.)&lt;/p&gt;

&lt;p&gt;Mastodon has a very easy to use API, so it's a great replacement for Twitter if you'd like to experiment with generative art, natural language processing, or make a useful tool that posts updates on weather, or bills being passed by your government. As a bonus, you can easily get an RSS feed of your bot's posts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making your first Mastodon bot
&lt;/h2&gt;

&lt;p&gt;Setting up a new account for your bot is a breeze. First, you need to choose which Mastodon instance you want your bot to be on. I recommend &lt;a href="https://botsin.space" rel="noopener noreferrer"&gt;botsin.space&lt;/a&gt;, which was created specifically to run friendly bots.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmdu7ptisklnsbrap42fm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmdu7ptisklnsbrap42fm.png" alt="Make an account for your bot" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After you confirm your email, click the “Edit profile” link under your username and check off “This is a bot account”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjrt8zbu7bxqqkvq1p5xo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjrt8zbu7bxqqkvq1p5xo.png" alt="This is a bot" width="768" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After this, go to the Preferences page (the “cog” icon) and then click Development.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzwn29jty2zoaki3dh5ms.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzwn29jty2zoaki3dh5ms.png" alt="Preferences" width="791" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk3g8o0i5dbpial1m4u4w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk3g8o0i5dbpial1m4u4w.png" alt="Development" width="800" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now click the New Application button. Name your application, keep the settings the way they are, and click the Submit button at the bottom of the page.&lt;/p&gt;

&lt;p&gt;Now you can click your application’s name to reveal the access token for your bot. If you only see your API key, use this tool to generate your token.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdj9lawj1hljx5rnfa92k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdj9lawj1hljx5rnfa92k.png" alt="New application" width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmvo8wj49i7i88idjtxjt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmvo8wj49i7i88idjtxjt.png" alt="Your new bot" width="800" height="351"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And you’re done. Now for the fun part. For this tutorial I'm going to use my &lt;a href="https://glitch.com/edit/#!/generative-art-bot" rel="noopener noreferrer"&gt;generative-art-bot&lt;/a&gt; starter project on Glitch. You don't need to sign up for an account right now, Glitch lets you create temporary projects for you to test things out.&lt;/p&gt;

&lt;p&gt;First, click the Remix button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5534nv0yfkgzj8if8gn1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5534nv0yfkgzj8if8gn1.png" alt="Remix the project" width="800" height="527"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, update your &lt;code&gt;.env&lt;/code&gt; file with your access token. For &lt;code&gt;MASTODON_API&lt;/code&gt; you can use &lt;code&gt;https://botsin.space/api/v1/&lt;/code&gt;. Also update the value of &lt;code&gt;BOT_ENDPOINT&lt;/code&gt;. This can be anything, for example &lt;code&gt;12345&lt;/code&gt;. You will then be able to use the URL of your project together with the endpoint with a site like &lt;a href="https://cron-job.org/" rel="noopener noreferrer"&gt;cron-job.org&lt;/a&gt; to wake up your bot and do something. (I'll explain this part later in this tutorial.)&lt;/p&gt;

&lt;p&gt;The Glitch project is structured so that the code for your bot goes inside &lt;code&gt;bot.js&lt;/code&gt;. Here we load one of the generators (see the &lt;code&gt;generators&lt;/code&gt; folder) that will produce our image, and then we can either share it on Mastodon, or Twitter, or both.&lt;/p&gt;

&lt;p&gt;For this tutorial, let's try the triangular mesh generator.&lt;/p&gt;

&lt;p&gt;Delete the content of your &lt;code&gt;bot.js&lt;/code&gt; file so that we have a fresh start and add this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const helpers = require(__dirname + '/helpers.js'),
      generators = {
        triangular_mesh: require(__dirname + '/generators/triangular-mesh.js'),
      },
      mastodon = require(__dirname + '/bot/fediverse/mastodon.js');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;helpers&lt;/code&gt; is a module that has a few helper functions, for example &lt;code&gt;random_from_array&lt;/code&gt;, which will let us change up the text of the bot's status message every time it posts. And &lt;code&gt;color-scheme&lt;/code&gt; is a library that lets you generate color palettes, which we can use for our artwork.&lt;/p&gt;

&lt;p&gt;And this is what connects the &lt;code&gt;bot.js&lt;/code&gt; file with the main app that powers our bot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = () =&amp;gt; {

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code inside this exported function is what runs when you visit your bot's endpoint URL.&lt;/p&gt;

&lt;p&gt;First, let's set up messages for our bot to pick from when it posts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const helpers = require(__dirname + '/helpers.js'),
      generators = {
        triangular_mesh: require(__dirname + '/generators/triangular-mesh.js'),
      },
      mastodon = require(__dirname + '/bot/fediverse/mastodon.js');

module.exports = () =&amp;gt; {
  const status_text = helpers.random_from_array([
    'Check this out!',
    'New picture!',
    'Just look at that!'
  ]);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we're going to need some colors. I'm going to go with the &lt;a href="http://www.colourlovers.com/palette/4594645/petals" rel="noopener noreferrer"&gt;petals&lt;/a&gt; color scheme from &lt;a href="http://www.colourlovers.com/" rel="noopener noreferrer"&gt;colourlovers.com&lt;/a&gt;. And I'm going to have the bot post images with the size of 1200x500px.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const helpers = require(__dirname + '/helpers.js'),
    generators = {
      triangular_mesh: require(__dirname + '/generators/triangular-mesh.js'),
    },
    mastodon = require(__dirname + '/bot/fediverse/mastodon.js');

module.exports = () =&amp;gt; {

  const status_text = helpers.random_from_array([
      'Check this out!',
      'New picture!',
      'Just look at that!'
    ]);
  }

  const options = {
    width: 1200,
    height: 500,
    colors: ['571014', 'D4292F', 'FC5978', 'FE7B35', 'FBAC00']
  };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's generate a random triangular mesh using our settings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const helpers = require(__dirname + '/helpers.js'),
      generators = {
        triangular_mesh: require(__dirname + '/generators/triangular-mesh.js'),
      },
      mastodon = require(__dirname + '/bot/fediverse/mastodon.js');

module.exports = () =&amp;gt; {

  const status_text = helpers.random_from_array([
    'Check this out!',
    'New picture!',
    'Just look at that!'
  ]);

  const options = {
    width: 1200,
    height: 500,
    colors: ['571014', 'D4292F', 'FC5978', 'FE7B35', 'FBAC00']
  };

  generators.triangular_mesh(options, (err, image) =&amp;gt; {


  });

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now we're ready to share our art.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const helpers = require(__dirname + '/helpers.js'),
      generators = {
        triangular_mesh: require(__dirname + '/generators/triangular-mesh.js'),
      },
      mastodon = require(__dirname + '/bot/fediverse/mastodon.js');

module.exports = () =&amp;gt; {

  const status_text = helpers.random_from_array([
    'Check this out!',
    'New picture!',
    'Just look at that!'
  ]);

  const options = {
    width: 1200,
    height: 500,
    colors: ['571014', 'D4292F', 'FC5978', 'FE7B35', 'FBAC00']
  };

  generators.triangular_mesh(options, (err, image) =&amp;gt; {
    mastodon.post_image(status_text, image.path, (err, data) =&amp;gt; {


    });
  });

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As a final touch, let's log whether the bot did in fact post the image, and an error message if it didn't so that we can debug the problem.&lt;/p&gt;

&lt;p&gt;This is what your &lt;code&gt;bot.js&lt;/code&gt; file should look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const helpers = require(__dirname + '/helpers.js'),
      generators = {
        triangular_mesh: require(__dirname + '/generators/triangular-mesh.js'),
      },
      mastodon = require(__dirname + '/bot/fediverse/mastodon.js');

module.exports = () =&amp;gt; {

  const status_text = helpers.random_from_array([
    'Check this out!',
    'New picture!',
    'Just look at that!'
  ]);

  const options = {
    width: 1200,
    height: 500,
    colors: ['571014', 'D4292F', 'FC5978', 'FE7B35', 'FBAC00']
  };

  generators.triangular_mesh(options, (err, image) =&amp;gt; {
    mastodon.post_image(status_text, image.path, (err, data) =&amp;gt; {
      if (err){
        console.log('oh no...', err)
      } else {
        console.log('image was posted!');
        console.log(data.url);
      }
    });
  });

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perfect.&lt;/p&gt;

&lt;p&gt;Before we generate our first artwork, let's pull up the log, so we can see what the bot is doing. You can open the Activity Log using the Log button under your project icon.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjtpi671e8ruyxq70y2ca.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjtpi671e8ruyxq70y2ca.png" alt="Log button" width="800" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And now you can go to the endpoint URL of your bot (you can click the "Show" button on top of the page to see the URL of your project, and then add &lt;code&gt;/BOT_ENDPOINT&lt;/code&gt; at the end, just like in the example I used earlier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://generative-art-bot.glitch.me/12345
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz1irjxxj4n25jyfut4l4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz1irjxxj4n25jyfut4l4.png" alt="Show button" width="800" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open this URL in a new browser tab or window -- and you will see this in your Activity Log back in the Glitch editor:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnl37tlwzzyrib28uynfi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnl37tlwzzyrib28uynfi.png" alt="Log" width="800" height="254"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can copy the URL from the log to see your bot's post:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1bdhwr87dfimliq6epxd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1bdhwr87dfimliq6epxd.png" alt="Our art!" width="800" height="493"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every time you visit the endpoint URL a new image will be generated. (I will explain later in this tutorial how to do this automatically.)&lt;/p&gt;

&lt;p&gt;Now, time to experiment a little bit.&lt;/p&gt;

&lt;p&gt;Let's look at what's actually inside &lt;code&gt;generators/triangular-mesh.js&lt;/code&gt; and maybe poke around, to see if we can make the bot's output more fun and interesting.&lt;/p&gt;

&lt;p&gt;When you open the file, you will see &lt;a href="https://generativeartistry.com/tutorials/triangular-mesh/" rel="noopener noreferrer"&gt;a link to the tutorial&lt;/a&gt; that inspired this generator. We see how the options are being set up. (I'll get to the &lt;code&gt;animate&lt;/code&gt; option in a little bit.)&lt;/p&gt;

&lt;p&gt;The generator uses something called &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API" rel="noopener noreferrer"&gt;&lt;code&gt;canvas&lt;/code&gt;&lt;/a&gt; to make your image, which is an HTML element designed just for that. We can see a function called &lt;code&gt;drawTriangle&lt;/code&gt;, which, we might correctly assume draws the triangles. It looks pretty straightforward, let's change it up a bit. How about adding a smaller triangle inside the triangle?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const drawTriangle = (pointA, pointB, pointC) =&amp;gt; {
    ctx.beginPath();
    ctx.moveTo(pointA.x, pointA.y);
    ctx.lineTo(pointB.x, pointB.y);
    ctx.lineTo(pointC.x, pointC.y);
    ctx.lineTo(pointA.x, pointA.y);
    ctx.closePath();
    ctx.fillStyle = '#' + helpers.random_from_array(options.colors); 
    ctx.fill();
    ctx.stroke();

    /* Adding new code for a smaller triangle.*/

    ctx.beginPath();
    ctx.moveTo(pointA.x + 10, pointA.y - 10);
    ctx.lineTo(pointB.x - 10, pointB.y - 10);
    ctx.lineTo(pointC.x - 10, pointC.y + 10);
    ctx.lineTo(pointA.x + 10, pointA.y - 10);
    ctx.closePath();
    ctx.fillStyle = '#' + helpers.random_from_array(options.colors); 
    ctx.fill();
    ctx.stroke();

  }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is a little bit of math involved, as with all good art, but all I'm doing is moving the points closer to the center. Let's go back to our bot's endpoint URL and see what this does.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fogtsr7aafgvcib9g3u6z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fogtsr7aafgvcib9g3u6z.png" alt="Almost" width="800" height="492"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Alright, this is not exactly what I had in mind, I calculated the points of the inner triangle wrong. But it actually looks good! And this is cool about generative art, sometimes "mistakes" can &lt;a href="https://inconvergent.net/2018/a-myriad-of-mistakes/" rel="noopener noreferrer"&gt;make for a more interesting output&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Feel free to play some more with this generator, or check out the other examples, or even create &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API" rel="noopener noreferrer"&gt;your own generator&lt;/a&gt;. What's that? Oh, you're still wondering about the &lt;code&gt;animate&lt;/code&gt; option?&lt;/p&gt;

&lt;p&gt;Alright, let's go back to &lt;code&gt;bot.js&lt;/code&gt; and add this to our &lt;code&gt;options&lt;/code&gt; object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const options = {
    width: 100,
    height: 100,
    colors: ['571014', 'D4292F', 'FC5978', 'FE7B35', 'FBAC00'],
    animate: true
  };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Make sure to add a comma after &lt;code&gt;colors&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;For the sake of speeding things up, I also changed the size of the image.&lt;/p&gt;

&lt;p&gt;Back to our bot's endpoint--&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frzsywndqcm3jr2uua9nu.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frzsywndqcm3jr2uua9nu.gif" alt="Animated" width="640" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This particular generator produces GIFs that are too large for Mastodon's 8MB file size limit, so the quality is a little too low, but you could experiment with the &lt;code&gt;encoder&lt;/code&gt; settings and maybe find a way to improve this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automating your bot
&lt;/h2&gt;

&lt;p&gt;The final step in this tutorial will be automating our bot. Glitch puts inactive apps (that is, apps that don't get any outside traffic) to sleep after 5 minutes, so you will have to either periodically refresh your bot's endpoint URL all day, or, a much more convenient solution, use a site like &lt;a href="https://cron-job.org/" rel="noopener noreferrer"&gt;cron-job.org&lt;/a&gt; or &lt;a href="https://uptimerobot.com/" rel="noopener noreferrer"&gt;uptimerobot.com&lt;/a&gt; to do that for you.&lt;/p&gt;

&lt;p&gt;I'm going to use cron-job.org to show you how to set this up.&lt;/p&gt;

&lt;p&gt;Once you sign up for an account, head to the "Cronjobs" section and add a new &lt;a href="https://simple.wikipedia.org/wiki/Cron" rel="noopener noreferrer"&gt;cronjob&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr98b5ebot6ets7ynqu0b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr98b5ebot6ets7ynqu0b.png" alt="Add new cronjob" width="800" height="231"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd3whs5f013vei4qjoz0q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd3whs5f013vei4qjoz0q.png" alt="Add new cronjob" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click "User defined" under "Schedule". Here, select all the options under Days of months, Days of week, Months. Under Minutes, select 0. And under Hour, select on which hour your bot will post.&lt;/p&gt;

&lt;p&gt;For example, if you want to post every 6 hours, select the options 0, 6, 12, and 18.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fysa63uwtm0gfvszwm8we.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fysa63uwtm0gfvszwm8we.png" alt="Time settings" width="800" height="676"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hit the "Create cronjob" button at the bottom of the page, and you're all set!&lt;/p&gt;

&lt;p&gt;If you want to keep your bot running permanently, you will need to sign up for a Glitch account, which I would highly recommend even for other projects, not just bots.&lt;/p&gt;

&lt;p&gt;If you get stuck at any point during this tutorial, feel free to &lt;a href="https://botmakers.org" rel="noopener noreferrer"&gt;join the Botmakers group&lt;/a&gt; and someone will be happy to help you out.&lt;/p&gt;

&lt;p&gt;Thanks for following along, and have fun making generative art bots!&lt;/p&gt;

</description>
      <category>bots</category>
      <category>mastodon</category>
      <category>node</category>
      <category>generativeart</category>
    </item>
  </channel>
</rss>
