<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>weblog.masukomi.org - raku</title>
    <subtitle>Autistic, ADHD, Geek. The weblog of Kay Rhodes (masukomi).</subtitle>
    <link rel="self" type="application/atom+xml" href="https://weblog.masukomi.org/tags/raku/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://weblog.masukomi.org"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2022-12-18T00:00:00-05:00</updated>
    <id>https://weblog.masukomi.org/tags/raku/atom.xml</id>
    <entry xml:lang="en">
        <title>Rewriting Hey</title>
        <published>2022-12-18T00:00:00-05:00</published>
        <updated>2022-12-18T00:00:00-05:00</updated>
        
        <author>
          <name>
            masukomi
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://weblog.masukomi.org/2022/12/18/rewriting-hey/"/>
        <id>https://weblog.masukomi.org/2022/12/18/rewriting-hey/</id>
        
        <content type="html" xml:base="https://weblog.masukomi.org/2022/12/18/rewriting-hey/">&lt;div class=&quot;ox-hugo-toc toc&quot;&gt;
&lt;div class=&quot;heading&quot;&gt;Table of Contents&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/18/rewriting-hey/#overview&quot;&gt;Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/18/rewriting-hey/#in-the-beginning&quot;&gt;In the Beginning&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/18/rewriting-hey/#final-totals&quot;&gt;Final Totals&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/18/rewriting-hey/#writing-in-chicken-scheme&quot;&gt;Writing in Chicken Scheme&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/18/rewriting-hey/#delusions-of-sharability&quot;&gt;Delusions of Sharability&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/18/rewriting-hey/#crystal-lang&quot;&gt;Crystal Lang&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/18/rewriting-hey/#final-totals&quot;&gt;Final Totals&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/18/rewriting-hey/#writing-in-crystal&quot;&gt;Writing in Crystal&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/18/rewriting-hey/#fast-forward-dot-dot-dot&quot;&gt;Fast-Forward…&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/18/rewriting-hey/#and-then-raku&quot;&gt;And then Raku&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/18/rewriting-hey/#final-totals&quot;&gt;Final Totals&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/18/rewriting-hey/#writing-in-raku&quot;&gt;Writing in Raku&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/18/rewriting-hey/#reflecting-on-the-rewrites&quot;&gt;Reflecting on the rewrites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/18/rewriting-hey/#if-you-liked-that-dot-dot-dot&quot;&gt;If you liked that…&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/18/rewriting-hey/#p-dot-s-dot-what-about-the-email-app-with-the-same-name&quot;&gt;P.S. What about the email app with the same name?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;!--endtoc--&gt;
&lt;h2 id=&quot;overview&quot;&gt;Overview&lt;/h2&gt;
&lt;p&gt;“Hey!” started as an Interruption Tracker, and now supports Time Tracking too. It has been through 3 iterations: &lt;a rel=&quot;external&quot; href=&quot;https://call-cc.org/&quot;&gt;Chicken Scheme&lt;/a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https://crystal-lang.org/&quot;&gt;Crystal&lt;/a&gt;, and now &lt;a rel=&quot;external&quot; href=&quot;https://raku.org/&quot;&gt;Raku&lt;/a&gt;. This post is a high-level developer’s diary of what I wrote, why I rewrote it, and what I learned along the way.&lt;/p&gt;
&lt;h2 id=&quot;in-the-beginning&quot;&gt;In the Beginning&lt;/h2&gt;
&lt;p&gt;Once upon a time I was a tech lead, team lead, and eventually principal engineer. My days were &lt;em&gt;filled&lt;/em&gt; with interruptions. They were making it impossible to get anything done, and more importantly to me, they were a source of a lot of stress.&lt;/p&gt;
&lt;p&gt;I decided that if I was going to get a handle on the interruptions I needed to understand them. I needed to know &lt;em&gt;when&lt;/em&gt; they were happening so that I could plan focus time. I needed to know &lt;em&gt;who&lt;/em&gt; was interrupting me so that maybe I could talk to them about it. I needed to know &lt;em&gt;why&lt;/em&gt; I was being interrupted so that I could find things I could document better to preempt those interruptions.&lt;/p&gt;
&lt;p&gt;It started out as a little Chicken Scheme script that grew organically. It quickly became a hard-to-maintain hairball of code.&lt;/p&gt;
&lt;p&gt;But it worked, and it was good.&lt;/p&gt;
&lt;h3 id=&quot;final-totals&quot;&gt;Final Totals&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;~1300 lines of Scheme&lt;/li&gt;
&lt;li&gt;~2500 lines of JavaScript (mostly library stuff) to support some fancy “graph it via the web” stuff that never really worked out well.&lt;/li&gt;
&lt;li&gt;~1000 lines of HTML to hold the JavaScript graphing stuff.&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/masukomi/hey&quot;&gt;GitHub Repo Here&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;writing-in-chicken-scheme&quot;&gt;Writing in Chicken Scheme&lt;/h3&gt;
&lt;p&gt;I love Scheme. It really works for my brain. Chicken Scheme is one of the better schemes. It’s got a large collection of useful libraries. It also transpiles to C (or JavaScript actually). The end result is a fast tiny binary. As a bonus, you can generate C files so that your libraries can be called from almost any other language.&lt;/p&gt;
&lt;p&gt;As an example, my &lt;a rel=&quot;external&quot; href=&quot;https://github.com/masukomi/private_comments&quot;&gt;private_comments&lt;/a&gt; API web server runs in less than 7MB of RAM and I didn’t even &lt;em&gt;try&lt;/em&gt; to make it small.&lt;/p&gt;
&lt;p&gt;Unfortunately figuring anything out in Chicken Scheme felt like pulling teeth. There’s a ton of documentation, but it’s mostly useless. It assumes a ridiculous amount of knowledge and doesn’t explain anything. It feels like “Here’s the method signature. Have fun figuring out what it does.”&lt;/p&gt;
&lt;p&gt;Getting anything done in Chicken Scheme feels like a major accomplishment. It’s also incredibly draining because it’s so damn hard to figure out if you’re new. It’s not the language’s fault. The language is trivially easy, like all Schemes. It’s the documentation.&lt;/p&gt;
&lt;p&gt;These days I use Chicken Scheme very strategically. For example, &lt;a rel=&quot;external&quot; href=&quot;https://github.com/masukomi/heatmapper&quot;&gt;my CLI heatmap generation tool&lt;/a&gt; is written in Chicken Scheme because I wanted something &lt;em&gt;very&lt;/em&gt; fast. I also liked that folks could use the core library in any other language if they felt like dealing with their language’s C interface.&lt;/p&gt;
&lt;h3 id=&quot;delusions-of-sharability&quot;&gt;Delusions of Sharability&lt;/h3&gt;
&lt;p&gt;I should also note that I was working under a mistaken belief. I believed that it would  be possible to generate a binary for an OS that I could just hand to someone without them having to know anything about Chicken Scheme, or Go, or whatever it was written in.&lt;/p&gt;
&lt;p&gt;The truth is, you can’t. It’s theoretically possible. If you could fully statically link a binary, you’d have no worries. Unfortunately it turns out that that, practically speaking, that’s impossible on macOS. They really, &lt;em&gt;really&lt;/em&gt; want you to use dylibs. Excluding apps with a “hello world” level of complexity, I’m not sure you can do it.&lt;/p&gt;
&lt;p&gt;I spent a &lt;em&gt;lot&lt;/em&gt; of time and energy trying to make this happen, but ultimately had to abandon the hope.&lt;/p&gt;
&lt;h2 id=&quot;crystal-lang&quot;&gt;Crystal Lang&lt;/h2&gt;
&lt;p&gt;I’m a Ruby dev by trade, and Crystal is, essentially, just a compiled ruby with Static Typing. Or, it was at the time. These days it’s added concurrency and parallelism and is growing into its own thing.&lt;/p&gt;
&lt;p&gt;I wanted to rewrite it in a nice, organized, maintainable way. At the time Crystal was still pre-1.0 volatile, and didn’t have a ton of users or projects. There were, and I think, still are, multiple ORMs (Object Relational Mappings) competing with no clear winner.&lt;/p&gt;
&lt;p&gt;Unfortunately, they were very immature tools. So, I took one that I thought was good, and added in relations like “has many” and “belongs to”.&lt;/p&gt;
&lt;p&gt;I thought. I planned. I organized. I Object Oriented the 💩 out of it. I wrote and used &lt;a rel=&quot;external&quot; href=&quot;https://github.com/masukomi/sparker&quot;&gt;a sparkline library for Crystal&lt;/a&gt;. I wrote &lt;a rel=&quot;external&quot; href=&quot;https://github.com/masukomi/crystal_cli_graph&quot;&gt;a CLI bar chart library for Crystal&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I added a CLI bar-chart graph of interruptions by hour so that I could easily see when I was being interrupted.&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ hey report interrupts_by_hour&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Interrupts By Hour:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                          ▁&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                          █&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                 ▁     ▁  █&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                 █     █  █&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                 █     █  █     ▁&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                           ▁     █     █  █  ▁  █&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                           █     █     █  █  █  █&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                           █     █     █  █  █  █&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                           █  ▁  █     █  █  █  █&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                           █  █  █     █  █  █  █&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                           █  █  █     █  █  █  █&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                           █  █  █     █  █  █  █&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                           █  █  █     █  █  █  █&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;▁  ▁  ▁  ▁  ▁  ▁  ▁  ▁  ▁  █  █  █  ▁  █  █  █  █  ▁  ▁  ▁&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;00 01 02 03 04 05 07 07 08 09 10 11 12 13 14 15 16 17 18 23&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Honestly? It was pretty damn good.&lt;/p&gt;
&lt;p&gt;But then, my life changed. I was completely burnt out from the constant interruptions. I was having random Panic Attacks over trivial things. My wife was burnt out too. We quit our jobs, cashed in the 401k and lived off of savings for the better part of a year. It set back our retirement, but gave us enough time to &lt;em&gt;begin&lt;/em&gt; recovering.&lt;/p&gt;
&lt;p&gt;I didn’t need Hey! anymore, so I wandered off.&lt;/p&gt;
&lt;h3 id=&quot;final-totals&quot;&gt;Final Totals&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;~1600 lines of Crystal in the core tool (including tests)&lt;/li&gt;
&lt;li&gt;~300 for the &lt;a rel=&quot;external&quot; href=&quot;https://github.com/masukomi/crystal_cli_graph&quot;&gt;bar chart lib&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;~50 for the &lt;a rel=&quot;external&quot; href=&quot;https://github.com/masukomi/sparker&quot;&gt;sparkline lib&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;~400 for the &lt;a rel=&quot;external&quot; href=&quot;https://github.com/masukomi/crystal_fmt&quot;&gt;cli table generator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;~150 lines for the &lt;a rel=&quot;external&quot; href=&quot;https://github.com/masukomi/sentence_options&quot;&gt;custom arguments parser&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;~300 lines of additions to the DB library (mostly macros)&lt;/li&gt;
&lt;li&gt;Total ~2800 lines of Crystal&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/masukomi/hey_2&quot;&gt;GitHub Repo Here&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;writing-in-crystal&quot;&gt;Writing in Crystal&lt;/h3&gt;
&lt;p&gt;Crystal’s a great language. I have nothing bad to say about it. I happily supported them on &lt;a rel=&quot;external&quot; href=&quot;https://opencollective.com/crystal-lang&quot;&gt;Open Collective&lt;/a&gt; for a long time. If you want to see what I think is a pretty well designed Crystal app, go look at &lt;a rel=&quot;external&quot; href=&quot;https://github.com/masukomi/oho&quot;&gt;oho&lt;/a&gt;. It’s the world’s greatest tool for converting colored terminal output to beautiful HTML. I’m pretty proud of it.&lt;/p&gt;
&lt;p&gt;These days though, Crystal isn’t my happy-place. I’ve spent too many years in Ruby. I want something different for my personal coding.&lt;/p&gt;
&lt;h2 id=&quot;fast-forward-dot-dot-dot&quot;&gt;Fast-Forward…&lt;/h2&gt;
&lt;p&gt;Fast-forward from 2016 to December 2022. I’m unemployed again, like so many of us (&lt;a rel=&quot;external&quot; href=&quot;https://masukomi.org/resume/kay_rhodes_resume.html&quot;&gt;Hire Me!&lt;/a&gt;), and while I’m actually getting &lt;em&gt;a lot&lt;/em&gt; done, I don’t &lt;em&gt;feel&lt;/em&gt; like I am. I’m being too hard on myself, and not giving myself the credit I deserve for accomplishing the things I have. I decide to start time tracking. I figured if I could look back and see how I actually spent the day I could have a better feeling for what &lt;em&gt;really&lt;/em&gt; happened. “I didn’t get anything done today on my work, but that’s because I spent a ton of time on all these other things that needed doing.”&lt;/p&gt;
&lt;p&gt;It turns out, I was right. In addition, the act of tracking my time makes me think about how I’m spending it, &lt;em&gt;as&lt;/em&gt; I’m spending it.&lt;/p&gt;
&lt;p&gt;I didn’t want to write a new time tracker. I just wanted to track my time. I knew there were multiple, good, off-the-shelf CLI time trackers.&lt;/p&gt;
&lt;p&gt;I tried using 3 of them, but they all frustrated me for one reason or another. Some tools wanted me to interface with it in a way that felt awkward or annoying. Some had annoying technical things.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/TailorDev/Watson&quot;&gt;Watson&lt;/a&gt; came very close, but every time i needed to backdate a timer i had to type in explicit 4 digit 24 hour time. E.g. 08:30 not 8:30 and 18:47 not 6:47. It’s a little thing but I was doing it at least ten times a day and it annoyed me every time. Also, the ability to edit a timer was just broken.&lt;/p&gt;
&lt;p&gt;Then I realized… I already &lt;em&gt;have&lt;/em&gt; a time tracker that works with my 🧠. It just doesn’t support &lt;em&gt;end&lt;/em&gt; times.&lt;/p&gt;
&lt;p&gt;I checkout the Crystal repo. I compile. It goes 💥. It goes 💥 here. It goes 💥 there. It goes 💥 everywhere. The language has changed in notable ways which break my code, and break the code in libraries I was depending on.&lt;/p&gt;
&lt;p&gt;In Crystal’s defense, it was 0.33.0 when I ported Hey! to it and they were very clear about the fact that things would be changing before they hit 1.0.&lt;/p&gt;
&lt;p&gt;The compiler was very helpful in telling me what changes to make. Eventually though, I hit a case where it was complaining that I wasn’t implementing a method defined in an abstract class, and I &lt;em&gt;definitely&lt;/em&gt; was. At that point I gave up. I just don’t have the emotional spoons to go fixing problems I didn’t create in a side-project that I didn’t even want to write in the first place. I don’t particularly want to be writing in Crystal these days anyway.&lt;/p&gt;
&lt;p&gt;Maybe the Chicken Scheme version?&lt;/p&gt;
&lt;p&gt;Chicken Scheme has moved from v4 to v5 in the intervening years, but Chicken’s upgrade is relatively painless. I’ve already done it for a couple of projects. It’s mostly just a matter of changing some import statements.&lt;/p&gt;
&lt;p&gt;20 minutes later and I’ve got a working version of Hey! It’s a worse codebase, &lt;em&gt;but it complies!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Hack. Hack. Hack.
Bug. Bug. Bug. I’m fighting with Chicken Scheme again.&lt;/p&gt;
&lt;p&gt;“Arrgh! I do not need this. This isn’t even a good codebase to begin with.”&lt;/p&gt;
&lt;p&gt;So, I step back. I ask myself what the &lt;em&gt;bare minimum&lt;/em&gt; feature set would be that would be good enough to use and not annoy me:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the ability to start and stop a timer&lt;/li&gt;
&lt;li&gt;the ability to tag a timer&lt;/li&gt;
&lt;li&gt;the ability to backdate a timer because I frequently forget to start or stop them.&lt;/li&gt;
&lt;li&gt;no !@#$ 24hr time.&lt;/li&gt;
&lt;li&gt;a log of time spent.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That’s not actually that much…&lt;/p&gt;
&lt;h2 id=&quot;and-then-raku&quot;&gt;And then Raku&lt;/h2&gt;
&lt;p&gt;I create a new directory and start hacking. I’m still new to Raku, but overall I’m loving it.&lt;/p&gt;
&lt;p&gt;I started by writing about ~250 lines of ugly-ass no-apologies code. I had one goal: get it working in the shortest possible time. 250 lines gets me a DB layer and the ability to start and stop timers (no backdating).&lt;/p&gt;
&lt;p&gt;I try to run it. It goes 💥, but that’s to be expected. I have no tests &amp;amp; I’ve literally never compiled it. To my great surprise, the bugs are all little things like missing commas or semicolons. There’s &lt;em&gt;nothing&lt;/em&gt; notable.&lt;/p&gt;
&lt;p&gt;This is &lt;em&gt;huge&lt;/em&gt;. If a Raku newb like me can write ~250 lines of code and not have any notable bugs, it means they have done a damn good job of putting together a language.&lt;/p&gt;
&lt;p&gt;I’m chuffed. I keep hacking. Along the way, I’m noticing that lots of little nice-to-have’s are trivial to add while I’m there.&lt;/p&gt;
&lt;p&gt;I don’t bother with an ORM. I don’t bother with &lt;em&gt;any&lt;/em&gt; OOP (Object Oriented Programming). It’s just a collection of functions that query a SQLite DB with raw SQL and pass the resulting hashes around.&lt;/p&gt;
&lt;p&gt;The ecosystem of libraries gets me nice things like time durations as strings “2 hours and 33 minutes” or “2h33m”, and pretty tables. The pretty tables are &lt;a rel=&quot;external&quot; href=&quot;https://github.com/masukomi/Prettier-Table/&quot;&gt;my fork of another library&lt;/a&gt;, but I’m not including that in the totals because I didn’t write it for this project.&lt;/p&gt;
&lt;p&gt;I still don’t have the command line graphs implemented, and it looks like I’ll have to port that from Crystal. There isn’t a Sparkline library yet either, so add another ~300 lines of code before I’m done.&lt;/p&gt;
&lt;h3 id=&quot;final-totals&quot;&gt;Final Totals&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;~800 lines of Raku&lt;/li&gt;
&lt;li&gt;~100 lines of &lt;a rel=&quot;external&quot; href=&quot;https://github.com/pgrange/bash_unit&quot;&gt;bash_unit&lt;/a&gt; tests&lt;/li&gt;
&lt;li&gt;~300 lines of &lt;em&gt;future&lt;/em&gt; code&lt;/li&gt;
&lt;li&gt;Silly levels of satisfaction&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/masukomi/hey_3&quot;&gt;GitHub Repo Here&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;writing-in-raku&quot;&gt;Writing in Raku&lt;/h3&gt;
&lt;p&gt;Notable things: I wrote precisely zero lines of code to process the command line arguments in a natural language fashion. I wrote zero lines of code to generate or wire up the CLI help doc shown below. Raku gave it to me “out of the box”.&lt;/p&gt;
&lt;p&gt;It took me about 5 lines to include a starter db with the package, check if you need it, and put it in place. That’s a combination of the language having a concept of resources in a bundle, &lt;a rel=&quot;external&quot; href=&quot;https://github.com/jonathanstowe/XDG-BaseDirectory&quot;&gt;a library that understands XDG Base Directory stuff&lt;/a&gt;, and &lt;a rel=&quot;external&quot; href=&quot;https://github.com/masukomi/XDG-GuaranteedResources&quot;&gt;my XDG::GuaranteeResources&lt;/a&gt; library that combines the two.&lt;/p&gt;
&lt;p&gt;Raku’s still got a very small community, but they are “knocking it out of the park” with useful libraries. And the language has been &lt;a rel=&quot;external&quot; href=&quot;https://raku.org/archive/doc/apocalypse.html&quot;&gt;incredibly well thought out&lt;/a&gt;. I have complaints, but they’re all nitpicks.&lt;/p&gt;
&lt;p&gt;Maybe it’s just that I started my professional programming career with Perl5. Whatever the reason Raku really works for my 🧠.&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Usage:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  hey start [&amp;lt;start_args&amp;gt; ...] -- Start a new timer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  hey stop [&amp;lt;stop_args&amp;gt; ...] -- stop an existing timer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  hey log &amp;lt;number&amp;gt; &amp;lt;duration&amp;gt; -- see a log of recent timers&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  hey log-interrupts &amp;lt;number&amp;gt; &amp;lt;duration&amp;gt; -- see a log of recent interruptions&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  hey running -- lets you know if there are any timers running &amp;amp; what they are for&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  hey &amp;lt;name&amp;gt; [&amp;lt;start_args&amp;gt; ...] -- Record an interruption&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  hey kill timer &amp;lt;id&amp;gt; -- Remove an unwanted timer.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  hey kill &amp;lt;name&amp;gt; -- Remove an unwanted person / thing from interruptions&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [&amp;lt;start_args&amp;gt; ...]    optional time adjustment, project(s), &amp;amp; optional tags&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [&amp;lt;stop_args&amp;gt; ...]     optional id, and optional time adjustments (e.g. 4 minutes ago)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;number&amp;gt;              number of duration units&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;duration&amp;gt;            duration string. E.g. minutes, hours, days, etc.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;name&amp;gt;                name of person / thing that interrupted you&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;id&amp;gt;                  the id of the timer to delete.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;reflecting-on-the-rewrites&quot;&gt;Reflecting on the rewrites&lt;/h2&gt;
&lt;p&gt;Looking back at all this work. I find myself coming to an interesting conclusion. With regards to code written specifically for you:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I believe that choosing subjectively good technology is more important than objectively good technology.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You have limited time to work on projects &lt;em&gt;for you&lt;/em&gt;. Don’t spend them in languages you don’t love. Write them with tools, and languages you &lt;em&gt;do&lt;/em&gt; love. Write them with tools that are exciting you. Rewrite them when you’ve moved on and you want to use them, but the idea of maintaining the old stuff is just draining.&lt;/p&gt;
&lt;p&gt;99% of the tools you write for you will never be looked at by anyone else. Even less of it will be &lt;em&gt;used&lt;/em&gt; by someone else. Don’t worry about what’s “good”. Do what makes &lt;em&gt;you&lt;/em&gt; feel good.&lt;/p&gt;
&lt;p&gt;Chicken Scheme made me feel good. Sometimes it still does. Crystal allowed my to do good things quickly, but it was never Joyful to me. I’m long past the days of Rubyish syntax being Joyful. I like it. It’s good, but I’ve written many many thousands of lines of it and the wonder and joy of it has worn off.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;[UPDATE] Since writing this I’ve thought a lot about the choices we make when coding specifically for ourselves vs coding for others. The result is the &lt;a rel=&quot;external&quot; href=&quot;https://weblog.masukomi.org/2023/02/10/duct-tape-baling-wire-methodology/&quot;&gt;Duct Tape &amp;amp; Baling Wire Methedology&lt;/a&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Was it worth rewriting all those times?&lt;/p&gt;
&lt;p&gt;100%&lt;/p&gt;
&lt;p&gt;The first rewrite (Crystal) was in a language I was enjoying, but more importantly it was desperately needed. The original codebase was spaghetti. It had grown without planning, as so many tiny-but-useful tools do.&lt;/p&gt;
&lt;p&gt;The second rewrite (Raku) was because I didn’t have the emotional spoons to deal. Fixing problems someone else created, in a tool i didn’t want to be writing, in a language I didn’t want to use… ugh. I didn’t need that.&lt;/p&gt;
&lt;p&gt;However, this rewrite also ended up reinforcing my thoughts about how awesome Raku is, and teaching me some new tricks.&lt;/p&gt;
&lt;h2 id=&quot;if-you-liked-that-dot-dot-dot&quot;&gt;If you liked that…&lt;/h2&gt;
&lt;p&gt;If you found that interesting, you’re probably the kind of geek who writes a bunch of useful command line tools. If so, you should check out &lt;a rel=&quot;external&quot; href=&quot;https://tooloo.dev&quot;&gt;TooLoo&lt;/a&gt;. That’s my Open Source tool that helps you document your tools. Find them later. Use them more.&lt;/p&gt;
&lt;h2 id=&quot;p-dot-s-dot-what-about-the-email-app-with-the-same-name&quot;&gt;P.S. What about the email app with the same name?&lt;/h2&gt;
&lt;p&gt;Hey! was created before the email service. I figure this project is never going to become popular enough that I’ll have to worry about brand confusion. ;)&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>I used AI to generate products &amp; write copy for my store</title>
        <published>2022-12-06T00:00:00+00:00</published>
        <updated>2022-12-06T00:00:00+00:00</updated>
        
        <author>
          <name>
            masukomi
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://weblog.masukomi.org/2022/12/06/i-used-ai-to-generate-products-write-copy-for-my-store/"/>
        <id>https://weblog.masukomi.org/2022/12/06/i-used-ai-to-generate-products-write-copy-for-my-store/</id>
        
        <content type="html" xml:base="https://weblog.masukomi.org/2022/12/06/i-used-ai-to-generate-products-write-copy-for-my-store/">&lt;div class=&quot;ox-hugo-toc toc&quot;&gt;
