<?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 Neidig</title>
    <description>The latest articles on DEV Community by Stefan Neidig (@dasheck0).</description>
    <link>https://dev.to/dasheck0</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%2F790592%2F5502e612-c2bc-46f8-ad08-94f2bb1f7fe1.png</url>
      <title>DEV Community: Stefan Neidig</title>
      <link>https://dev.to/dasheck0</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dasheck0"/>
    <language>en</language>
    <item>
      <title>git-mcp-server crashed my repository</title>
      <dc:creator>Stefan Neidig</dc:creator>
      <pubDate>Sat, 26 Jul 2025 10:54:36 +0000</pubDate>
      <link>https://dev.to/dasheck0/git-mcp-server-crashed-my-repository-1om4</link>
      <guid>https://dev.to/dasheck0/git-mcp-server-crashed-my-repository-1om4</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclaimer: AI was used for checking grammar and to improve readability. Content was written by human.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Just a quick story that happened yesterday and perhaps a warning to the vibe coders out there. As the title suggests, I too tend to vibe code from time to time. When I do, I go all out and allow the agent to even commit its changes. I use a git-mcp-server for this (see &lt;a href="https://github.com/modelcontextprotocol/servers/tree/main/src/git" rel="noopener noreferrer"&gt;https://github.com/modelcontextprotocol/servers/tree/main/src/git&lt;/a&gt;), which does a great job until I noticed some strange behaviour during one vibe coding session.&lt;/p&gt;

&lt;h1&gt;
  
  
  The situation
&lt;/h1&gt;

&lt;p&gt;After the agent committed everything, there were still some staged files. Not knowing what they were, I ran &lt;code&gt;git status&lt;/code&gt; myself and found the following situation&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;M ./.git/index
M ./.git/logs/HEAD
M ./.git/logs/reds/heads/feature/...
M ./.git/refs/heads/feature/....
# and other non git related files
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Part of my &lt;code&gt;.git&lt;/code&gt; directory (in particular the index) was staged and marked as changed. However, this means that these files were checked into the VCS to begin with, which shouldn't happen. I tried to find the MCP tool call that was responsible for this. Here is the malicious action in question:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git_add
Repo path: "/Users/..../root/path/of/project"
Files: "."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git_commit
Repo path: "/Users/..../root/path/of/project"
Message: "chore: some message"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As I was in a true vibe coding session, I barely checked what the agent did. But even if I had, I would never have guessed that a “git add .” would lead to the corruption of my local repository (and, as I later found out, my remote repository as well).&lt;/p&gt;

&lt;h1&gt;
  
  
  The problem
&lt;/h1&gt;

&lt;p&gt;As I searched for issues reporting the same behavior, I found this: &lt;a href="https://github.com/modelcontextprotocol/servers/issues/2373" rel="noopener noreferrer"&gt;https://github.com/modelcontextprotocol/servers/issues/2373&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So basically, what was happening was that all files starting with a &lt;code&gt;.&lt;/code&gt; were staged, and not just the current directory, which is usually denoted by &lt;code&gt;.&lt;/code&gt;. I do not want to bash the maintainers of the MCP server, especially since this was fixed rather quickly (I’m still not sure why this happened to me yesterday). What I would like to do is show you how to fix it once you are in that situation, as the solution is not that straightforward. I also want to talk about some learnings I drew from this incident.&lt;/p&gt;

&lt;h1&gt;
  
  
  The solution
&lt;/h1&gt;

&lt;p&gt;Git has a built-in behavior that prevents the &lt;code&gt;.git&lt;/code&gt; directory from being put into VCS. Somehow, the MCP tool managed to bypass this safeguard. So let’s figure out how to fix it.&lt;/p&gt;

&lt;p&gt;First of all, what’s the big deal about having this in VCS, you might ask? For starters, Git behaves unreliably from that point on. Commits no longer work properly — it doesn’t throw an error, but it also doesn’t commit anything. Secondly, you’re no longer able to push to the remote repository. Check out this log:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push origin develop 

Enumerating objects: 14486, done.
Counting objects: 100% (14486/14486), done.
Delta compression using up to 12 threads
Compressing objects: 100% (12446/12446), done.
remote: error: object 53d0cf36e260779eb90f3a546842ac0a38327f48: hasDotgit: contains '.git'
remote: fatal: fsck error in packed object
error: remote unpack failed: index-pack failed
To github.com:.../....git
 ! [remote rejected] develop -&amp;gt; develop (failed)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Git has a built-in tool that checks whether &lt;code&gt;.git&lt;/code&gt; files have been checked into VCS and prevents the remote from accepting changes that include such commits. These are just two obvious breaking points. I would assume there are many more. We can even check if we have commits that include &lt;code&gt;.git&lt;/code&gt; files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git fsck --full | grep '.git'

Checking object directories: 100% (256/256), done.
warning in tree 783fc820c5d91ee46c64fc0d08d7413474451718: hasDot: contains '.'
warning in tree 53d0cf36e260779eb90f3a546842ac0a38327f48: hasDotgit: contains '.git'
warning in tree e0eabd8ea18232fa10b87de0be0548259b18f11f: hasDot: contains '.'
Checking objects: 100% (14492/14492), done.
Verifying commits in commit graph: 100% (15/15), done.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So &lt;code&gt;53d0cf3&lt;/code&gt; seems to be one of these commits. The unfortunate part is that we need to remove this from our repository, and the only way to do that is by rewriting the Git history. This is a huge issue, especially for large repositories with multiple PRs and team members working on them, as it essentially breaks everything. But as far as I know (please correct me if I’m wrong), this is our only option. So let’s get on with it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git filter-repo --force --path-glob '.*' --invert-paths
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we are scanning all of our commits for files starting with a &lt;code&gt;.&lt;/code&gt;. I tried using the glob &lt;code&gt;.git*&lt;/code&gt;, but that didn’t seem to work. &lt;code&gt;--invert-paths&lt;/code&gt; means we remove all files that match the pattern, and &lt;code&gt;--force&lt;/code&gt; tells Git to enforce the rewriting of the history, even if the repository is not a fresh clone. After running this, all &lt;code&gt;.&lt;/code&gt; files are removed from every commit, and each commit receives a new hash.&lt;/p&gt;

&lt;p&gt;Next, we should add and commit all necessary dotfiles again in a new commit. For me, this was only the &lt;code&gt;.gitignore&lt;/code&gt; file, so the following worked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git checkout HEAD@{1} -- .gitignore &amp;amp;&amp;amp; git commit -m "chore: restore gitingore file" 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we need to check for &lt;code&gt;.git&lt;/code&gt; files in our commits again and shouldn't find anything&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git fsck

Checking object directories: 100% (256/256), done.
Checking objects: 100% (182/182), done.
dangling blob a111f1ad14e068fe85b133634a4917cca01ee5b4
Verifying commits in commit graph: 100% (14/14), done.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looking good. We then need to add the remote again, since it is removed when running &lt;code&gt;git filter-repo&lt;/code&gt;. We now essentially have a new repository that coincidentally shares the same history, but with different commit hashes. Therefore, we need to force push, which breaks PRs, issues, and anything tied to the previous remote history. &lt;/p&gt;

&lt;p&gt;We also need to force merge into other branches (most likely master or main) and force push them as well. It’s not something I hope to do in the future again, but the alternative would have been to completely reinitialize Git and commit everything as an initial commit. For me, this approach was the better option.&lt;/p&gt;

&lt;h1&gt;
  
  
  The learnings
&lt;/h1&gt;

&lt;p&gt;I was happy to have my Git repository back, but it was crucial to prevent this from happening ever again. Here are some things that might help:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Put **/.git into .gitignore&lt;/strong&gt;. It might seem odd, but it would have saved me from a lot of trouble. Better safe than sorry.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Git hooks to check for .git files before committing&lt;/strong&gt;. There are tools to help you get started with Git hooks (e.g., Husky, Lefthook).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do not let the agent commit (i.e., avoid using a Git MCP Server)&lt;/strong&gt;. While this might seem obvious, I’m not entirely against using them. It’s like falling off a horse and never riding again — there will always be bugs, and we should focus on finding solutions rather than abandoning the software altogether.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check the MCP Server before using it&lt;/strong&gt;. I will be more cautious in the future about which MCP server I use. I probably would have never anticipated this bug, let alone read the code to try and understand what the server is doing. But sourcing MCP servers from reliable projects — and checking issues, stars, and popularity — can certainly help.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Really understand the crucial parts of your automation&lt;/strong&gt;. Don’t blindly trust it. Mishaps, bugs, and catastrophes can happen. A broken Git history might be one of the worst-case scenarios. When automating parts of your core infrastructure, make sure you understand what is happening and monitor it closely. If in doubt, avoid it (but only if you’re really in doubt).&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;My doctor once told me (regarding my health), "Not as bad as it could have been." That pretty much sums up this story in one sentence. While I’m not happy about having to completely rewrite the repository’s history, I’m certainly glad that I managed to get it back to a functional state. I learned a few things about Git (again) and now have a story to tell. But boy, I don’t ever want to deal with this again.&lt;/p&gt;

&lt;p&gt;Have you every had an issue like that? Is there a better way to deal with this issue? Please let me know.&lt;/p&gt;