&lt;div class=&quot;heading&quot;&gt;Table of Contents&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/06/i-used-ai-to-generate-products-write-copy-for-my-store/#quick-summary&quot;&gt;Quick Summary&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/06/i-used-ai-to-generate-products-write-copy-for-my-store/#it-started-as-a-joke-dot-dot-dot&quot;&gt;It started as a joke…&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/06/i-used-ai-to-generate-products-write-copy-for-my-store/#the-work-begins-dot-dot-dot&quot;&gt;The work Begins…&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/06/i-used-ai-to-generate-products-write-copy-for-my-store/#generating-images&quot;&gt;Generating images&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/06/i-used-ai-to-generate-products-write-copy-for-my-store/#prepping-images&quot;&gt;Prepping images&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/06/i-used-ai-to-generate-products-write-copy-for-my-store/#redbubble&quot;&gt;RedBubble&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/06/i-used-ai-to-generate-products-write-copy-for-my-store/#the-site&quot;&gt;The site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/06/i-used-ai-to-generate-products-write-copy-for-my-store/#know-thyself&quot;&gt;Know Thyself&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/06/i-used-ai-to-generate-products-write-copy-for-my-store/#that-sweet-marketing-copy&quot;&gt;That Sweet Marketing Copy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/06/i-used-ai-to-generate-products-write-copy-for-my-store/#final-thoughts&quot;&gt;Final Thoughts&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/06/i-used-ai-to-generate-products-write-copy-for-my-store/#will-i-share-my-code&quot;&gt;Will I share my code?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/06/i-used-ai-to-generate-products-write-copy-for-my-store/#what-s-my-favorite&quot;&gt;What’s my favorite?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://weblog.masukomi.org/2022/12/06/i-used-ai-to-generate-products-write-copy-for-my-store/#so-many-images&quot;&gt;So Many Images&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;!--endtoc--&gt;
&lt;h2 id=&quot;quick-summary&quot;&gt;Quick Summary&lt;/h2&gt;
&lt;p&gt;I used Midjourney to generate art that I threw on t-shirts, coasters, and almost everything else RedBubble offers. Then I used OpenAI to generate copy for it, and combined that with a handful of custom scripts to generate a product site called &lt;a rel=&quot;external&quot; href=&quot;https://bedbathandthebeyond.com&quot;&gt;Bed Bath &amp;amp; The Beyond&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It took about 40 hours of work to put all that together for 13 products, but that will be faster next time. In the end, this is a surprisingly viable option, and the only real restriction on profit is how much effort you’re willing to put into marketing what you make.&lt;/p&gt;
&lt;h2 id=&quot;it-started-as-a-joke-dot-dot-dot&quot;&gt;It started as a joke…&lt;/h2&gt;
&lt;p&gt;A friend &lt;a rel=&quot;external&quot; href=&quot;https://connectified.com/@cobie/109442153511919853&quot;&gt;threw this out on Mastodon&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;/images/2022/12/06/cobies_initial_post_small.jpg&quot; alt=&quot;mastodon post suggesting &#39;bed bath and the beyond&#39; as a hook for horror writers&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; /&gt;
	&lt;figcaption&gt;&lt;strong&gt;screenshot of mastodon posts&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;For a giggle, I asked Midjourney for “UNSPEAKABLE HORRORS AT UNSPEAKABLE PRICES. ALSO, BATH MATS.” and this came out&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;/images/2022/12/06/monster_bath_mats_small.jpg&quot; alt=&quot;four bath mats with toothy monsters on them. most have tentacles. one is a terrified blue face&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;And they looked “real” enough that I wondered if I could actually make a “cool” bath-mat.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;/images/2022/12/06/first_real_bath_mat_small.jpg&quot; alt=&quot;the first &#39;real&#39; bath mat. an woodcut style image of lovecraft with writhing tentacles behind him&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; /&gt;
	&lt;figcaption&gt;&lt;strong&gt;lovecraft &amp; tentacles bath mat&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;A little editing, and I’d extracted it from the “bath mat”, and &lt;a rel=&quot;external&quot; href=&quot;https://www.redbubble.com/shop/ap/133892066?ref=studio-promote&quot;&gt;thrown it on Redbubble&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;/images/2022/12/06/etched_lovecraft_floor_pillow_small.jpg&quot; alt=&quot;the same image, but now on a floor pillow&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; /&gt;
	&lt;figcaption&gt;&lt;strong&gt;the same image on a floor pillow&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;That’s when things started to spiral out of control.&lt;/p&gt;