</description>
      <category>git</category>
      <category>mcp</category>
      <category>ai</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>I tried cline 3.0.0 and here is what happend</title>
      <dc:creator>Stefan Neidig</dc:creator>
      <pubDate>Sun, 29 Dec 2024 13:01:11 +0000</pubDate>
      <link>https://dev.to/dasheck0/i-tried-cline-300-and-here-is-what-happend-3dm5</link>
      <guid>https://dev.to/dasheck0/i-tried-cline-300-and-here-is-what-happend-3dm5</guid>
      <description>&lt;p&gt;&lt;em&gt;This post was created with the help of AI (fixing grammer and spelling). Actual writing was done by me (human).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;EDIT: I updated the cost ratio between Deepseek and Claude Sonet 3.5 after I found the correct input and output tokens&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now that I have your attention, I apologise for the clickbait title. I'm trying to make it worth your while to read. As the title says, I tested cline 3.0.0 in a real-world scenario. I have already used cline in version 2.X with promising results. Two weeks ago the new version came out with some nifty new features like MCP servers, .clinerules and an autonomous mode. I wanted to put this to the test.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MCP server: little helper tools that perform certain tasks (e.g. calculations, connections to an API, ...)&lt;/li&gt;
&lt;li&gt;.clinerules: A file at the top level of your project that contains specific instructions for cline to follow&lt;/li&gt;
&lt;li&gt;Autonomous mode: In this mode, cline does not need confirmation from the user. You can define which actions Cline may perform independently and which must be confirmed by the user.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've built a task management platform (a fancier word for todo app) and I want to take you on a tour of one particular part of it, because it has a little twist that I can't reveal until the end. This task management platform (let's call it "Tasks" for now) offers everything you would expect from a task management platform. I'll probably write about it in the future too. What it lacked was a landing page. &lt;/p&gt;

&lt;h4&gt;
  
  
  Landing page before
&lt;/h4&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%2Fzih387evks4s4i6djk63.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%2Fzih387evks4s4i6djk63.png" alt="Image description" width="800" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you may have guessed, I used cline to create a landing page for me. It all worked well and looked good. It also added a testimonials section without me specifically instructing it to. However, the profile pictures for the testimonials were just placeholders. And that's when it hit me. This is a really cool use case for an MCP server.&lt;/p&gt;

&lt;h4&gt;
  
  
  Landing page by cline
&lt;/h4&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%2Fynjb8vae7kj5uqaowjnj.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%2Fynjb8vae7kj5uqaowjnj.png" alt="Image description" width="800" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  MCP server
&lt;/h2&gt;

&lt;p&gt;An MCP server (Model Context Protocol) is like a personal helper for your AI assistant that acts as an MCP client. It is a small program that runs or can be called in the background and is ready to perform certain tasks when called.&lt;/p&gt;

&lt;p&gt;For example, imagine you need to retrieve data from the web, commit files to the repository or simply get the current time for the AI to work with – that’s where an MCP server comes in. It listens, waits for instructions and completes the tasks without you having to write additional code each time. The AI understands what each MCP server does and calls it automatically when it needs to.&lt;/p&gt;

&lt;p&gt;In this project, I needed an MCP server to generate facial images for testimonials by pulling them from ThisPersonDoesNotExist.com. The website ThisPersonDoesNotExist.com went viral some time ago for creating a photorealistic images of a person every time you visit it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Face Generator
&lt;/h2&gt;

&lt;p&gt;So I turned to cline and said&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Add yourself a tool for generating an image of a human face. It is really simple. Just visit &lt;a href="https://thispersondoesnotexist.com" rel="noopener noreferrer"&gt;https://thispersondoesnotexist.com&lt;/a&gt;. This will generate such an image. You just have to download it and store it somewhere. Give yourself some options/parameters (i.e. location where to save the image). And write the tool in a way so that it can be integrated in coding workflow easily. For example, we just created testimonials for a website. This tool would be handy to generate a face for the testimonial giver. So I hope you get what I want.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As you can see, I wasn't so sure I had made myself clear enough for it to work. But sure enough, the first draft of the server did just that. It also asked me if it should run. It worked, without any issues the first time, which was scary. Not that it can produce code that works first time. It's that it's so easy to go from "I could really use a tool like this to make my life easier" to "It's there and it works" in less than a minute. Here are some of the images, generated. &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&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%2Fv5rglbb8zssue4cgx72l.png" alt="Image description" width="256" height="256"&gt;&lt;/td&gt;
&lt;td&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%2Faz4mzxam9yei5su2xp14.png" alt="Image description" width="256" height="256"&gt;&lt;/td&gt;
&lt;td&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%2Fs5v2v04ju0sqx5tzno42.png" alt="Image description" width="256" height="256"&gt;&lt;/td&gt;
&lt;td&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%2Fpx1plqq0ktf0je8y2om4.png" alt="Image description" width="256" height="256"&gt;&lt;/td&gt;
&lt;td&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%2Fuy0ff8bdo33s8fwonbpx.png" alt="Image description" width="256" height="256"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Iteration of the first draft
&lt;/h2&gt;

&lt;p&gt;The first draft was only simple and it did what was my intention. After that, I had more ideas on how to improve it and kept on iterating. Here are some prompts that I used to make this tool even more helpful.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please keep in mind that you sometimes need to generate multiple images at once: not sure if it’s best to invoke the tool multiple times or if it would be better to invoke it once with a new parameter and loop inside the script. Also add an option to resize the image to a given size. There should be a default for this, so this parameter is optional.&lt;/p&gt;

&lt;p&gt;Can we add an option to generate faces with different shapes? Circle and rounded rectangle would be useful. Allow for a borderRadius parameter for the rounded shape.&lt;/p&gt;

&lt;p&gt;I noticed that the output images are .jpg by default. Let’s make sure all images are saved as .png, regardless of the input filename. Update the filename logic to enforce this.&lt;/p&gt;

&lt;p&gt;Add options to resize the images during generation. Default should be 256x256, but I want to pass width and height as parameters when needed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As you can see, I've tried to describe what I want without saying how to do it, as the AI is capable of doing this itself. Disclaimer: I didn't review the generated code too much. From what I saw, it looked okay-ish. I was more focused on getting a result. Eventually, I got a tool that worked quite well for different scenarios and worked on every iteration, which is impressive. After some testing, I figured it was time to put it to the test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing the tool
&lt;/h2&gt;

&lt;p&gt;Now I wanted to replace the placeholder images with real faces from the Face Generator mcp tool. I also forgot to mention that cline built and installed the mcp server all by himself. I almost took that for granted. 8) This part is a bit bumpier than the others and I'll try to explain it in a back and forth sort of way. Bear with me, there is an important lesson here.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Now invoke this tool and add faces to the testimonials. Do not use the temp-faces directory. Use one that actually serves images for this React application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I created the "temp-faces" directory to test the mcp tool. cline called the tool correctly, but with the wrong parameters (3 images). So I had to prompt once more:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Check the LoginPage to see how many testimonials you will need.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And lo and behold, it generated the images and replaced them correctly in the existing code. But the styling was not correct. So once again a prompt to correct this.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The images are pulled correctly. However, the styling is off. Look at the screenshot.&lt;/p&gt;
&lt;/blockquote&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%2Fjak0qf6moilemgtl57kq.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%2Fjak0qf6moilemgtl57kq.png" alt="Image description" width="800" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The screenshot function didn't actually work, but that was due to the model I was using. I just described it and it resized the images correctly. So the tool worked, even in a real scenario. Now it was time to publish it so cline doesn't use a local copy of it. Maybe this tool is useful for others as well? &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%2Fc4ii5ylbjkh3sayrhuhu.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%2Fc4ii5ylbjkh3sayrhuhu.png" alt="Image description" width="800" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Publishing it
&lt;/h2&gt;

&lt;p&gt;So publishing means cleaning everything up, preparing it for publishing and actually publishing it. Also, I had to move it. When cline is instructed to create a tool, it uses its own folder for that, which is not my project directory. And instead of thinking too much about it, I once again focused more on what I want the AI to do, not how it does it. Here are the prompts&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Move the face- generator MCP server to my Nodejs project directory. I want to publish it from there.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I left out the actual path because I didn't want reveal directory structure. It's important to point this out so no one thinks the AI is smart enough to guess/know the correct directory. There's probably an MCP server tool for accessing the file system, so it can actually figure that out. But none of that was used here.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;One final touch to this MCP server tool. I want to release it somewhere. Please prepare the package for release. Add a README (for example). Not sure what else we need. Also explain where and how I can release it.&lt;/p&gt;

&lt;p&gt;Now that the README and LICENSE are in place, publish the face- generator to npm. Make it public.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And then it broke.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;npm publish –access public. I got an error saying the package is private. Remove the ‘private’ field from package.json and try again.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And at this point I realised what has already become clearer. Instead of telling the AI what to do, I simply pointed out the error to it and thought, "Figure it out for yourself". For some of you who have been working with such systems longer than I have, this may not be anything new, but for me it was an epiphany. And something that sets other systems, and cline 2.X in particular, apart from the latest version. I could actually shoot back and the AI figured out the rest. It was no surprise that it was able to overcome this issue and finally publish. If you want to see the result and / or just need a mcp server tool to generate random profile pictures, here you go &lt;a href="https://www.npmjs.com/package/@dasheck0/face-generator" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/@dasheck0/face-generator&lt;/a&gt;. If you take a look at version 1.0.0, you will find an important typo in the readme file. Instead of &lt;code&gt;npm install @dasheck0/face-generator&lt;/code&gt; and it said to run &lt;code&gt;npm install @yourname/face-generator&lt;/code&gt;, which would lead to installation errors. I didn't see it, when it produced this line, which is another important lesson. Always be the pilot (at least for now), while the AI is the co-pilot. This means you must keep an eye on what it's doing. For me, anyway, this was the perfect opportunity to test its autonomous capabilities. Here is the prompt&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I see that the installation is not correct it should be ‘npm install &lt;a class="mentioned-user" href="https://dev.to/dasheck0"&gt;@dasheck0&lt;/a&gt;/face-generator’. please fix it, commit it, push it and rerelease it on npm.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I auto approved everything (MCP server invocation, editing files, reading files and safe command line execution) and then went to get some water. The task was done in less than a minute without me having to intervene. Impressive, despite the fact that it was simply&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fix a typo&lt;/li&gt;
&lt;li&gt;increment the version&lt;/li&gt;
&lt;li&gt;commit everything&lt;/li&gt;
&lt;li&gt;execute some commands (e.g. npm publish)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The impressive thing is that I'm telling the AI to do something that is more than just coding, and it works from A to Z.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some stats and the twist
&lt;/h2&gt;

&lt;p&gt;Alright, let's cut to the chase. I promised you a twist. cline is independent of AI models, meaning you can use almost any model (even open source models). I believe the models from Anthropic should be used. At least those are the models I've used so far. And they are getting pretty expensive. I've burned through $50 in a couple days. That's still a lot cheaper when you factor in the time it would have taken me if I had done it by hand. However from a non-monetization perspective, it gets pretty expensive very quickly. I saw a video the other day about Deepseek performing similarly to Claude Sonnet 3.5 at a fraction of the cost. Twist: So everything you've seen so far has been the work of the Deepseek model. I haven't looked at the benchmarks yet, but in my experience it performs almost as well as Claude Sonnet 3.5, which is really impressive for an open source model. The main difference (besides the cost) is that it thinks in much smaller steps. Claude Sonnet 3.5 can complete a complex task in just one edit, whereas Deepseek requires multiple edits. I like this approach much better as it is more tailored to the way we work, which has helped me to understand it better. At the end of the day, it's just a different kind of approach. Here are some stats on token usage and pricing&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requests to the model: 155&lt;/li&gt;
&lt;li&gt;Tokens used: 5,698,390 (50,688 Output, 713,558 Cache Miss Input)&lt;/li&gt;
&lt;li&gt;Spend: $0.18 (Deepseek)&lt;/li&gt;
&lt;li&gt;Cost for the same amount of tokens for Claude Sonnet 3.5: $2.90 ($3.00 per MTok &lt;a href="https://docs.anthropic.com/en/docs/about-claude/models#model-comparison-table" rel="noopener noreferrer"&gt;https://docs.anthropic.com/en/docs/about-claude/models#model-comparison-table&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The price difference between Deepseek and Claude is huge (only 6% of the cost). I can say with certainty that Deepseek is my new go to model with cline. And I can also say with certainty that cline is my CoPilot now more than ever.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;All in all, this experiment was a great success and I learned a lot from it. Before I present my learnings I want to emphasise that AI is a powerful tool, but not the answer to everything. I am far from blindly trusting AI and accepting it as our lord and saviour. I think it is important to deal with this type of technology these days, especially as a developer. I've been a software developer since 2004 and I've seen a lot in that time. So I'm not an AI kiddie who is suddenly the best developer in the world just because he turned to AI. It was important for me to mention this so as not to appear biased. that would stand in the way of an open dialog.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;AI co-piloting has become much more helpful. It's not capable enough to replace you (yet). But developers who know how to use it will replace you. &lt;strong&gt;Interacting with AI is the new skill that everyone should learn&lt;/strong&gt;. Like learning how to google in the mid 2000s.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tell AI what to do or how to do it. But not both.&lt;/strong&gt; I prefer to focus on the what, because that feels more natural to me. There was a constant back and forth between me and the AI – like suggesting ideas to a colleague, except this colleague can generate entire servers in seconds. I would suggest an idea, Cline would execute it, and if something wasn't right, I would step in to correct it. This dynamic felt like a true collaboration, where the AI did the heavy lifting and I focused on creative problem solving.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Know what to expect from your co-pilot and how to use it effectively&lt;/strong&gt;. Cline automated things I would normally dread. What stood out was how effortlessly the AI filled in the gaps without me having to grind through repetitive tasks. However, the AI didn’t always get everything right. There were typos, missteps and quirks that required my attention. I was not able to tell it a god-prompt to do everything. I think we will never get there. But giving smaller tasks and iterating on them was working very well.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;I am in no way affiliated with any of the above tools. But I am an eager user of these and wanted to share my experience. These are just my learnings based on my personal opinion and experiments. Yours may differ. And if so I would also love to learn from you as well. What are your experiences, successes and failures? Let's talk.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>genai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Using Midjourney for creating 2d game assets</title>
      <dc:creator>Stefan Neidig</dc:creator>
      <pubDate>Sat, 09 Sep 2023 11:26:46 +0000</pubDate>
      <link>https://dev.to/dasheck0/using-midjourney-for-creating-2d-game-assets-2j6d</link>
      <guid>https://dev.to/dasheck0/using-midjourney-for-creating-2d-game-assets-2j6d</guid>
      <description>&lt;p&gt;I started game development almost 20 years ago and have published few titles on itch.io, with many more in the bank. The main reason for that is that I lost interest in many of them due to the lack of visual aesthetics. It really motivates me when I see an idea come to life. However, I couldn't draw anything pleasing even if my life depended on it. With the uprising of generative AI in general and Midjourney in particular, I wanted to try it out for myself and see if I could use this as my designer/art director for my future game development projects.&lt;/p&gt;

&lt;p&gt;
  tl;dr
  &lt;p&gt;Midjourney produces amazing results but struggles with some basic asset types (i.e. buttons). Prompt engineering is key. Will use it again in future games. If you want to see the results for yourself, checkout: &lt;a href="https://dasheck.itch.io/fantasy-matching-card-game" rel="noopener noreferrer"&gt;itch.io&lt;/a&gt; &lt;/p&gt;

&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;I wanted to create a simple game so I wouldn't risk dropping it because of complexity or the fact that it takes weeks to complete. This is about asset creation, not game development in general. Also, I used phaserJS for this because it handles a lot of the complexity in creating games (e.g. rendering, animations, ...).&lt;/p&gt;

&lt;p&gt;So I decided to use a simple card matching game, often called Memory. You see a set of cards, all face down. Your task is to choose two cards. If they match, you get a point and the cards are removed from the game. If they don't match, the cards are turned face down again and it's your opponent's turn. The opponent is a simple agent who follows some rules that are not relevant to the experiment.&lt;/p&gt;

&lt;p&gt;The goal of this experiment was to create &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a visually appealing background&lt;/li&gt;
&lt;li&gt;a cool looking set of cards (including back cover)&lt;/li&gt;
&lt;li&gt;a button image&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wanted a fantasy-style game, similar to Bastion or Rayman Legends.&lt;/p&gt;

&lt;h2&gt;
  
  
  Process
&lt;/h2&gt;

&lt;p&gt;Before I started the midjourney part, I created a few simple assets to work with so I had the game ready before I started creating the actual production assets. This is something I never considered doing before, but found very helpful and will continue to do in the future. Here are the assets I came up with:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fh9005rjrv5avkqfvyo8z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fh9005rjrv5avkqfvyo8z.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So the game would basically look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fmq2i9et7g98ykzb77b69.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fmq2i9et7g98ykzb77b69.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Normally, that would have been it, except for trying to find some free assets from the internet that usually wouldn't work. Now for the midjourney part.&lt;/p&gt;

&lt;h2&gt;
  
  
  Midjourney
&lt;/h2&gt;

&lt;p&gt;Midjourney is a generative AI that can generate images. You provide a prompt of what you want to see, and 30 seconds later Midjourney shows you 4 results to choose from. From there you can upscale, regenerate or enhance them to your liking.&lt;/p&gt;

&lt;h3&gt;
  
  
  Back cover
&lt;/h3&gt;

&lt;p&gt;First, I wanted to get an idea of how this game could look like. So I started with a simple prompt like&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

2d matching card game, concept art, mobile game, bastion style


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

&lt;/div&gt;

&lt;p&gt;which produced amongst others the following image, that I eventually went with:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fztsevvxmzallzcalayly.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fztsevvxmzallzcalayly.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I used the style for the rest of the generation and even took one of the card designs as a back cover. Post-processing the images consisted of either removing the background with another AI tool or rearranging the images with Figma. In this particular case, I traced the inner part of the back cover to get a shape that I could use as a mask for the actual memory tiles. Here is an example (from left to right: back cover, mask, example tile):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F5gcctkv9fdzz55kzgw4b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F5gcctkv9fdzz55kzgw4b.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This worked pretty well and was done pretty quickly. So I had a template and just needed actual images to mask and rearrange so I could export the resulting layers as a single image.&lt;/p&gt;

&lt;h3&gt;
  
  
  Memory tiles
&lt;/h3&gt;

&lt;p&gt;This was not as easy as I had hoped. Since I wanted a fantasy setting, all my prompts went something like this: &lt;code&gt;fantasy [object], bastion style&lt;/code&gt;. Naturally, I experimented with different "objects" like heroes, monsters, buildings, castles, and so on. This was quite good, but eventually led to a problem: I could no longer win. In this game, it's extremely hard to remember complex shapes and similar images, at least for me. I developed an agent that memorised the revealed tiles and their position. The tiles were identified by their id. The actual picture did not matter to the agent. So it was much easier for him to find matching pairs than for me. And this was ultimately related to the way I used Midjourney. Here is an example of a prompt and the final cards I created from the 4 images generated:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

fantasy action scene, bastion style


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

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.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%2F9qk5ac8hlfqs6ybbegls.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F9qk5ac8hlfqs6ybbegls.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you reveal a card, you get to see it for 1 second before it is concealed again. That's not nearly enough time to memorise these complex shapes, especially when they're so similar. To minimise this, I had to use different themes, subjects, and settings when creating the images. Here are some of the examples I ended up using for the game. Note that sometimes I had to regenerate them to make them more distinct to the ones I already had:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

fantasy magician, bastion style 
fantasy battle horse, bastion style
fantasy rpg hero group fighting monsters, bastion style
fantasy well, bastion style
fantasy crystal, bastion style
fantasy waterfall, bastion style --no building people house castle
fantasy ogre, bastion style


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

&lt;/div&gt;

&lt;p&gt;There were many more requests to Midjourney to count against my quota. So I tried to reuse as much as possible of the 4 images I generated. Especially more complex scenes like "fantasy rpg hero group fighting monsters" produced a lot of cards because they had several different distinct scenes within one image. Here are all the tiles that made it into the game:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fed2mzw6f1shqpvthuksu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fed2mzw6f1shqpvthuksu.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Remaining assets and the final game
&lt;/h3&gt;

&lt;p&gt;The remaining assets were the background and a button graphic. The background was quite simple&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

unobstrusive fantasy game background, only nature, bastion style -- no building people monster hero


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

&lt;/div&gt;

&lt;p&gt;which was then blurred. It was important to include the &lt;code&gt;--no&lt;/code&gt; directive to the prompt, as I didn`t want to draw too much attention away from the actual memory tiles.&lt;/p&gt;

&lt;p&gt;For the button graphic, I simply created a few mockups and then removed the background using another AI tool. This was harder than I thought it would be, and I wasn't as happy with it as I would have liked. So the buttons could still be a little tricky. Here's what the finished game looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fx6ez25u2y6cpxzamk6w6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fx6ez25u2y6cpxzamk6w6.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want, you can play it on &lt;a href="https://dasheck.itch.io/fantasy-matching-card-game" rel="noopener noreferrer"&gt;itch.io&lt;/a&gt;. Keep in mind that this is just an experiment to see if Midjourney is suitable as a tool for creating game assets. So don't expect too much fun while playing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I had really high expectations before running this experiment, and most of them were met. I went for an art style that is hard for many to pull off, let alone me. I'm happy with the results (except for the button graphic). Not only that, I was able to do it all in one sitting and used 6.87% of my monthly quota (while still experimenting). All in all, I consider this a success and I will most definitely use it in future games.&lt;/p&gt;

&lt;p&gt;Counterintuitively it is harder for Midjourney to create basic shapes like buttons (or even text). As I've didn't go into that direction it is hard for me to tell, whether Midjourney is able to help here. This could be part of another experiment.&lt;/p&gt;

&lt;p&gt;Also keep in mind that I'm not an expert at creating prompts for Midjourney. So it would be easier if I knew how to word this properly. If you have feedback on this, please let me know.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feedback
&lt;/h2&gt;

&lt;p&gt;I would love to hear your experience with Midjourney. Have you used it in the past. And if so, would you like to share your results (e.g. images, assets, prompts, insights). If not, do you plan to use it?&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>ai</category>
      <category>midjourney</category>
    </item>
    <item>
      <title>How to create series on dev.to?</title>
      <dc:creator>Stefan Neidig</dc:creator>
      <pubDate>Sun, 27 Aug 2023 11:43:17 +0000</pubDate>
      <link>https://dev.to/dasheck0/how-to-create-series-on-devto-1cln</link>
      <guid>https://dev.to/dasheck0/how-to-create-series-on-devto-1cln</guid>
      <description>&lt;p&gt;Wanted to create a series about github actions. I added the frontmatter meta like so&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
title: Github Actions introduction
tags: ...
series: Github Actions
---
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also added a second draft article, that is not visible yet. However, there is no series shown in the article that I expected (see screenshot of example). Is there something I am missing? Thanks for any help :) &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h_mj1-6v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/02poidqthi1i1u2tt9ri.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h_mj1-6v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/02poidqthi1i1u2tt9ri.png" alt="Image description" width="690" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>question</category>
      <category>help</category>
      <category>answer</category>
      <category>qa</category>
    </item>
    <item>
      <title>Introduction to Github Actions</title>
      <dc:creator>Stefan Neidig</dc:creator>
      <pubDate>Sat, 19 Aug 2023 22:44:08 +0000</pubDate>
      <link>https://dev.to/dasheck0/github-actions-4l94</link>
      <guid>https://dev.to/dasheck0/github-actions-4l94</guid>
      <description>&lt;p&gt;This is the start of a series of articles about Github actions. Mainly because I feel I have something to share, but also because I want to make a habit of writing and sharing. With that in mind, I appreciate any feedback to become a better writer. So thank you in advance :)&lt;/p&gt;

&lt;p&gt;Before we begin, I'd like to briefly outline what topics I will be covering to give you an idea of what to expect. I will&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;give a brief introduction about github actions&lt;/li&gt;
&lt;li&gt;set up a workflow with more detailed information&lt;/li&gt;
&lt;li&gt;create an action that you can run manually&lt;/li&gt;
&lt;li&gt;show you how you can use them in a monorepo setup&lt;/li&gt;
&lt;li&gt;show you how you can use reusable actions&lt;/li&gt;
&lt;li&gt;give some tips I wish I had known when I first started creating Github actions&lt;/li&gt;
&lt;li&gt;share some of the actions I have created over the last few months&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I will not look into how to create your own github action that you can release on the marketplace. However, there is a &lt;a href="https://dev.to/balastrong/create-a-custom-github-action-in-typescript-21ad"&gt;great tutorial here on dev.to for that&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As you may have guessed, this will be a multi-part article and I will do my best to break it down into easily digestible reads. Again, your feedback will help a lot to make the next part better than the current one. So thanks again :)&lt;/p&gt;




&lt;h1&gt;
  
  
  What are Github actions
&lt;/h1&gt;

&lt;p&gt;Github actions are a way to automate things provided by Github (as the name suggests). It is integrated into your repository and can be triggered by certain events, which we will cover later in this tutorial. After a trigger, we can perform various steps and do things that we normally do manually.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why do we need them?
&lt;/h1&gt;

&lt;p&gt;There are certain steps that are necessary when maintaining a codebase or building software. Some examples are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Running a linter to enforce a certain code style or some rules that relate to best practises&lt;/li&gt;
&lt;li&gt;The actual building of the software (e.g., a mobile app, a Docker image, ...)&lt;/li&gt;
&lt;li&gt;Running tests to make sure everything works as intended&lt;/li&gt;
&lt;li&gt;Running various checks to make sure your codebase is healthy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This list is not exhaustive and you probably have some ideas about what you would do in your case. Running these things automatically on a given trigger is really helpful because it obviously saves time. But it also ensures that they actually get executed. If you are working in a larger team, you can not rely on developers to perform these tasks by hand, as it can be easy to forget. Perhaps some of the tasks you want to run are difficult to do or require prior setup. With Github Actions, you can describe them once and then run them as many times as you want until you reach your quota.&lt;/p&gt;

&lt;h1&gt;
  
  
  How do we get started?
&lt;/h1&gt;

&lt;p&gt;We start by creating what we call a workflow as a yaml file under &lt;code&gt;.github/workflows&lt;/code&gt; in the root of your repository.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.github/
 workflows/
 lint.yml src/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the yaml file, we need to define the name and jobs we want to run. Let's start with an example of linting a codebase (i.e. executing an npm command).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Run lint

on:
  push:
    branches:
      - master
      - develop
      - feature/*
      - hotfix/*
      - release/*

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - name: Check out codebase
        uses: actions/checkout@v3
        with:
          fetch-depth: 0
      - name: Setup node
        uses: actions/setup-node@v3
      - name: Install depedencies
        run: npm ci # --legacy-peer-deps
      - name: Run lint command
        run: npm run lint
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let us take a closer look. First, we define a trigger. This specifies what event must occur for our actions to be executed. Here we have defined a simple push trigger and specified some branches. If a push event occurs in one of these branches, all jobs will be executed.&lt;/p&gt;

&lt;p&gt;We can define several jobs. Each of them will be executed independently. We can specify on which machine the jobs should be executed. Here we have chosen &lt;code&gt;ubuntu-latest&lt;/code&gt;. Within this job we have defined a series of steps that run in sequence. The name parameter specifies the name, so you can easily see the logs and know what is going on. Within the job, we specify what needs to be done. This is done in two ways.&lt;/p&gt;

&lt;p&gt;The first way is to reuse an existing action from the Github action marketplace. These are actions that have been created by third parties. Usually we can specify parameters to customise the actions to our needs. You just need to specify the &lt;code&gt;uses&lt;/code&gt; parameter in your workflow, followed by the action name. Check the &lt;a href="https://github.com/marketplace?type=actions"&gt;marketplace&lt;/a&gt; to see what actions are available, and read the action's readme file to find out what it does and what parameters you can use. We used &lt;code&gt;actions/checkout&lt;/code&gt; and &lt;code&gt;actions/setup-node&lt;/code&gt; to check out our source code and create a node environment. We specified version 3 for both actions, which is the latest at the time of writing. You must always specify a version when using Marketplace actions.&lt;/p&gt;

&lt;p&gt;The second way is to describe the tasks themselves, using the &lt;code&gt;run&lt;/code&gt; parameter followed by the actual commands. We use it for installing dependencies and running an npm command. You can also specify a set of commands as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
steps:
  - name: Run multiple commands
    run: |
      npm run lint
      npm run test
      echo "We are done here"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are more details on how to invoke these commands and configure your workflows, as well as best practises that I would like to show you. We will do this in a later part of this series.&lt;/p&gt;

&lt;p&gt;I hope this brief introduction will help you understand the benefits of Github actions and the basic concepts. See you in the next article where we will discuss some details about configuring your workflows.&lt;/p&gt;




&lt;p&gt;I have been a developer all my life and currently CTO at NanoGiants. My work involves not only programming tasks, but also strategy, tooling, and leadership. If you have an interest in a particular topic, let me know. I will consider writing about it if you find it useful :) Thank you a lot!&lt;/p&gt;

</description>
      <category>githubactions</category>
      <category>github</category>
      <category>softwaredevelopment</category>
      <category>softwarengineering</category>
    </item>
    <item>
      <title>Mini Monster Quest - Picking things up again</title>
      <dc:creator>Stefan Neidig</dc:creator>
      <pubDate>Sun, 09 Apr 2023 10:29:53 +0000</pubDate>
      <link>https://dev.to/dasheck0/mini-monster-quest-picking-things-up-again-4i6h</link>
      <guid>https://dev.to/dasheck0/mini-monster-quest-picking-things-up-again-4i6h</guid>
      <description>&lt;p&gt;This is a post about a game that I have been working on. Mini monster quest is a spherical tower defense game. Your main goal is to protect your crystal and fend off waves of monsters coming after you. You have a blade that spins around your crystal, which you can level up and change into a different form. Can you beat it? Find out at &lt;a href="https://dasheck.itch.io/mini-monster-quest"&gt;https://dasheck.itch.io/mini-monster-quest&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;I dug this project back up after a while, and I immediately realized why I abandoned it in the first place. This is an update on how I overcame motivation issues and lack of inspiration, and what the current state of the project is. This is by no means a "how to overcome lack of motivation". This is just me rambling and trying to get it out of my system. So please do not expect a well-crafted punchline :)&lt;/p&gt;

&lt;p&gt;Let us start with a not so surprising, but still demotivating fact: I can't draw for the life of me. All of you who have already developed a game know what I am getting at. The look of a game is in some way proportional to the motivation you have to work on it. The better it looks, the more desire you have to keep working on it. At least that's been my experience. Due to my lack of drawing skills, I always start with a big malus. So I rely on third party assets or procedurally generated content &lt;a href="https://dev.to/dasheck0/shifting-from-nfts-to-something-more-meaningful-3055"&gt;another project of mine&lt;/a&gt;. But in the end, it does not solve the problem for various reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Third-party assets do not cover everything, so you have to stitch together assets from different sources that do not ultimately fit together&lt;/li&gt;
&lt;li&gt;It's hard to find assets that match the style you want to use&lt;/li&gt;
&lt;li&gt;You tend to be more attached to your own work than to the work of others&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So what brought me back to this project after almost two years? And how do I get my assets today? Let us discuss the first question:&lt;/p&gt;

&lt;h3&gt;
  
  
  What brought me back to this project after almost two years?
&lt;/h3&gt;

&lt;p&gt;Actually, a variety of reasons. First of all, without knowing it, I have built accountability partners. I have friends, family, and colleagues with whom I often talk about my projects. Every time we meet (especially colleagues), they show me my progress on their projects and I show them mine (if any). And I regularly wished I could show more instead of just talking about what I could do. Having accountability partners is a great thing to keep the ball rolling, even when the pace is slow.&lt;/p&gt;

&lt;p&gt;Second, I have a dream of building a passive income stream. While I am not sure games are the best choice here, it's been a long-time hobby of mine. So it feels natural to do it. Even if the passive income part fails, I have done something fun along the way.&lt;/p&gt;

&lt;p&gt;And finally, I like the original game idea (which I saw somewhere). However, I do not see this particular type of game anywhere. There is undeniably great potential for tower defense games. But I always see the same structure in these games, at least for the mobile platform. My goal is to bring new ideas to this field, as I like this type of games myself.&lt;/p&gt;

&lt;h3&gt;
  
  
  And how do I come up with my assets these days?
&lt;/h3&gt;

&lt;p&gt;I still try to find suitable third-party assets from other artists, especially ones that are free to use. But as the game progresses, it gets harder and harder to find assets that really fit the style and do not feel weird. I am also considering buying some, since the market for free assets is limited. However, that's not something that would work with what I am planning with Mini Monster Quest.&lt;/p&gt;

&lt;p&gt;With the advent of AI, I tried Midjourney and found something that works for the foreseeable future. Midjourney does not generate vector graphics, but it gives some inspiration and does the creative part (a big problem for me). I then just replicate the generated image as a vector graphic in Figma. I have done this twice and it works quite well, even if it is time consuming.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the future of this game?
&lt;/h3&gt;

&lt;p&gt;I will not present a complete roadmap. But I want to give some ideas of what I plan to do with the game. Especially for upcoming releases in the next months (this is about building responsibility).&lt;/p&gt;

&lt;p&gt;My main goal is to build a tool to help with balancing. I tried Machiniations.io but failed to build the game loop properly to predict balance in higher levels and waves. So I am in the process of building something that works like Machinations and gives me insight into multiple runs with different parameters of the game economy. I hope to end up with something that is fun to play (not just once) and provides an incentive to "grind".&lt;/p&gt;

&lt;p&gt;The next big task is to increase the replay value and provide something to work on besides just getting through the levels. One idea is to allow players to collect drops and make their own radar templates that they can use to beat certain levels. Each of these radar templates has unique shapes and properties (damage, speed, ...).&lt;/p&gt;

&lt;p&gt;That's if for today. Thank you to everyone who has supported me so far!&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>minimonsterquest</category>
      <category>devjournal</category>
      <category>programming</category>
    </item>
    <item>
      <title>Shifting from NFTs to something (more) meaningful</title>
      <dc:creator>Stefan Neidig</dc:creator>
      <pubDate>Mon, 06 Jun 2022 17:48:03 +0000</pubDate>
      <link>https://dev.to/dasheck0/shifting-from-nfts-to-something-more-meaningful-3055</link>
      <guid>https://dev.to/dasheck0/shifting-from-nfts-to-something-more-meaningful-3055</guid>
      <description>&lt;p&gt;Inb4: This is not a post against NFTs (neither the actual concept nor how it is currently executed). I actually love the idea of NFTs, specifically ERC-721, and the things you can do with them other than create and exploit a secondary market. In fact, that's exactly what drove me away.&lt;/p&gt;

&lt;p&gt;We have all seen the hype and the decline or consolidation over the last few months. We have been inundated with collections that had little to no purpose and whose only purpose was to make some money. Many have failed, and so have we. Again, this is not a critique of NFTs, nor is it a post mortem or an explanation of why our collection failed. This is a post about why we started this collection to begin with and why we see more value in not turning it into an NFT collection.&lt;/p&gt;

&lt;p&gt;The idea behind Loot from a Chest was to make high quality gaming assets available to everyone. Perhaps we need to go back for a moment to understand why. I started as a game programmer when I was 15 years old. I learned to program by developing games using C++ and OpenGL (those were the days!). I am pretty good at programming, designing architectures, and bringing it to the cloud/server, but I can not draw a stick figure even if my life depended on it. So developing a polished game was out of my reach, aside from working with a designer or buying/using free assets. I always felt limited by that. That changed when I stumbled across procedural content creation. This is a technique where you generate content by understanding the structure of the content and building it in a mathematical/algorithmic way. Here is an example for Loot from a Chest.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--W5aR5NG1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/td29u397lqu754bi2jw2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--W5aR5NG1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/td29u397lqu754bi2jw2.png" alt="Sword breakdown" width="800" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A sword is a composite asset consisting of a blade, guard, grip, ornament, and pommel. Each of these components is made up of sub-components that one can be described mathematically and then drawn, without requiring any skills (other than programming, which suits me fine). If you are interested in a more detailed example, let me know and I'll write it up. With this approach, I was able to create high quality assets as long as I understood the structure of those assets well enough. Even better, by writing a flexible algorithm, you can parameterize certain aspects and create a wide variety of assets with the same code base. For someone who can not draw and has always dreamed of creating a polished game, that's a huge accomplishment! Here are some examples of the current Loot from a Chest generator:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2_E1IgW0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qd1pddgkv897uwqcga3d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2_E1IgW0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qd1pddgkv897uwqcga3d.png" alt="Example Assets" width="800" height="233"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that such things as colors, type of the blade, length and height of components are parameters that can be easily changed to create unique weapons. We discovered the lance with the blue blade by accident when I set the height of the grip to a value that was much too high.&lt;/p&gt;

&lt;p&gt;Getting back to the topic at hand: We tried to understand the content we wanted to generate, and developed a flexible algorithm to generate a unique variety of these assets - and then turn them into an NFT collection, which is still available on OpenSea. But the mere fact that these assets are available as NFTs has not added any value to the original idea - to make high-quality assets available to everyone. So what do you do in such cases - you make it work. After a while, it did not feel right and gradually the motivation to work on this project decreased. Also, it goes against the idea of turning these assets into NFTs, as avatar collections (this is just a variation of that) are about uniqueness and perceived limitation, while we wanted to enable everyone to have this.&lt;/p&gt;

&lt;p&gt;And that brings us to the end and the current state of Loot from a Chest. If NFTs are not the answer, what is? There are two answers to that (at least to our current knowledge).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Asset packs &lt;/li&gt;
&lt;li&gt;DIY Editor&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Asset packs are a common thing in game development. Normally I am the consumer, but with a procedural content generator in hand, I am now a producer. We created a simple asset pack with little effort and uploaded it to &lt;a href="https://lootfromachest.itch.io/loot-from-a-chest-sword-asset-pack"&gt;itch.io&lt;/a&gt; and &lt;a href="https://assetstore.unity.com/packages/2d/gui/loot-from-a-chest-sword-asset-pack-217511"&gt;Unity Asset Store&lt;/a&gt; (no advertising intended). Although they cost money, one could argue that they should be free, or at least cheaper, since they are easy to create. I'd like to take this a step further. Why not provide the algorithm and generate the assets yourself (with all available notches /parameters)? This is actually what we are working on at the moment. To summarize this, I would like to show you some screenshots of the current Loot from a Chest Asset Studio. I would really appreciate feedback (on the idea, on the design, on the features you would like to see, whatever you would like feedbacking ). &lt;/p&gt;

&lt;p&gt;Thanks for reading and sharing (either your ideas or this article to spread the idea)!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project Dashboard&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TLgz2zmK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q44x4mkfzou2fdsz2m1f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TLgz2zmK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q44x4mkfzou2fdsz2m1f.png" alt="Project Dashboard" width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project Detail&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uKQEWGmB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3hrfskmz5vjtywsc7q9h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uKQEWGmB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3hrfskmz5vjtywsc7q9h.png" alt="Project Detail" width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Editor&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8shV9IGL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/30ehl52g46q51if9rr6u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8shV9IGL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/30ehl52g46q51if9rr6u.png" alt="Editor" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project Settings&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ac5kUJjY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eem5hg513jxo0fvg14vw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ac5kUJjY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eem5hg513jxo0fvg14vw.png" alt="Project Settings" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Distribution settings, for the creation of certain types of assets&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SDo-U0vR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gzn4nkveedcubcv7jqcd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SDo-U0vR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gzn4nkveedcubcv7jqcd.png" alt="Distribution Settings" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Export as PNGs of any size and SVGs&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qG4bB4ov--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6q5bxdg308vwe36p5eby.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qG4bB4ov--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6q5bxdg308vwe36p5eby.png" alt="Export" width="800" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nft</category>
      <category>procedural</category>
      <category>assets</category>
      <category>programming</category>
    </item>
    <item>
      <title>The cost of running a smart contract</title>
      <dc:creator>Stefan Neidig</dc:creator>
      <pubDate>Tue, 08 Feb 2022 19:32:21 +0000</pubDate>
      <link>https://dev.to/dasheck0/the-cost-of-running-a-smart-contract-3oo5</link>
      <guid>https://dev.to/dasheck0/the-cost-of-running-a-smart-contract-3oo5</guid>
      <description>&lt;p&gt;For &lt;a href="https://lootfromachest.com"&gt;Loot from a Chest&lt;/a&gt;, we decided to look into creating a custom smart contract because we need some functionality that is not provided by existing smart contracts. Writing and running a smart contract was a black box for us. None of us had done this before. There were open questions that we wanted answers to quickly&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How does it work exactly?&lt;/li&gt;
&lt;li&gt;Who are the parties involved and how do they interact with each other?&lt;/li&gt;
&lt;li&gt;What does it cost to run a smart contract?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Questions 1 and 2 will be covered in another article soon. In this article, let us take a look at the costs associated with running a smart contract. &lt;/p&gt;

&lt;h1&gt;
  
  
  What is a smart contract?
&lt;/h1&gt;

&lt;p&gt;A smart contract is a program that runs entirely on a blockchain. The data involved is also stored on the blockchain. With this program, you can do anything you want. Conduct voting, run decentralized finances, and of course, run a marketplace selling goods like NFTs. There are many guides that show you how to write these programs. Few of them tell you what happens afterwards when you want to deploy them on the blockchain.&lt;/p&gt;

&lt;p&gt;Let's take a look at the Ethereum blockchain and try to keep things simple. The basic unit of Ethereum is called a block and it is a stack of transactions with a hash of the previous block.  So these blocks are linked together like a chain (hence the name) and form the basis of the fraud prevention we love about blockchain technology. To perform such a transaction, we need to expend computational energy. We call this cost &lt;code&gt;gas&lt;/code&gt;. The &lt;code&gt;gas price&lt;/code&gt; is more or less determined by  supply and demand. The higher the demand, the higher the gas pric. In fact, we often see high amplitudes in a short time. If we want to determine the cost of creating a smart contract, depends on how much &lt;code&gt;gas&lt;/code&gt; we have to spend to execute the transactions that are involved as well as the &lt;code&gt;gas price&lt;/code&gt; at the time when they happen. &lt;/p&gt;

&lt;p&gt;Fortunately, Ethereum is open source and we can read all about it in the &lt;a href="https://ethereum.github.io/yellowpaper/paper.pdf"&gt;Ethereum Yellow Paper&lt;/a&gt;. On page 27, we can see the amount of &lt;code&gt;gas&lt;/code&gt; needed for certain operations. The following operations are required to create a smart contract.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;G_txcreate = 32000 &lt;code&gt;gas&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;G_transaction = 21000 &lt;code&gt;gas&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So at least 53000 &lt;code&gt;gas&lt;/code&gt; to create a smart contract. Yes, this is the minimum amount of gas. You also have to pay &lt;code&gt;gas&lt;/code&gt; for every byte of data your program requires. Ethereum uses what are called slots of 256-bit size for this purpose. To store data in a slot, 20000 &lt;code&gt;gas&lt;/code&gt; is required. This results in 640.000 &lt;code&gt;gas&lt;/code&gt; for 1kB of data (256 bits = 32 bytes; 1kB = 1024 bytes = 32 * 32 bytes). There are several ways to determine the size of your smart contract. &lt;/p&gt;

&lt;h1&gt;
  
  
  Determining the size of the contract
&lt;/h1&gt;

&lt;p&gt;There are many ways to calculate the size of your smart contract. We create one using &lt;a href="https://www.npmjs.com/package/hardhat"&gt;hardhat&lt;/a&gt;. This tool has a plugin called &lt;a href="https://www.npmjs.com/package/hardhat-contract-sizer"&gt;hardhat-contract-sizer&lt;/a&gt;. This outputs the size of the contract in kilobytes. For Loot from a Chest this was 21.045kB. Another method (i.e. measuring the byte size of the deployed contract binaries) gave 23.13kB. So there might be some fuzziness. &lt;/p&gt;

&lt;h1&gt;
  
  
  Putting it all together
&lt;/h1&gt;

&lt;p&gt;Finally, to calculate the cost of creating the smart contract we need to determine the &lt;code&gt;gas price&lt;/code&gt; and the Ether price. The Ether price tells us how many dollars we need to spend to buy the Ether. For this, there are many trackers that determine these both prices in real time and historically. At the time of writing the &lt;code&gt;gas price&lt;/code&gt; was 2822700013 &lt;code&gt;wei&lt;/code&gt; (or 0.000000002822700013 &lt;code&gt;ETH&lt;/code&gt;) and the Ether price was $3018.38 per Ether. Now we can do the math:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const gas = 32000 + 21000 + 21.045 * 640000;
const gasPrice = 0.000000002822700013;
const etherPrice = 3018.38;

const price = gas * gasPrice * etherPrice;
console.log(price) // -&amp;gt; 115.20548267230792
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To deploy our very basic smart contract, we have to pay $115.21. For a more sophisticated contract that we have in mind for Loot from a Chest, we will probably have to spend much more. I hope this helps you get a better sense of the costs involved in creating a smart contract. We have not talked about the costs that will be incurred if you do other transactions (such as buying your NFTs). The math is the same. You just need to figure out what the transactions are involved and what data and operations make up those transactions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One last tipp&lt;/strong&gt;: In the Ethereum RPC, there is a method called &lt;a href="https://www.quicknode.com/docs/ethereum/eth_estimateGas"&gt;eth_estimateGas&lt;/a&gt;. You can write a program that uses this function and embeds a gas price and Ether price tracker to determine the cost in advance. This is basically an automated version of what we explored in this article.&lt;/p&gt;

&lt;h1&gt;
  
  
  Final thoughts
&lt;/h1&gt;

&lt;p&gt;Running a smart contract can be an expensive thing to do. There are existing ones out there that you could look into. Marketplaces like Open Sea or Rarible are based on very sophisticated smart contracts with advanced features like royalties. If you do not need additional features to run your project, you should use them. If you do, you should look at side chains like Polygon or alternatives like Solana. They run on less gas and are therefore cheaper to work with. But keep in mind that they are not as mature compared to the Ethereum Blockchain. Also, most of the NFT community is on Ethereum, which means you have a smaller audience to sell to or have to convert to your chosen blockchain!&lt;/p&gt;

&lt;p&gt;If you have not checked out "Loot from a Chest" yet, you really should :) It is a collection of 10000 procedurally generated swords in a fantasy world. Join our &lt;a href="https://discord.gg/aS3vQcQQUC"&gt;Discord&lt;/a&gt; and visit our &lt;a href="https://lootfromachest.com"&gt;Website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Feel free to leave comments. I hope this helps you in your digital endeavour. If not, drop me a line and I'll be happy to help :)&lt;/em&gt;&lt;/p&gt;

</description>
      <category>nft</category>
      <category>crypto</category>
      <category>smartcontract</category>
    </item>
    <item>
      <title>Should you name your nfts?</title>
      <dc:creator>Stefan Neidig</dc:creator>
      <pubDate>Thu, 03 Feb 2022 20:32:20 +0000</pubDate>
      <link>https://dev.to/dasheck0/should-you-name-your-nfts-40hj</link>
      <guid>https://dev.to/dasheck0/should-you-name-your-nfts-40hj</guid>
      <description>&lt;p&gt;This question was asked the other day in the &lt;a href="https://discord.gg/uYaCrUsMNM"&gt;Skull in Love Discord&lt;/a&gt;. My first thought was "sure, why not?". Then as I thought about it further, I realised that it is quite a bit. In this article I would like to expand on that thought and show an approach how to name even 10,000 NFT items.&lt;/p&gt;

&lt;p&gt;If you look at various collections, you will notice that most of them do not name their NFT items. There is an increasing counter that serves as the name (e.g. Cryptopunk #4211). While this is useful, it does not really encourage identification with the items or the collection. This is not necessarily a problem, as it is often  not intended. However, giving NFT items a name can also have advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It creates an identification with the NFT item. This is especially useful if you want to create a collection that has meaning and not just be flipped.&lt;/li&gt;
&lt;li&gt;It serves as an additional layer for rarity or traits. There may be names that are rarer, contain titles, or have other collectible characteristics.&lt;/li&gt;
&lt;li&gt;Names can tell a story that strengthens the overall value of the collection and the underlying idea.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The challenge
&lt;/h2&gt;

&lt;p&gt;So why do so few artists bother to name their NFT items? In my opinion, the most obvious reason is the added layer of complexity. If you want to create a collection of 10,000 items, you also have to come up with 10,000 names. This is no easy task. Here I would like to suggest a way out of this complexity - something called grammar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Grammars
&lt;/h2&gt;

&lt;p&gt;Grammars are a concept from theoretical computer science and describe how a language is structured. It defines literals, i.e. the smallest building blocks of a language (e.g. letters, numbers, syllables) and gives rules on how to combine them to form words and sentences. This logic can be applied to our given problem. The resulting grammar describes a language whose words and phrases form the names for our NFT items. To illustrate this, let me show an example from our NFT collection, &lt;a href="https://lootfromachest.com"&gt;"Loot from a Chest"&lt;/a&gt;. Loot from a Chest is a collection of 10,000 procedurally generated swords in a fantasy world called Aeliv. &lt;/p&gt;

&lt;p&gt;The first thing you should think about is the logic of the language you want to create. Which sentences should end up being formally correct and which should not? In our case, we want to give names to the swords. Formally correct names are, for example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Longsword&lt;/li&gt;
&lt;li&gt;Shiny Sword&lt;/li&gt;
&lt;li&gt;Sword of Brikandal&lt;/li&gt;
&lt;li&gt;Thorma's heavy Sword&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are many more possibilities, but you get the idea. From these names you can deduce some logic how to build them&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;sword&lt;/li&gt;
&lt;li&gt; Sword&lt;/li&gt;
&lt;li&gt;Sword of &lt;/li&gt;
&lt;li&gt;'s  Sword&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To simplify things, let us assume that we only have these 4 rules. Now we just need literals and we can start creating names. Here is an example of a list of literals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;adjective&amp;gt;&lt;/code&gt;: [heavy, golden, long, short, ...]&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;name&amp;gt;&lt;/code&gt;: [Brikandal, Thorma, Shrivel, Pouch, ...]&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This already gives a nice list of unique names:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shortsword&lt;/li&gt;
&lt;li&gt;Shrivel's golden Sword&lt;/li&gt;
&lt;li&gt;Long sword&lt;/li&gt;
&lt;li&gt;Sword of Pouch&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In fact, with these 4 rules and 8 literals, we can create quite a few unique names. Note that while they are unique, they may not be perceived as unique, which is a common problem with procedurally generated content. We will deal with this in a later section of this article. First, let us see how we implement our grammar. We will use a tool called &lt;a href="https://tracery.io"&gt;tracery&lt;/a&gt; from &lt;a href="https://twitter.com/GalaxyKate"&gt;galaxykate&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing a grammar
&lt;/h2&gt;

&lt;p&gt;Let's create a new nodejs project. Go to your terminal and type in&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir naming-nfts
cd naming-nfts
npm i -y
npm i tracery-grammar
touch index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your index.js, add this boilerplate code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const tracery = require('tracery-grammar');

const grammar = tracery.createGrammar({
  // ...
});

grammar.addModifiers(tracery.baseEngModifiers); 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need to import the tracery module. The grammar variable contains, well, our grammar. And we add modifiers to make our lives easier. This allows us to capitalise and pluralise words. Now we need to create our literals and rules. In tracery, these concepts are mixed. Let's apply our rules from Loot from a Chest to tracery.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const adjectives = ['heavy', 'golden', 'long', 'short'];
const names = ['Brikandal', 'Thorma', 'Shrivel', 'Pouch'];
const rules = ['#adjective#sword', '#adjective# Sword', 'Sword of #name#', '#name#'s #adjective# Sword'];

const grammar = tracery.createGrammar({
  adjectives,
  names,
  rules
});

grammar.addModifiers(tracery.baseEngModifiers); 
console.log(grammar.flatten('#rules#')); // --&amp;gt; "Heavy Sword"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every time you call 'flatten', tracery traces the grammar (hence the name). We start with the #rules# symbol. This can have one of 4 possible states. Starting from this state, we use various other rules (e.g. #adjective# and #name#) to fill in actual literals and produce a name. However, the names are not unique. First, we have too few literals to cover even a fraction of 10,000 unique names. And second, we have too few rules for the names to be perceived as unique. Let's deal with the literals first, since this is easy to fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Improving the grammar
&lt;/h2&gt;

&lt;p&gt;Basically, you need to find more possible states for your literal classes (i.e. adjectives and names). There are many random word generators you can use to accomplish this. As an example, let me show you unique-names-generator (NPM).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { adjectives, names } = require('unique-names-generator');

const rules = ['#adjective#sword', '#adjective# Sword', 'Sword of #name#', '#name#'s #adjective# Sword'];

const grammar = tracery.createGrammar({
  adjectives,
  names,
  rules
});

grammar.addModifiers(tracery.baseEngModifiers); 
console.log(grammar.flatten('#rules#')); // --&amp;gt; "Winona's big Sword"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of creating our own adjectives and names, we use the dictionaries provided by unique-names-generator. This package is great because it is configurable, extensible, and provides a large number of combinations out of the box. But there are many other packages you can use. Choose one that works best for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding diversity
&lt;/h2&gt;

&lt;p&gt;Now let's tackle the problem of items not perceived as unique. This is something that can not be easily solved with a package. Perception is hard to measure and therefore hard to improve. However, we know that diversity affects uniqueness and therefore how unique your names are perceived. So what you want to do is increase diversity. You can do this by adding more rules or changing rules that are too similar. In the example given, we find that &lt;code&gt;&amp;lt;adjective&amp;gt;sword&lt;/code&gt; and &lt;code&gt;&amp;lt;adjective&amp;gt; Sword&lt;/code&gt; are too similar for people to perceive them as unique, even though they are unique. Often you need to get creative and try a few things. Keep rules that work and update or remove rules that do not. Eventually you will find a grammar that gives you a variety of names for your NFT items. Here is an example of 10 random names from our grammar that names swords for Loot from a Chest:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Combat Gladius&lt;/li&gt;
&lt;li&gt;Noble Dagger of Grotdag&lt;/li&gt;
&lt;li&gt;Silver Dagger&lt;/li&gt;
&lt;li&gt;Blade of Rudbrag&lt;/li&gt;
&lt;li&gt;Dagger of the Night&lt;/li&gt;
&lt;li&gt;Breaking Blade&lt;/li&gt;
&lt;li&gt;Mighty Spear&lt;/li&gt;
&lt;li&gt;Steelaxe&lt;/li&gt;
&lt;li&gt;Gladius&lt;/li&gt;
&lt;li&gt;Heavy Sword of Nimildan&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Naming NFT items can be a fun activity and will likely help create a connection between your audience and your collection. Naming things is one of the most difficult problems, but can be tackled with a concept called grammar and tools like tracery and random name generators (there are many of them). You can even create complex descriptions and stories using this approach. It can be a challenge to make them seem unique, so remember to diversify your rules that make up the grammar, and you are good to go. I hope this helps you get started or even consider naming your items other than #4211, and if so, please let me know how you did!&lt;/p&gt;

&lt;p&gt;If you have not checked out "Loot from a Chest" yet, you really should :) Join our Discord at &lt;a href="https://discord.gg/aS3vQcQQUC"&gt;https://discord.gg/aS3vQcQQUC&lt;/a&gt; or visit our website at &lt;a href="https://lootfromachest.com"&gt;https://lootfromachest.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZoEma81O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l9739ed27uhohde399m4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZoEma81O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l9739ed27uhohde399m4.png" alt="Map of Aeliv" width="800" height="571"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Feel free to leave comments. I hope this helps you in your digital endeavour. If not, drop me a line and I'll be happy to help :)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DISCLAIMER&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;Not naming items is no dealbreaker. There are many successful NFT projects out there that do not name their items. This article argues that naming might be strategy to further increase engagement and shows how to deal with the complex task of naming 10,000+ items, so that they are still perceived as unique.&lt;/p&gt;

</description>
      <category>nft</category>
      <category>procedural</category>
      <category>content</category>
    </item>
    <item>
      <title>An approach to automate the minting and selling of NFTs on rarible</title>
      <dc:creator>Stefan Neidig</dc:creator>
      <pubDate>Sat, 15 Jan 2022 20:17:17 +0000</pubDate>
      <link>https://dev.to/dasheck0/an-approach-to-automate-the-minting-and-selling-of-nfts-on-rarible-36kd</link>
      <guid>https://dev.to/dasheck0/an-approach-to-automate-the-minting-and-selling-of-nfts-on-rarible-36kd</guid>
      <description>&lt;p&gt;If you create an NFT collection, you will eventually get to the point where you need to upload your collection to a marketplace (e.g. Rarible, OpenSea). And if you are aiming for a 10k collection, you'll realize that you can not do this by hand. There are several approaches to automate this task. In this article I will show you how to approach this task with rarepress.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://rarepress.org/" rel="noopener noreferrer"&gt;Rarepress&lt;/a&gt; is a decentralized NFT operating system. This means that it has all the tools to interact with NFTs (i.e. create, mint, sell, trade), marketplaces and much more. This includes a file store (i.e. ipfs), database, API, and wallet management. You can easily access it via &lt;a href="https://npmjs.com" rel="noopener noreferrer"&gt;npm&lt;/a&gt;. With this, we push an NFT to the ipfs, upload it to Rarible.com (including metadata, traits and royalties) and make it available for sale. Please note that there is an &lt;a href="https://medium.com/rarible-dao/how-to-mint-a-10-000-item-generative-art-nft-collection-with-21-lines-of-javascript-dfa603cc56d5" rel="noopener noreferrer"&gt;amazing article by Skøgard&lt;/a&gt;. However, I have found that there is a lot of trial and error involved here as well. So I would like to show you my approach based on the lessons learned from Skøgard.&lt;/p&gt;

&lt;p&gt;Start a new terminal and add some boilerplate&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir rarepress-test
cd rarepress-test
npm init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add all relevant details and you have a clean project. Run &lt;code&gt;npm i rarepress&lt;/code&gt; to install rarepress. Also, create a file that you want to mint and upload to Rarible. We will have two functions, namely &lt;code&gt;mint&lt;/code&gt; and &lt;code&gt;sell&lt;/code&gt;. But let's start with some boilerplate code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Rarepress = require('rarepress');
const fs = require('fs');

const filePath = '.../path/to/your/nft.png';
const file = fs.readFileSync(filePath);

const rarepress = new Rarepress();
const account = await rarepress.init({ network: 'mainnet', host: 'https://eth.rarenet.app/v1' });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, you should connect your wallet to rarepress. As mentioned earlier, rarepress has a tool called mushie for this. Run &lt;code&gt;npx mushie import&lt;/code&gt; in your terminal. You will need to enter your secret key phrase (e.g. prau pebbly carditis bastardy oeuvre salute) and your decryption password. Now your wallet is connected to rarepress. If you run the script again later, you will have to enter your decryption password again.&lt;/p&gt;

&lt;p&gt;Now for the mint function&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const mint = async (file, name, description, attributes, royalties) =&amp;gt; {
  // add file to file system
  const cid = await rarepress.fs.add(file); 

  // create token
  const token = await rarepress.token.create({
    metadata: {
      name,
      description,
      image: `/ipfs/${cid}`,
      attributes,
    },
    royalties,
  });

  await rarepress.fs.push(cid);
  await rarepress.fs.push(token.uri);

  const response = await rarepress.token.send(token);

  return { cid, token, response };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's already a lot going on. Let's break it down. First, we need to add the file to ipfs (inter planetary file system). This is a decentralized storage like blockchain, but for files. So the file is stored on many computers rather than just one cloud server, making it more durable. When we add this, we get a hash of the file in return. This is a crucial part. Since it is a file hash, you always get the same hash for the same file. You can do great things with this (like check if someone added the same file as you to ipfs).&lt;/p&gt;

&lt;p&gt;After that, we create the actual token. We specify a name, description, the hash of our file in ipfs, attributes, and royalties. For a complete reference of the parameters, see the &lt;a href="https://api.rarepress.org/#/?id=rarepresstokenbuild" rel="noopener noreferrer"&gt;docs&lt;/a&gt;. If you specify the attributes, users can filter and search for your items later on Rarible (or OpenSea) by them. This is important because it allows flippers to see which NFTs are rarer than others and decide whether to invest based on that information. Royalties mean that a portion of future sales goes to the original creator. You can specify multiple royalty recipients with their respective shares. Note that each marketplace may have its own royalty caps (e.g. Rarible is at 50%). A share of 1000 is equal to 10.00%. So if someone sells our NFT for 1ETH, we get 0.1ETH because of the royalty. Finally, we push our file and token to ifps and make a request to Rarible to upload our token. From the &lt;code&gt;response&lt;/code&gt; we can construct a valid rarible.com URL (see later section in this article).&lt;/p&gt;

&lt;p&gt;Note that the second parameter of &lt;code&gt;rarepress.token.send&lt;/code&gt; is optional and can be changed to point to any marketplace you want. If you skip this parameter it points to rarible.com.  &lt;/p&gt;

&lt;p&gt;Now for the sell function&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const sell = async (token) =&amp;gt; {
  const trade = await rarepress.trade.create({
    what: {
      type: 'ERC721',
      id: token.tokenId
    },
    with: {
      type: 'ETH',
      value: 10**18
    }
  });

  const tradeResponse = await rarepress.trade.send(trade);
  return { trade, tradeResponse };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we create a trade with the token we just minted. It takes two parameters. The &lt;code&gt;what&lt;/code&gt; describes what the subject of the trade is (i.e. our token). We need to specify the type, which is always &lt;code&gt;ERC721&lt;/code&gt; for NFTs, and the ID of the token. The &lt;code&gt;with&lt;/code&gt; parameter describes what we want in exchange for our token. The value is specified in the smallest possible unit, so Wei for ETH. We want 1ETH, which is equal to 10^18 Wei (see &lt;a href="https://academy.binance.com/en/glossary/wei" rel="noopener noreferrer"&gt;https://academy.binance.com/en/glossary/wei&lt;/a&gt; for more information). Finally, we need to send the trade and return both the trade and the trade response.&lt;/p&gt;

&lt;p&gt;Now we need to put the parts together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(async () =&amp;gt; {
  const { token, response } = await mint(
    file, // file
    'Frame 208', // name
    'A frame from the game', // description
    [ // attributes
      { trait_type: 'rarity', value: 'unique' },
      { trait_type: 'background', value: 'green' },
      { trait_type: 'mouth', value: 'closed' },
      // ...
    ],
    [ // royalties
      { account, value: 500 }
    ]);

  await sell(token);

  console.log(`Done. You can find your nft at https://rarible.com/token/${response.id}`);
})();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you visit the rarible link you should see something like this:&lt;br&gt;
&lt;a href="https://media.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%2F85wwgpfek72675g9k9ur.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F85wwgpfek72675g9k9ur.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And that's it. Automatically minting an NFT including attributes and royalties, uploading to ipfs and selling the NFT. I have tried to go into as much detail as necessary to understand what's going on. But I barely scratched the surface. In fact, many more things are possible with rarepress. You can even run your own NFT marketplace.&lt;/p&gt;