&lt;h2 id=&quot;the-work-begins-dot-dot-dot&quot;&gt;The work Begins…&lt;/h2&gt;
&lt;h3 id=&quot;generating-images&quot;&gt;Generating images&lt;/h3&gt;
&lt;p&gt;I spent that night working through images on Midjourney. It was hours of work, but as I was being pretty lenient with Midjourney I was able to get usable results pretty quickly. &lt;strong&gt;At the bottom of this post is a screenshot of the stream of images I generated.&lt;/strong&gt; I’d put it here, but it’s really long. ;)&lt;/p&gt;
&lt;h3 id=&quot;prepping-images&quot;&gt;Prepping images&lt;/h3&gt;
&lt;p&gt;Then came the editing. By default an upscaled image from midjourney with a 3:2 aspect ratio is only 1536 x 1024 which is fine on your screen, but not so hot for printing.&lt;/p&gt;
&lt;p&gt;Fortunately, I’ve actually got a background in print and fabrics are &lt;em&gt;not&lt;/em&gt; a high-resolution, or high-fidelity medium. So, upscaling artifacts &lt;em&gt;shouldn’t&lt;/em&gt; be a big deal on most things. I’m a bit unsure about the comforters and shower curtains though. Because of this, the acceptable resolution is much lower. Also, &lt;a rel=&quot;external&quot; href=&quot;https://help.redbubble.com/hc/en-us/articles/202270679-Dimensions-Format&quot;&gt;RedBubble has this handy page&lt;/a&gt; that suggests resolutions for each of their products.&lt;/p&gt;
&lt;p&gt;Combine that with &lt;a rel=&quot;external&quot; href=&quot;https://www.pixelmator.com/blog/2019/12/17/all-about-the-new-ml-super-resolution-feature-in-pixelmator-pro/&quot;&gt;Pixelmator Pro’s ML Super Resolution&lt;/a&gt; and the upscaling went pretty well.&lt;/p&gt;
&lt;p&gt;Most of the images required very little editing.&lt;/p&gt;
&lt;h3 id=&quot;redbubble&quot;&gt;RedBubble&lt;/h3&gt;
&lt;p&gt;At this point I’ve sunk at least 10 hours into the process. I’ve made two or three product pages on RedBubble for them. Creating the RedBubble product pages was … work. There’s just no getting around it. It’s a time sink.&lt;/p&gt;
&lt;p&gt;In their defense, it requires a lot of subjective human decision making. They’ve also done a ton of work to help folks to promote things. For example, when I click on “Download Images” on the Desk Mat for &lt;a rel=&quot;external&quot; href=&quot;https://bedbathandthebeyond.com/products/billy_and_gog_s_grand_adventures/&quot;&gt;Billy and Gog’s Grand Adventures&lt;/a&gt; I get this excellent collection of promo images to use to promote it.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;/images/2022/12/06/example_product_images_small.png&quot; alt=&quot;five professional looking product images of the desk mat with my image on it in many scenes&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; /&gt;
	&lt;figcaption&gt;&lt;strong&gt;screenshot of desk mats&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Upload, choose, set default colors, save, see what you missed, edit the page to tweak default fabric colors again, repeat.&lt;/p&gt;