&lt;p&gt;Feel free to leave comments. I hope this helps you in your digital endeavour. If not, drop me a line and I'll be happy to help :)&lt;/p&gt;

</description>
      <category>nft</category>
      <category>minting</category>
      <category>rarible</category>
      <category>opensea</category>
    </item>
    <item>
      <title>How to check how unique your NFT collection really is</title>
      <dc:creator>Stefan Neidig</dc:creator>
      <pubDate>Wed, 12 Jan 2022 20:58:35 +0000</pubDate>
      <link>https://dev.to/dasheck0/how-to-check-how-unique-your-nft-collection-really-is-15be</link>
      <guid>https://dev.to/dasheck0/how-to-check-how-unique-your-nft-collection-really-is-15be</guid>
      <description>&lt;p&gt;An NFT collection consists of many items, each of which every item is unique, or at least should be unique. If you create what is called an avatar collection, where an item is created by layering, you often end up with a largely unique collection. We can even find a formal model for this.&lt;/p&gt;

&lt;p&gt;Let us say we have &lt;code&gt;x&lt;/code&gt; layers (i.e. background, face, glasses, mouth, nose, ...). Each layer can have &lt;code&gt;y&lt;/code&gt; different states (e.g. yellow background, green background, white background, ...). If the layers have a different number of states, you can use the average number of states, which is a sufficient approximation. We can then find the number of possible combinations by &lt;code&gt;x^y (Math.pow(x, y)&lt;/code&gt;. Suppose we have 5 layers, where each layer can have 10 different states, then we get &lt;code&gt;10^5 = 100000&lt;/code&gt; different combinations. &lt;/p&gt;

&lt;p&gt;So what is the probability that we have a duplicate NFT in 10000 generated objects (i.e. two objects that have the same state in each layer)? Again, we apply mathematics to this problem. Basically, we draw from a pool of &lt;code&gt;x^y&lt;/code&gt; combinations with repetitions. On the first try, we have no chance of getting a duplicate, since we only drew once. After that, we still have &lt;code&gt;x^y&lt;/code&gt; combinations to draw from, but we only consider the combinations that are not identical, so &lt;code&gt;x^y-1&lt;/code&gt;. The next time we draw again from &lt;code&gt;x^y&lt;/code&gt; combinations with &lt;code&gt;x^y-2&lt;/code&gt; valid combinations. I think you can see the pattern now. If we multiply these values, we get the chance of &lt;code&gt;n&lt;/code&gt; drawings, each of which is unique. We need to invert this because we want to get the chance that we have at least one duplicate in our randomly generated NFT collection.&lt;/p&gt;

&lt;p&gt;Let us write a small javascript program where we can enter our numbers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const calculateUniqueness = (count, poolSize) =&amp;gt; {
    let result = poolSize / poolSize;

    for (let i = 1; i &amp;lt; count; i++) {
        result = result * (poolSize - i) / poolSize;
    }

    return 1 - result;
};

console.log("Chance of duplicates", calculateUniqueness(10000, 100000));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output of this program (5 layers, 10 different states each, 10000 generated NFTs) is &lt;strong&gt;1&lt;/strong&gt;. You have a 100% probability of having at least one duplicate. That's scary, considering that 5 layers with 10 different states is quite a lot! But with this formula, we immediately know what to do about it. Let's us put in some numbers.&lt;/p&gt;

&lt;p&gt;Suppose we still have 5 levels now, but with 20 different combinations. The pool size is now 3200000 and the probability of duplicates is 99.99%. This is still not good, even if we now have now 20 different states for our layers, which is a huge amount of assets to create (100 assets)!&lt;/p&gt;

&lt;p&gt;In our second scenario, we now have 8 layers with 10 different states. The pool size is now 100000000 and the probability of duplicates is 39.34%, which is a huge improvement. If we increase the number of layers to 10, the probability of duplicates is 0.49%, which is almost non-existent. Note that we still only have 100 assets to create, which is the same number as in our first scenario. So if you want more uniqueness in your NFT collection, you should increase the number of layers over the number of states each layer can have.&lt;/p&gt;

&lt;p&gt;Since we are dealing with probabilities, you can still get a unique collection even if the probability of duplicates is high. Therefore, you should analyze your collection with property profiles. We will cover this in the next article.&lt;/p&gt;

&lt;p&gt;EDIT: I also created a website for this, where you can plugin your numbers as well. You can access this tool &lt;a href="https://nft-uniqueness-checker.vercel.app/"&gt;here&lt;/a&gt;. Feel free to leave feedback!&lt;/p&gt;

</description>
      <category>nft</category>
      <category>collection</category>
      <category>probability</category>
      <category>unique</category>
    </item>
  </channel>
</rss>