&lt;h3 id=&quot;the-site&quot;&gt;The site&lt;/h3&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://gohugo.io&quot;&gt;Hugo&lt;/a&gt; is my default static site generator. It’s fast, it’s easy, and I’m familiar with it. So I start making pages, and it… is… taking… forever.&lt;/p&gt;
&lt;p&gt;The process was&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;grab the product url&lt;/li&gt;
&lt;li&gt;make a markdown link&lt;/li&gt;
&lt;li&gt;choose 2 or 3 items to highlight&lt;/li&gt;
&lt;li&gt;download images of the image on those products&lt;/li&gt;
&lt;li&gt;make a markdown link to each of those product pages&lt;/li&gt;
&lt;li&gt;embed the image in the page with a markdown link to the product page around it.&lt;/li&gt;
&lt;li&gt;come up with some witty title and ridiculous copy for the page&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I punted on the last one. The process doesn’t &lt;em&gt;sound&lt;/em&gt; like much when you say it, but in practice it was hugely time consuming, mentally draining, boring, and soul sucking.&lt;/p&gt;
&lt;h3 id=&quot;know-thyself&quot;&gt;Know Thyself&lt;/h3&gt;
&lt;p&gt;I knew that if I forced my way through, I could finish the 13 or so products I had. I also knew that I’d never add anything else to the site if I did. I’d definitely not make another site if some other entertaining idea came along.&lt;/p&gt;
&lt;p&gt;So, I wrote some code. We’re talking ugly, get it done, do the first thing that’ll work kind a code.&lt;/p&gt;
&lt;p&gt;Along the way I discover that for some reason Firefox doesn’t bother to store session cookies in its SQLite cookie database, and it turns out I need session cookies. So, right click, inspect the network call to their GraphQL API (totally undocumented) and “Copy as curl”.&lt;/p&gt;
&lt;p&gt;Then write a bash script to read in the clipboard, extract the cookies and throw them into some ancient Netscape Navigator format that curl apparently knows how to handle. This file doesn’t need to be regenerated for …. days? I dunno.&lt;/p&gt;
&lt;p&gt;Then copy the url for the product promotion page (the one with links to downloadable images) and run that through another script that extracts the product id, gives it to curl, which utilizes the new cookie file, and hits their GraphQL endpoint to extract the JSON (same stuff as on the web page). It’s more JSON than I need but refining the query would have been wasted time.&lt;/p&gt;
&lt;p&gt;Run that JSON through a third script (this one in &lt;a rel=&quot;external&quot; href=&quot;https://raku.org/&quot;&gt;Raku&lt;/a&gt;) that presents me with a list like this. Now I just need to scan the RedBubble promo page to find images I want to use, and type in their numbers.&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[33] Shower Curtain&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[34] Spiral Notebook&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[35] Sticker&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[36] Tall Mug&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[37] Tapestry&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[38] Throw Blanket&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[39] Throw Pillow&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[40] Transparent Sticker&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[41] Travel Coffee Mug&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[42] Wood Mounted Print&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[43] Zipper Pouch&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[44] iPad Skin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[45] iPad Snap Case&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[46] iPhone Skin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[47] iPhone Snap Case&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[48] iPhone Soft Case&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[49] iPhone Tough Case&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[50] iPhone Wallet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Choose some items (comma separated):&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The script considers my choices, downloads the default product image, runs it through imagemagic for resizing, takes my original artwork, resizes that, asks me for the name of the product and ….. voilà I’ve got a markdown file with all the soul-sucking grunt work done for me.&lt;/p&gt;
&lt;p&gt;And yes, I have a way to add new products without overwriting the page.&lt;/p&gt;
&lt;h3 id=&quot;that-sweet-marketing-copy&quot;&gt;That Sweet Marketing Copy&lt;/h3&gt;
&lt;p&gt;I never lost sight of the fact that this was, ultimately, a joke. I expect to, over time, make &lt;strong&gt;tens of dollars&lt;/strong&gt; from this. If we consider my hourly rate it’s very unlikely this thing will ever pay for the labor that went into it.&lt;/p&gt;
&lt;p&gt;So, because I’m not going to get rich on this, and I’m &lt;em&gt;probably&lt;/em&gt; going to get a Cease and Desist letter from a Megacorp who likely lacks a sense of humor and thus shan’t be named. I’m not worried about “real” copy.&lt;/p&gt;
&lt;p&gt;However. We’re a day and a half of work into this thing and frankly my ability to write entertaining micro-fiction about each of these is… shall we say, “diminished”.&lt;/p&gt;
&lt;p&gt;But along the way I’ve been keeping my friend’s discord ( the one responsible for this stupidity ) in the loop. There someone points to &lt;a rel=&quot;external&quot; href=&quot;https://www.alexbirkett.com/ai-text-generator/&quot;&gt;an article about using AI for marketing copy&lt;/a&gt;, and I remember that I’d seen a bunch of hype about OpenAI on Mastodon lately. I don’t really want great “marketing copy”. I want creative stories, that happen to also be marketing copy.&lt;/p&gt;
&lt;p&gt;So, I make an account there, and see what comes out. I started by creating some copy for this image, which I imagined having come from some old children’s book.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;/images/2016/12/06/elouise_makes_a_friend_small.png&quot; alt=&quot;an etching of a young girl offering handfuls of plant matter to an eight foot tall tentacle monster with big eyes&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; /&gt;
	&lt;figcaption&gt;&lt;strong&gt;Elouise offers flowers to a tentacle montster&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Folks… Text AIs &lt;em&gt;are good&lt;/em&gt;.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;/images/2022/12/06/example_open_ai_copy_small.png&quot; alt=&quot;a screenshot of the results of my first attempt at using OpenAI for generating copy. alas, it&#39;s a lot of text.&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; /&gt;
	&lt;figcaption&gt;&lt;strong&gt;OpenAI text output screenshot&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In the end I edited the &lt;a rel=&quot;external&quot; href=&quot;https://bedbathandthebeyond.com/products/elouise_makes_a_friend/&quot;&gt;Elouise Makes A Friend&lt;/a&gt; text down to this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This image from Elouise Makes a Friend is a timeless reminder of friendship and kindness. It shows Elouise bravely offering a flower to the Tentacle Monster, who in turn offers a kind smile. Whether you choose a the sleeveless top, the throw pillow, or a coffee mug, this image will comfort you and remind you of the power of friendship.&lt;/p&gt;
&lt;p&gt;Bring this touching moment from Elouise Makes a Friend into your home. Our products featuring this image are perfect for gifting to that special someone, or for yourself.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Everything required heavy editing, but that didn’t matter. It’s &lt;em&gt;radically&lt;/em&gt; easier to edit two to three paragraphs of copy than to come up with some ridiculous story that you then have to edit anyway.&lt;/p&gt;
&lt;p&gt;Over time, I got better and guiding the AI, and increasingly impressed with what it would come up with. For example, I let it create almost everything on &lt;a rel=&quot;external&quot; href=&quot;https://bedbathandthebeyond.com/about&quot;&gt;the About page&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;Knowing then what I know now, would I do it again? 100%
It was fun. I’m ridiculously proud of it, and I genuinely want many of the products.&lt;/p&gt;
&lt;p&gt;Would I recommend it to others?&lt;/p&gt;
&lt;p&gt;Yes, but with caveats. You really need tooling to get from “I threw something on RedBubble” to “I have a site for my products”. Otherwise your brain will melt. I guess you could outsource that work, but the profit margin is so small here that that’d just put you farther in the hole.&lt;/p&gt;
&lt;p&gt;There are some existing tools on GitHub but a quick glance suggested they might be abandoned, and frankly it was faster to write ~100 lines of Raku than figure out and tweak someone else’s stuff.&lt;/p&gt;
&lt;p&gt;Also, I really need to find a prettier template. I’d hire someone to make one but there’s no way this thing is going to cover the cost of my time to make it, and I’m not currently employed (&lt;a rel=&quot;external&quot; href=&quot;https://masukomi.org/resume/kay_rhodes_resume.html&quot;&gt;hire me!&lt;/a&gt;) so that’s not going to happen.&lt;/p&gt;
&lt;p&gt;Will I add to the site? Almost guaranteed. You can &lt;a rel=&quot;external&quot; href=&quot;https://corporaterunaways.social/@bedbathandthebeyond&quot;&gt;Follow Bed Bath &amp;amp; The Beyond on Mastodon&lt;/a&gt; to see the latest items as I add them.&lt;/p&gt;
&lt;h3 id=&quot;will-i-share-my-code&quot;&gt;Will I share my code?&lt;/h3&gt;
&lt;p&gt;Maybe? It’s kinda crap, and could use a &lt;em&gt;lot&lt;/em&gt; of refinement, and frankly not many folks have realized the joys of Raku yet so it’s probably not in a language you want to poke anyways.&lt;/p&gt;
&lt;h3 id=&quot;what-s-my-favorite&quot;&gt;What’s my favorite?&lt;/h3&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://bedbathandthebeyond.com/products/lovecraft_and_octopus/&quot;&gt;Lovecraft &amp;amp; The Octopus&lt;/a&gt;. Something about this just tickles my funny-bone. Also it looks unreasonably good &lt;a rel=&quot;external&quot; href=&quot;https://www.redbubble.com/shop/ap/133923215?ref=studio-promote&quot;&gt;on everything I put it on&lt;/a&gt;. I can not explain it. Like, how can you not want &lt;a rel=&quot;external&quot; href=&quot;https://www.redbubble.com/shop/ap/133923215?ref=studio-promote&quot;&gt;this ridiculous clock&lt;/a&gt;?&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;/images/2022/12/06/lovecraft_and_octopus_clock.jpg&quot; alt=&quot;a woodcut of lovecraft looking slightly confused with a bug-eyed tentacle monster behind him. it is on a clock and the arms are coming out of lovecraft&#39;s forehead.&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; /&gt;
	&lt;figcaption&gt;&lt;strong&gt;a clock with an image of lovecraft and a giant octopus thing behind him&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;so-many-images&quot;&gt;So Many Images&lt;/h2&gt;
&lt;p&gt;Working With AI Image generators is like herding cats. This is, honestly, a surprisingly small number of images to get 13 usable products. See &lt;a rel=&quot;external&quot; href=&quot;https://weblog.masukomi.org/2022/11/30/a-journey-with-midjourney/&quot;&gt;A Journey With Midjourney&lt;/a&gt; if you’re curious about the process.&lt;/p&gt;
&lt;p&gt;Some of these are good, but I haven’t gotten around to incorporating in the site yet. A handful of these are pixelated, because I’ve got another blog post idea involving them… maybe more t-shirts. ;)&lt;/p&gt;
&lt;p&gt;Holler if there’s anything there that isn’t on the site, that you’d actually buy. I’ll add a page for it. I’m &lt;a rel=&quot;external&quot; href=&quot;https://connectified.com/@masukomi/&quot;&gt;@masukomi@connectified.com&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;/images/2022/12/06/midjourney_image_stream_small.jpg&quot; alt=&quot;a screenshot showing a stream of many many many images that were generated in midjourney&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; /&gt;
	&lt;figcaption&gt;&lt;strong&gt;midjourney image stream screenshot&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
</content>
        
    </entry>
</feed>
