<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Eric Yoon]]></title><description><![CDATA[script kiddie]]></description><link>https://blog.yoonicode.com</link><image><url>https://substackcdn.com/image/fetch/$s_!-zZv!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b12ceff-14c6-430b-aa64-b0c24a0c6348_1280x1280.png</url><title>Eric Yoon</title><link>https://blog.yoonicode.com</link></image><generator>Substack</generator><lastBuildDate>Mon, 01 Jun 2026 16:53:44 GMT</lastBuildDate><atom:link href="https://blog.yoonicode.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Eric Yoon]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[eric@yoonicode.com]]></webMaster><itunes:owner><itunes:email><![CDATA[eric@yoonicode.com]]></itunes:email><itunes:name><![CDATA[Eric Yoon]]></itunes:name></itunes:owner><itunes:author><![CDATA[Eric Yoon]]></itunes:author><googleplay:owner><![CDATA[eric@yoonicode.com]]></googleplay:owner><googleplay:email><![CDATA[eric@yoonicode.com]]></googleplay:email><googleplay:author><![CDATA[Eric Yoon]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Cognitive Function-Maxxing with Smart Home Tech]]></title><description><![CDATA[An introduction to human engineering through my journey with CO2 monitoring.]]></description><link>https://blog.yoonicode.com/p/cognitive-function-maxxing-with-smart-home-tech-20383bb32436</link><guid isPermaLink="false">https://blog.yoonicode.com/p/cognitive-function-maxxing-with-smart-home-tech-20383bb32436</guid><dc:creator><![CDATA[Eric Yoon]]></dc:creator><pubDate>Mon, 01 Jun 2026 06:37:08 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/4d828e50-b8e8-46c7-bf2e-26e455c1be3d_1024x1025.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Have you ever noticed yourself getting sleepy after sitting in an office for a while? Have you ever felt unable to concentrate while taking an exam in a large lecture&nbsp;hall?</p><p>Of course we all get tired at work and nervous during tests. But otherwise imperceptible environmental factors could also be at&nbsp;play.</p><p>Ever since I watched this <a href="https://www.youtube.com/watch?v=1Nh_vxpycEA">Tom Scott video</a> seven years ago, I&#8217;ve been acutely aware of the effects carbon dioxide levels can have on cognition and concentration. If you go outside, you&#8217;re likely to measure a nominal CO2 level of 400ppm (much to climate change scientists&#8217; concern&nbsp;!!). But if you take a reading in your bedroom after you&#8217;ve been working with the door shut for a few hours, levels can quickly rise to &gt;&nbsp;2000ppm.</p><p>The bad news is that cognitive function has been shown to be inversely correlated to CO2 concentration. At 1400ppm, cognitive function on demanding tasks (like your physics exam, or my software engineering job) can decline by up to&nbsp;50%.</p><p>I wasn&#8217;t going to accept the fact that my brain could be slowing down due to invisible particles in the air. So $30 and one Amazon purchase later, I got my hands on a portable CO2&nbsp;monitor.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SHgQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2112160-c2aa-40aa-8e21-d9003713521b_1024x1025.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SHgQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2112160-c2aa-40aa-8e21-d9003713521b_1024x1025.jpeg 424w, https://substackcdn.com/image/fetch/$s_!SHgQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2112160-c2aa-40aa-8e21-d9003713521b_1024x1025.jpeg 848w, https://substackcdn.com/image/fetch/$s_!SHgQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2112160-c2aa-40aa-8e21-d9003713521b_1024x1025.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!SHgQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2112160-c2aa-40aa-8e21-d9003713521b_1024x1025.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SHgQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2112160-c2aa-40aa-8e21-d9003713521b_1024x1025.jpeg" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f2112160-c2aa-40aa-8e21-d9003713521b_1024x1025.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!SHgQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2112160-c2aa-40aa-8e21-d9003713521b_1024x1025.jpeg 424w, https://substackcdn.com/image/fetch/$s_!SHgQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2112160-c2aa-40aa-8e21-d9003713521b_1024x1025.jpeg 848w, https://substackcdn.com/image/fetch/$s_!SHgQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2112160-c2aa-40aa-8e21-d9003713521b_1024x1025.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!SHgQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2112160-c2aa-40aa-8e21-d9003713521b_1024x1025.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>This handheld monitor provided great value to my life. Every hour or so, I would check the reading, and if it was over 1000ppm, I&#8217;d get up and open a window (or turn on the central HVAC&nbsp;fan).</p><div><hr></div><p>When I tell people about my interest in &#8220;biohacking,&#8221; I get the sense that they usually have the wrong idea. The word might conjure images of cyborgs, implants, and brain-machine interfaces. Admittedly, I do have a <a href="https://dangerousthings.com/product/next/">microchip in my hand</a>, but that&#8217;s beside the point. The definition of biohacking that I subscribe to&nbsp;is:</p><blockquote><p>Using technology to enhance the human condition through biological interfaces.</p></blockquote><p>Under this definition, something as simple as buying a CO2 monitor counts as biohacking! You&#8217;re improving a biological factor by using technology. Nothing about this is invasive&#8212;you&#8217;ve just introduced another metric into your&nbsp;life!</p><p>Due to the weird reaction the term &#8220;biohacking&#8221; gets, I&#8217;ve started trying to popularize the term <em>human engineering.</em> Bringing a CO2 monitor to work is just as much <em>human engineering</em> as inserting a magnet into your finger&nbsp;is.</p><div><hr></div><p>Anyways, back to the story. I brought my handheld CO2 monitor to my office. At the beginning of the day, levels started out pretty normal (around 600ppm), but by lunch time, they had risen all the way to 1500ppm. Obviously, this was due to about 15 humans performing respiration; or, alternatively, 500 trillion human cells performing cellular respiration.</p><p>Now, I must admit, having the CO2 monitor subjected me to the possibility of the nocebo effect. Watching the number rise potentially had psychological effects that made me actually feel less focused, or at the very least, attribute my tiredness to the CO2 concentration. However, when the solution is as simple as opening up a window, such downsides are miniscule.</p><p>This system worked great for a few days, but as a software developer who loves to over-engineer systems, I couldn&#8217;t just stop&nbsp;here.</p><div><hr></div><p>Despite probably <a href="https://xkcd.com/1205/">costing me time in the long run</a>, I&#8217;ve always loved automation! Checking the handheld monitor every few hours was a mental burden and one more thing to distract me. What if I could be automatically alerted when the CO2 levels rose to unacceptable levels?</p><p>After a bit of research, I landed on the <a href="https://www.netatmo.com/smart-weather-station">Netatmo Weather Station</a>, which is a consumer smart home device that constantly monitors your environment for factors like temperature, humidity, air pressure, and of course CO2 concentration. Luckily, this device connected to the Netatmo cloud, which has a convenient developer API! This API meant that I could ingest CO2 data into a simple Python or Node server running on my cloud VM, and send it anywhere I&nbsp;wanted.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EAID!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1fde04a-0d5b-4cab-a6ad-f89fd02017d7_743x653.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EAID!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1fde04a-0d5b-4cab-a6ad-f89fd02017d7_743x653.png 424w, https://substackcdn.com/image/fetch/$s_!EAID!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1fde04a-0d5b-4cab-a6ad-f89fd02017d7_743x653.png 848w, https://substackcdn.com/image/fetch/$s_!EAID!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1fde04a-0d5b-4cab-a6ad-f89fd02017d7_743x653.png 1272w, https://substackcdn.com/image/fetch/$s_!EAID!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1fde04a-0d5b-4cab-a6ad-f89fd02017d7_743x653.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EAID!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1fde04a-0d5b-4cab-a6ad-f89fd02017d7_743x653.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c1fde04a-0d5b-4cab-a6ad-f89fd02017d7_743x653.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!EAID!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1fde04a-0d5b-4cab-a6ad-f89fd02017d7_743x653.png 424w, https://substackcdn.com/image/fetch/$s_!EAID!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1fde04a-0d5b-4cab-a6ad-f89fd02017d7_743x653.png 848w, https://substackcdn.com/image/fetch/$s_!EAID!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1fde04a-0d5b-4cab-a6ad-f89fd02017d7_743x653.png 1272w, https://substackcdn.com/image/fetch/$s_!EAID!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1fde04a-0d5b-4cab-a6ad-f89fd02017d7_743x653.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">The Netatmo Weather&nbsp;Station.</figcaption></figure></div><p>The company I was interning for at the time was big into observability, meaning I had to learn how to use a system called Grafana. Grafana was indeed used for Official Company Business to monitor the health of the app, but I had other purposes in mind. I quickly set up some server code to forward data from the Netatmo API to Grafana, and the result was this beautiful graph!</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Z1CF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f658d5d-76fb-4c8b-9ff5-d2fe69b85a4b_1024x350.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Z1CF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f658d5d-76fb-4c8b-9ff5-d2fe69b85a4b_1024x350.png 424w, https://substackcdn.com/image/fetch/$s_!Z1CF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f658d5d-76fb-4c8b-9ff5-d2fe69b85a4b_1024x350.png 848w, https://substackcdn.com/image/fetch/$s_!Z1CF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f658d5d-76fb-4c8b-9ff5-d2fe69b85a4b_1024x350.png 1272w, https://substackcdn.com/image/fetch/$s_!Z1CF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f658d5d-76fb-4c8b-9ff5-d2fe69b85a4b_1024x350.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Z1CF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f658d5d-76fb-4c8b-9ff5-d2fe69b85a4b_1024x350.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6f658d5d-76fb-4c8b-9ff5-d2fe69b85a4b_1024x350.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!Z1CF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f658d5d-76fb-4c8b-9ff5-d2fe69b85a4b_1024x350.png 424w, https://substackcdn.com/image/fetch/$s_!Z1CF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f658d5d-76fb-4c8b-9ff5-d2fe69b85a4b_1024x350.png 848w, https://substackcdn.com/image/fetch/$s_!Z1CF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f658d5d-76fb-4c8b-9ff5-d2fe69b85a4b_1024x350.png 1272w, https://substackcdn.com/image/fetch/$s_!Z1CF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f658d5d-76fb-4c8b-9ff5-d2fe69b85a4b_1024x350.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>The next step was to create automated alerts. Grafana can be used to ping oncall engineers when request traffic drops below normal levels, so there&#8217;s no reason it couldn&#8217;t ping me when CO2 levels rose too&nbsp;high!</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!l4Q8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67fe8d93-05cb-4433-a931-62fc150404b1_700x214.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!l4Q8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67fe8d93-05cb-4433-a931-62fc150404b1_700x214.png 424w, https://substackcdn.com/image/fetch/$s_!l4Q8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67fe8d93-05cb-4433-a931-62fc150404b1_700x214.png 848w, https://substackcdn.com/image/fetch/$s_!l4Q8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67fe8d93-05cb-4433-a931-62fc150404b1_700x214.png 1272w, https://substackcdn.com/image/fetch/$s_!l4Q8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67fe8d93-05cb-4433-a931-62fc150404b1_700x214.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!l4Q8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67fe8d93-05cb-4433-a931-62fc150404b1_700x214.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/67fe8d93-05cb-4433-a931-62fc150404b1_700x214.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!l4Q8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67fe8d93-05cb-4433-a931-62fc150404b1_700x214.png 424w, https://substackcdn.com/image/fetch/$s_!l4Q8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67fe8d93-05cb-4433-a931-62fc150404b1_700x214.png 848w, https://substackcdn.com/image/fetch/$s_!l4Q8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67fe8d93-05cb-4433-a931-62fc150404b1_700x214.png 1272w, https://substackcdn.com/image/fetch/$s_!l4Q8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67fe8d93-05cb-4433-a931-62fc150404b1_700x214.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Alerts, straight to the company Slack&nbsp;channel.</p><div><hr></div><p>And with that, I had arrived at a pretty good solution. Even after my internship ended, I took the system back to my dorm room to monitor levels at home. I&#8217;d like to remark on some next steps I could take to make the system more robust and extensible (as any good software engineer&nbsp;should).</p><p>First, to my delight, the smart home world has been moving away from the old model of devices talking to 3rd-party servers. Besides being a privacy risk, commands and data having to go through multiple hops in the cloud is less than ideal. Instead of this, standards like Matter (over Wifi or Thread) have seen great participation from big tech and small manufacturers alike. Matter would allow your Google Home voice-activated speaker to talk to your lights, buttons, and CO2 monitors without any requests leaving your private LAN. Unfortunately, there are no commercial Matter-enabled CO2 monitors yet, but more devices are being added by the day&#8212;and you could even make your own using an <a href="https://store-usa.arduino.cc/products/nano-matter">Arduino Nano&nbsp;Matter</a>!</p><p>Second, my Netatmo-to-Grafana forwarding code was pretty hacky. There are more robust solutions such as <a href="https://www.home-assistant.io/">Home Assistant</a>, used by the top 1% of smart home enthusiasts.</p><p>Finally, it would be awesome to make all of this data available to AI agents! This is completely within the realm of possibility given software like the <a href="https://www.home-assistant.io/integrations/mcp_server/">Home Assistant MCP&nbsp;server</a>.</p><div><hr></div><p>In conclusion, I hope I&#8217;ve broadened your sense of what biohacking/human engineering constitute. You can make quite drastic improvements to your life with a little bit of technology. And even if you&#8217;re not big into smart home or aren&#8217;t the best with code, something as simple as a handheld monitor can make your day-to-day experience so much&nbsp;better.</p><p><em>View my open-source <a href="http://github.com/ericyoondotcom/CO2-Grafana">Netatmo + Grafana server repository</a> to build your own monitoring system, or check out my other work at <a href="https://yoonicode.com">yoonicode.com</a>. Cheers!</em></p>]]></content:encoded></item><item><title><![CDATA[How we will trust art made by humans]]></title><description><![CDATA[This is a story of one possible future in which AI works are indistinguishable from human ones.]]></description><link>https://blog.yoonicode.com/p/how-we-will-trust-art-made-by-humans-2072359b114c</link><guid isPermaLink="false">https://blog.yoonicode.com/p/how-we-will-trust-art-made-by-humans-2072359b114c</guid><dc:creator><![CDATA[Eric Yoon]]></dc:creator><pubDate>Wed, 04 Mar 2026 02:50:03 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/71aed876-7001-446a-9858-c230ed4478d3_1024x768.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p></p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!J4Yh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8961c685-01c9-4449-a072-302e2619cb73_1024x768.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!J4Yh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8961c685-01c9-4449-a072-302e2619cb73_1024x768.jpeg 424w, https://substackcdn.com/image/fetch/$s_!J4Yh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8961c685-01c9-4449-a072-302e2619cb73_1024x768.jpeg 848w, https://substackcdn.com/image/fetch/$s_!J4Yh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8961c685-01c9-4449-a072-302e2619cb73_1024x768.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!J4Yh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8961c685-01c9-4449-a072-302e2619cb73_1024x768.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!J4Yh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8961c685-01c9-4449-a072-302e2619cb73_1024x768.jpeg" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8961c685-01c9-4449-a072-302e2619cb73_1024x768.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!J4Yh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8961c685-01c9-4449-a072-302e2619cb73_1024x768.jpeg 424w, https://substackcdn.com/image/fetch/$s_!J4Yh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8961c685-01c9-4449-a072-302e2619cb73_1024x768.jpeg 848w, https://substackcdn.com/image/fetch/$s_!J4Yh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8961c685-01c9-4449-a072-302e2619cb73_1024x768.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!J4Yh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8961c685-01c9-4449-a072-302e2619cb73_1024x768.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>You can&#8217;t tell whether an image was AI generated. If you disagree, I urge you to <a href="https://www.realornotquiz.com/">play a game to test that hypothesis</a>. If you think you&#8217;re still pretty good at spotting AI media when you&#8217;re scrolling online, I am going to quietly link you the Wikipedia article on <a href="https://en.wikipedia.org/wiki/Survivorship_bias">survivorship bias</a>.</p><p>Anyways, I&#8217;m not here to talk about visually identifying AI works. Even if you&#8217;re the top 1% of AI discerners, I would like to ask you to consider what the other 99% believes.</p><p>Today, I want to discuss <em>trust</em> in a world where we are unable to tell computer&#8211; and human&#8211;generated works apart. If you still don&#8217;t believe <em>this world</em> is <em>our present world</em>, maybe you will consider our <em>future world</em>&nbsp;instead.</p><h4>Returning to meatspace</h4><p>Perhaps the only way for <em>you specifically</em> to know for certain that a work was human-produced is to&#8230; watch a human produce it. If you watched your friend take a photo, write a story, or draw a picture, barring sleight-of-hand and other deception, you can believe in the integrity of that&nbsp;media.</p><p>This is going to become the <em>only</em> way to verify the humanity of a work. It&#8217;s possible for this to be scaled up. Perhaps an exam proctor can verify the integrity of every one of their students&#8217; submissions. But it is unavoidable that this future will involve human oversight, including the time it takes to watch someone produce a&nbsp;work.</p><p>If you watch someone make something, you might be able to vouch for that work. Others may be able to take your word for it&#8212;or if not your word alone, the word of 3+ people who all witnessed its creation. How do we know whose word to trust,&nbsp;though?</p><h4>Trust networks</h4><p>Trust in real life looks like a web. I may trust someone new if two of my closest friends can vouch for them. Depending on who I am, I may also trust someone if fifty of my acquaintances can vouch for&nbsp;them.</p><p>If you can&#8217;t be there in person to see the creation of a work, your only bet is to hope that someone in your network was there instead: that is, someone to <em>attest</em> that the work is authentic. However, in this new world, <em>trusting</em> someone doesn&#8217;t simply mean that you believe that they have no intention to deceive. To trust someone, you also have to make an evaluation on their <em>ability to be deceived</em>; the word of someone tech illiterate isn&#8217;t useful when the goal is to tell whether something was made with&nbsp;AI.</p><p>Unlike online webs of trust, these networks need to remain small. Crucially, they are limited to meatspace interactions&#8212;there is no way to verify the integrity of a work if you&#8217;re online. Or even worse, the agent that you could be building trust towards may be an AI&nbsp;chatbot.</p><p>Luckily, we have tools to make this process of trust and attestation robust.</p><h4>The cryptography backing&nbsp;trust</h4><p>In this possible world, we might start using cryptography to solidify these trusted relationships. Keyrings in protocols like PGP make keeping track of trust networks&nbsp;easy.</p><p>As for attestation, this might take the form of public/private key cryptography employing signatures. After I sit down and write a blog post, I would ask my two witnesses (whom still need to be physically present) to sign the digital representation of my work with their public keys, effectively declaring that they watched me produce&nbsp;it.</p><p>Attestation can also show up as a matter of public record. This is the sole feat I believe blockchain to be useful for. If my two witnesses post the hash of my written work on a blockchain, they&#8217;ve forever and irrevocably attested to its authenticity.</p><h4>Conclusion</h4><p>In my humble opinion, <em>all possible futures</em> of our world are ones in which AI-generated works are indistinguishable by human-generated works, whether by human inspection or automated programs. Here I presented the mechanism we will use to verify humanity in <em>one possible&nbsp;future</em>.</p>]]></content:encoded></item><item><title><![CDATA[Modernizing the Yale Poker Club with Code]]></title><description><![CDATA[Playing card games is fun. Keeping track of ledgers is not. This is how my custom-built tech for Yale Poker Club helps players focus on winning, not accounting.]]></description><link>https://blog.yoonicode.com/p/modernizing-the-yale-poker-club-with-code-3bb076f802ec</link><guid isPermaLink="false">https://blog.yoonicode.com/p/modernizing-the-yale-poker-club-with-code-3bb076f802ec</guid><dc:creator><![CDATA[Eric Yoon]]></dc:creator><pubDate>Thu, 05 Feb 2026 05:36:48 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/dd0d388f-63f9-4bef-96f1-550b3c6c669a_1024x1366.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>While Yale students with active social lives are out partying on Friday nights, you&#8217;ll instead find me in the basement of William L. Harkness Hall. This gothic stone building is the home of Friday night games hosted by the <a href="https://yalepokerclub.com/">Yale Poker Club</a>. As <a href="https://yale-herald.com/2023/09/24/no-limit-at-the-table-with-the-yale-poker-club/">documented in the Yale Herald</a>, during these highly anticipated events, forty-something CS and Econ majors (let&#8217;s be real) gather to bet, check, and&nbsp;raise.</p><p>When the night&#8217;s over, though, the fun quickly turns into &#8220;wait, who do I Venmo?&#8221; and &#8220;why are we missing $20 from the ledger?!.&#8221; If you pay a visit to Harkness Hall the next Monday morning, you&#8217;ll find that the blackboards are filled with records of Yale&#8217;s best and brightest trying and failing to do simple addition.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7ETD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e675cee-aca8-4f0d-a380-5cb070000eba_1024x1366.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7ETD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e675cee-aca8-4f0d-a380-5cb070000eba_1024x1366.jpeg 424w, https://substackcdn.com/image/fetch/$s_!7ETD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e675cee-aca8-4f0d-a380-5cb070000eba_1024x1366.jpeg 848w, https://substackcdn.com/image/fetch/$s_!7ETD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e675cee-aca8-4f0d-a380-5cb070000eba_1024x1366.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!7ETD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e675cee-aca8-4f0d-a380-5cb070000eba_1024x1366.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7ETD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e675cee-aca8-4f0d-a380-5cb070000eba_1024x1366.jpeg" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7e675cee-aca8-4f0d-a380-5cb070000eba_1024x1366.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!7ETD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e675cee-aca8-4f0d-a380-5cb070000eba_1024x1366.jpeg 424w, https://substackcdn.com/image/fetch/$s_!7ETD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e675cee-aca8-4f0d-a380-5cb070000eba_1024x1366.jpeg 848w, https://substackcdn.com/image/fetch/$s_!7ETD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e675cee-aca8-4f0d-a380-5cb070000eba_1024x1366.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!7ETD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e675cee-aca8-4f0d-a380-5cb070000eba_1024x1366.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a><figcaption class="image-caption">The math is not mathing!!1!</figcaption></figure></div><p>With my experience with full-stack web development, I knew that this problem could be easily solved. I set out to make the ultimate Yale Poker Club ledger app. But before I could get coding, like any good engineer, I needed to determine the requirements and constraints for this&nbsp;app.</p><h4>Scoping the&nbsp;Problem</h4><p>Yale Poker Club is fast-paced. Enter the classroom, grab chips, and ask to be dealt cards. The more time spent fiddling around with a ledger app, the more time spent away from the table&#8212;and the bigger the headache I would have providing technical support.</p><p>So, I knew that having players download an app was a no-go. This needed to be a mobile-first web app, so players could pull up a simple URL and log their buy-ins. Also, I didn&#8217;t want players to have to log in with any SSO provider&#8212;the poker club runs on an honor system, so a simple &#8220;enter your email address&#8221; form would&nbsp;suffice.</p><p>That being said, Yale students love trying to break things. Some basic auth schema, disallowing players from meddling with each others&#8217; data, would be necessary.</p><h4>The App</h4><p>So, I built Yale Poker Club Ledger! Players could go to the website, select the table they&#8217;re sitting at, and buy&nbsp;in.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Qmaj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2594b25e-af9a-45e3-965a-7b3e57acf549_1024x801.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Qmaj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2594b25e-af9a-45e3-965a-7b3e57acf549_1024x801.png 424w, https://substackcdn.com/image/fetch/$s_!Qmaj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2594b25e-af9a-45e3-965a-7b3e57acf549_1024x801.png 848w, https://substackcdn.com/image/fetch/$s_!Qmaj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2594b25e-af9a-45e3-965a-7b3e57acf549_1024x801.png 1272w, https://substackcdn.com/image/fetch/$s_!Qmaj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2594b25e-af9a-45e3-965a-7b3e57acf549_1024x801.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Qmaj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2594b25e-af9a-45e3-965a-7b3e57acf549_1024x801.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2594b25e-af9a-45e3-965a-7b3e57acf549_1024x801.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!Qmaj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2594b25e-af9a-45e3-965a-7b3e57acf549_1024x801.png 424w, https://substackcdn.com/image/fetch/$s_!Qmaj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2594b25e-af9a-45e3-965a-7b3e57acf549_1024x801.png 848w, https://substackcdn.com/image/fetch/$s_!Qmaj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2594b25e-af9a-45e3-965a-7b3e57acf549_1024x801.png 1272w, https://substackcdn.com/image/fetch/$s_!Qmaj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2594b25e-af9a-45e3-965a-7b3e57acf549_1024x801.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!LR_P!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F813761aa-bfea-4f20-ab53-caa0ecbf64dd_1024x794.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LR_P!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F813761aa-bfea-4f20-ab53-caa0ecbf64dd_1024x794.png 424w, https://substackcdn.com/image/fetch/$s_!LR_P!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F813761aa-bfea-4f20-ab53-caa0ecbf64dd_1024x794.png 848w, https://substackcdn.com/image/fetch/$s_!LR_P!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F813761aa-bfea-4f20-ab53-caa0ecbf64dd_1024x794.png 1272w, https://substackcdn.com/image/fetch/$s_!LR_P!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F813761aa-bfea-4f20-ab53-caa0ecbf64dd_1024x794.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LR_P!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F813761aa-bfea-4f20-ab53-caa0ecbf64dd_1024x794.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/813761aa-bfea-4f20-ab53-caa0ecbf64dd_1024x794.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!LR_P!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F813761aa-bfea-4f20-ab53-caa0ecbf64dd_1024x794.png 424w, https://substackcdn.com/image/fetch/$s_!LR_P!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F813761aa-bfea-4f20-ab53-caa0ecbf64dd_1024x794.png 848w, https://substackcdn.com/image/fetch/$s_!LR_P!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F813761aa-bfea-4f20-ab53-caa0ecbf64dd_1024x794.png 1272w, https://substackcdn.com/image/fetch/$s_!LR_P!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F813761aa-bfea-4f20-ab53-caa0ecbf64dd_1024x794.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>On the page for the table itself, players have the option to buy in, top up, or buy out. Additionally, to solve the ledger discrepancy problem, players are required to submit a chip photo with their buy-out. That way, in case money is missing at the end of the night, some poor soul (&#8230;me) can go in and manually count the chips in every&nbsp;photo.</p><p>(Before you ask: yes, I tried to automate chip counting with a multimodal LLM; the technology just isn&#8217;t there&nbsp;yet.)</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!KPku!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d07c1e5-7b4e-4357-bb65-873cb6654acf_1024x568.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!KPku!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d07c1e5-7b4e-4357-bb65-873cb6654acf_1024x568.png 424w, https://substackcdn.com/image/fetch/$s_!KPku!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d07c1e5-7b4e-4357-bb65-873cb6654acf_1024x568.png 848w, https://substackcdn.com/image/fetch/$s_!KPku!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d07c1e5-7b4e-4357-bb65-873cb6654acf_1024x568.png 1272w, https://substackcdn.com/image/fetch/$s_!KPku!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d07c1e5-7b4e-4357-bb65-873cb6654acf_1024x568.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!KPku!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d07c1e5-7b4e-4357-bb65-873cb6654acf_1024x568.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9d07c1e5-7b4e-4357-bb65-873cb6654acf_1024x568.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!KPku!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d07c1e5-7b4e-4357-bb65-873cb6654acf_1024x568.png 424w, https://substackcdn.com/image/fetch/$s_!KPku!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d07c1e5-7b4e-4357-bb65-873cb6654acf_1024x568.png 848w, https://substackcdn.com/image/fetch/$s_!KPku!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d07c1e5-7b4e-4357-bb65-873cb6654acf_1024x568.png 1272w, https://substackcdn.com/image/fetch/$s_!KPku!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d07c1e5-7b4e-4357-bb65-873cb6654acf_1024x568.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h4>Sending Out&nbsp;Ledgers</h4><p>Great, now we know exactly how much money each person made! How can we have the losers pay the winners their well-deserved profits?</p><p>After manually sending out ledgers for the first few weeks, I had the idea to automate this process even further. Using the <a href="https://aws.amazon.com/ses/">AWS Simple Email Service</a>, I was able to dynamically generate HTML emails and blast them to all players at each&nbsp;table.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ajRI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe209eaf-feac-4b2f-a784-dfd3313fa3ce_1024x779.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ajRI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe209eaf-feac-4b2f-a784-dfd3313fa3ce_1024x779.png 424w, https://substackcdn.com/image/fetch/$s_!ajRI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe209eaf-feac-4b2f-a784-dfd3313fa3ce_1024x779.png 848w, https://substackcdn.com/image/fetch/$s_!ajRI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe209eaf-feac-4b2f-a784-dfd3313fa3ce_1024x779.png 1272w, https://substackcdn.com/image/fetch/$s_!ajRI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe209eaf-feac-4b2f-a784-dfd3313fa3ce_1024x779.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ajRI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe209eaf-feac-4b2f-a784-dfd3313fa3ce_1024x779.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/be209eaf-feac-4b2f-a784-dfd3313fa3ce_1024x779.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!ajRI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe209eaf-feac-4b2f-a784-dfd3313fa3ce_1024x779.png 424w, https://substackcdn.com/image/fetch/$s_!ajRI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe209eaf-feac-4b2f-a784-dfd3313fa3ce_1024x779.png 848w, https://substackcdn.com/image/fetch/$s_!ajRI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe209eaf-feac-4b2f-a784-dfd3313fa3ce_1024x779.png 1272w, https://substackcdn.com/image/fetch/$s_!ajRI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe209eaf-feac-4b2f-a784-dfd3313fa3ce_1024x779.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>To enable creating a table of who sends what to whom, I researched various algorithms online. I settled on a widely-known banking algorithm that greedily minimizes the number of transfers necessary. (Which is good, because Venmo seems to block users if they make too many transactions&#8230;)</p><h4>Reducing User&nbsp;Friction</h4><p>After testing the website for about a month, it seemed to be going swimmingly! We had fewer ledger discrepancies with the help of the chip photos, and banking was automatically settled without any need for blackboard math.</p><p>However, I noticed that it was a struggle educating players about the new system. Some weren&#8217;t aware that they had to buy in on the ledger. Some didn&#8217;t know what URL to go to. And more asked, &#8220;wait, which table number is&nbsp;this?&#8221;</p><p>I&#8217;ve always loved hardware that makes user interactions feel magical. It would&#8217;ve been easy to provide each table with a QR code&#8230; but when&#8217;s the last time you went to a restaurant and were happy to scan a code for the menu? I decided to go for something much more delightful: an NFC&nbsp;chip.</p><p>So, I bought some NFC stickers! Just like <a href="https://dangerousthings.com/product/next/">the one in my hand</a>, these let you write any URI to their few kilobytes of onboard memory. Then, when someone touches their phone to the tag (iPhone and Android compatible, by the way), a notification pops up, which you can click to be taken to the specified URI!</p><p>But plain NFC tags would be boring. So, I went to the <a href="https://ceid.yale.edu/">Yale Maker Space</a> and laser-cut some custom dealer chips, embellished with the Yale Poker Club&nbsp;logo.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!IYXl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F010b8e49-d329-4b2e-9d32-8db2c58c1306_1024x768.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IYXl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F010b8e49-d329-4b2e-9d32-8db2c58c1306_1024x768.jpeg 424w, https://substackcdn.com/image/fetch/$s_!IYXl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F010b8e49-d329-4b2e-9d32-8db2c58c1306_1024x768.jpeg 848w, https://substackcdn.com/image/fetch/$s_!IYXl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F010b8e49-d329-4b2e-9d32-8db2c58c1306_1024x768.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!IYXl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F010b8e49-d329-4b2e-9d32-8db2c58c1306_1024x768.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IYXl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F010b8e49-d329-4b2e-9d32-8db2c58c1306_1024x768.jpeg" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/010b8e49-d329-4b2e-9d32-8db2c58c1306_1024x768.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!IYXl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F010b8e49-d329-4b2e-9d32-8db2c58c1306_1024x768.jpeg 424w, https://substackcdn.com/image/fetch/$s_!IYXl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F010b8e49-d329-4b2e-9d32-8db2c58c1306_1024x768.jpeg 848w, https://substackcdn.com/image/fetch/$s_!IYXl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F010b8e49-d329-4b2e-9d32-8db2c58c1306_1024x768.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!IYXl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F010b8e49-d329-4b2e-9d32-8db2c58c1306_1024x768.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>With the NFC tag fastened to the back with some adhesive, these were ready to go! Now, players could tap the dealer button to be taken to the ledger&nbsp;website.</p><h4>Hungry for&nbsp;Data</h4><p>Since the conception of the Yale Poker Club ledger app, 50+ tables have been run and settled using the website. Soon, I realized that this was a treasure trove of&nbsp;data.</p><p>Poker players are always looking to increase their edge by learning how their fellow players make decisions and whether they are profitable. In addition, those dedicated to the game love tracking their earnings over time to determine whether they are a winning or losing&nbsp;player.</p><p>With a year of historical data, I realized I could create a real-time leaderboard. However, I didn&#8217;t want to make this a simple list&#8212;I&#8217;d had something much more eclectic&nbsp;planned.</p><p>There is way too much <a href="https://en.wikipedia.org/wiki/Glossary_of_poker_terms">poker-related jargon</a>, which can easily be offputting to new players. However, some select terms are quite humorous. Players are largely sorted into three categories: &#8220;whales&#8221; for those who all but give away money; &#8220;fish&#8221; for those who are inexperienced; and &#8220;sharks,&#8221; reserved for the best-of-the-best who make every calculated move according to the rules of game theory-optimal play.</p><p>So, I made the leaderboard sea-creature themed! Whales at the top; fish in the middle; sharks at the bottom, only if you scroll down. With a call to the Gemini API to generate an alliterative or rhyming nickname for every player, the ocean was now ready to be deployed.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!MZ0_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F879a11b2-3830-44bf-84dd-db4f1599a285_1024x714.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MZ0_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F879a11b2-3830-44bf-84dd-db4f1599a285_1024x714.png 424w, https://substackcdn.com/image/fetch/$s_!MZ0_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F879a11b2-3830-44bf-84dd-db4f1599a285_1024x714.png 848w, https://substackcdn.com/image/fetch/$s_!MZ0_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F879a11b2-3830-44bf-84dd-db4f1599a285_1024x714.png 1272w, https://substackcdn.com/image/fetch/$s_!MZ0_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F879a11b2-3830-44bf-84dd-db4f1599a285_1024x714.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MZ0_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F879a11b2-3830-44bf-84dd-db4f1599a285_1024x714.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/879a11b2-3830-44bf-84dd-db4f1599a285_1024x714.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!MZ0_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F879a11b2-3830-44bf-84dd-db4f1599a285_1024x714.png 424w, https://substackcdn.com/image/fetch/$s_!MZ0_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F879a11b2-3830-44bf-84dd-db4f1599a285_1024x714.png 848w, https://substackcdn.com/image/fetch/$s_!MZ0_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F879a11b2-3830-44bf-84dd-db4f1599a285_1024x714.png 1272w, https://substackcdn.com/image/fetch/$s_!MZ0_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F879a11b2-3830-44bf-84dd-db4f1599a285_1024x714.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h4>Conclusion</h4><p>Developing the ledger app was fun, made my experience at the table more pleasant, and helped me get to know some of the super smart people in the club. This is what I do best, after all: identifying a problem and solving it with&nbsp;code.</p><p>If you&#8217;re interested in poker and you&#8217;re a Yale student, <a href="https://yalepokerclub.com/">reach out to us</a>, and we&#8217;ll tell you where to find&nbsp;us!</p>]]></content:encoded></item><item><title><![CDATA[Explain The Tweet: Japanese Language Edition]]></title><description><![CDATA[I&#8217;m a wannabe Twitter comedian, but often times my jokes require what some might call elite ball knowledge. So, welcome to the first installment of &#8220;Explain The Tweet&#8221;, a mini blog-series where I explicate my best work. Maybe we&#8217;ll learn something cool along the way!]]></description><link>https://blog.yoonicode.com/p/explain-the-tweet-japanese-language-edition-5f94faf03415</link><guid isPermaLink="false">https://blog.yoonicode.com/p/explain-the-tweet-japanese-language-edition-5f94faf03415</guid><dc:creator><![CDATA[Eric Yoon]]></dc:creator><pubDate>Mon, 19 Jan 2026 08:48:28 GMT</pubDate><enclosure url="https://cdn-images-1.medium.com/max/759/1*h8lA2JMMrh5_nURiJC3TVw@2x.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I&#8217;m a wannabe Twitter comedian, but often times my jokes require what some might call <em>elite ball knowledge</em>. So, welcome to the first installment of &#8220;Explain The Tweet&#8221;, a mini blog-series where I explicate my best work. Maybe we&#8217;ll learn something cool along the&nbsp;way!</p><p>This is the &#127833; <em>Japanese Language edition</em>, dedicated to my jokes about my favorite target language.</p><h4>1. Moraic Timing and Sabrina Carpenter</h4><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://cdn-images-1.medium.com/max/759/1*h8lA2JMMrh5_nURiJC3TVw@2x.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://cdn-images-1.medium.com/max/759/1*h8lA2JMMrh5_nURiJC3TVw@2x.png 424w, https://cdn-images-1.medium.com/max/759/1*h8lA2JMMrh5_nURiJC3TVw@2x.png 848w, https://cdn-images-1.medium.com/max/759/1*h8lA2JMMrh5_nURiJC3TVw@2x.png 1272w, https://cdn-images-1.medium.com/max/759/1*h8lA2JMMrh5_nURiJC3TVw@2x.png 1456w" sizes="100vw"><img src="https://cdn-images-1.medium.com/max/759/1*h8lA2JMMrh5_nURiJC3TVw@2x.png" data-attrs="{&quot;src&quot;:&quot;https://cdn-images-1.medium.com/max/759/1*h8lA2JMMrh5_nURiJC3TVw@2x.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://cdn-images-1.medium.com/max/759/1*h8lA2JMMrh5_nURiJC3TVw@2x.png 424w, https://cdn-images-1.medium.com/max/759/1*h8lA2JMMrh5_nURiJC3TVw@2x.png 848w, https://cdn-images-1.medium.com/max/759/1*h8lA2JMMrh5_nURiJC3TVw@2x.png 1272w, https://cdn-images-1.medium.com/max/759/1*h8lA2JMMrh5_nURiJC3TVw@2x.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>To understand this joke, we need a crash course on Japanese phonetics. Let&#8217;s first talk about timing in languages.</p><p>English is stress-timed, meaning you&#8217;ll spend a roughly equal amount of time pronouncing sounds between each stressed syllable. Try&nbsp;this:</p><blockquote><p>I&#8217;M deVELoping A NEW appliCAtion.</p></blockquote><p>If you&#8217;re a native English speaker, you probably sped up the unstressed syllables to maintain a constant interval between each stressed syllable. Try pronouncing the sentence, but allot an equal time for each syllable, regardless of it&#8217;s stress. You sound like a&nbsp;robot.</p><p>Interestingly, languages like Spanish are indeed syllable-timed, which means native speakers <em>do</em> allot an equal amount of time for each syllable, regardless of&nbsp;stress.</p><p>Now we get to Japanese. Japanese is neither syllable-timed nor stress-timed; it is mora-timed. What is a <em>mora</em>, you might ask? Well, just like the syllable is the basic building block of English, the mora is the building block of Japanese.</p><p>Let&#8217;s look at the loanword <em>sensei</em> (yes, like what you would call your <em>karate</em> teacher, but also any other teacher for that matter). You might split the word into two syllables: <em>sen / sei</em>. However, a native Japanese speaker would split it into four <em>mora</em>: <em>se / n / se / i</em>. This moraic timing is so innate to the language that it is embedded into the writing systems. Notice how there are four characters, each corresponding to one <em>mora</em>:&nbsp;&#12379;&#12435;&#12379;&#12356;.</p><p>The nasal sound &#8220;n&#8221;&#8212;the only final-position consonant in the language&#8212;is allotted its own mora. The extended vowel &#8220;sei<em>&#8221; </em>(which may or may not be pronounced as a diphthong depending on where the speaker is from) is allotted two mora&#8212;two units of&nbsp;time.</p><p>And now we have the requisite elite ball knowledge to understand the joke! The video game company Nintendo is spelled &#12300;&#20219;&#22825;&#22530;&#12301;; or in a syllabary, &#12300;&#12395;&#12435;&#12390;&#12435;&#12393;&#12358;&#12301;. Each character corresponds to <em>ni / n / te / n / do / u </em>respectively.</p><p>Just like the &#8220;sei&#8221; in <em>sensei</em> takes up two mora, the &#8220;dou&#8221; in <em>Nintendo</em> takes up two mora. (And, in fact, <em>Nintendo</em> should be properly romanized as &#8220;Nintendou&#8221; if it were started any time after 1908). So, to respect the moraic timing, the <em>dou</em> should take two units of time to pronounce.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://cdn-images-1.medium.com/max/213/1*2mCvNwldw68_zjhoFF42YQ@2x.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://cdn-images-1.medium.com/max/213/1*2mCvNwldw68_zjhoFF42YQ@2x.png 424w, https://cdn-images-1.medium.com/max/213/1*2mCvNwldw68_zjhoFF42YQ@2x.png 848w, https://cdn-images-1.medium.com/max/213/1*2mCvNwldw68_zjhoFF42YQ@2x.png 1272w, https://cdn-images-1.medium.com/max/213/1*2mCvNwldw68_zjhoFF42YQ@2x.png 1456w" sizes="100vw"><img src="https://cdn-images-1.medium.com/max/213/1*2mCvNwldw68_zjhoFF42YQ@2x.png" data-attrs="{&quot;src&quot;:&quot;https://cdn-images-1.medium.com/max/213/1*2mCvNwldw68_zjhoFF42YQ@2x.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://cdn-images-1.medium.com/max/213/1*2mCvNwldw68_zjhoFF42YQ@2x.png 424w, https://cdn-images-1.medium.com/max/213/1*2mCvNwldw68_zjhoFF42YQ@2x.png 848w, https://cdn-images-1.medium.com/max/213/1*2mCvNwldw68_zjhoFF42YQ@2x.png 1272w, https://cdn-images-1.medium.com/max/213/1*2mCvNwldw68_zjhoFF42YQ@2x.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption"><em>Screenshot from musicnotes.com</em></figcaption></figure></div><p>And look at that: Carpenter chose to elongate the &#8220;dou&#8221; when pronouncing &#8220;switch it up like Nintendo&#8221; in her hit song &#8220;Espresso&#8221;!</p><p>We briefly touched on romanization, but now it&#8217;s time to explore that topic in depth&#8230; are you&nbsp;ready?</p><h4>2. Traditional vs. Modified Hepburn and the Performative Male</h4><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://cdn-images-1.medium.com/max/759/1*3iL0CPy0_7mQOm0I3s3tog@2x.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://cdn-images-1.medium.com/max/759/1*3iL0CPy0_7mQOm0I3s3tog@2x.png 424w, https://cdn-images-1.medium.com/max/759/1*3iL0CPy0_7mQOm0I3s3tog@2x.png 848w, https://cdn-images-1.medium.com/max/759/1*3iL0CPy0_7mQOm0I3s3tog@2x.png 1272w, https://cdn-images-1.medium.com/max/759/1*3iL0CPy0_7mQOm0I3s3tog@2x.png 1456w" sizes="100vw"><img src="https://cdn-images-1.medium.com/max/759/1*3iL0CPy0_7mQOm0I3s3tog@2x.png" data-attrs="{&quot;src&quot;:&quot;https://cdn-images-1.medium.com/max/759/1*3iL0CPy0_7mQOm0I3s3tog@2x.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://cdn-images-1.medium.com/max/759/1*3iL0CPy0_7mQOm0I3s3tog@2x.png 424w, https://cdn-images-1.medium.com/max/759/1*3iL0CPy0_7mQOm0I3s3tog@2x.png 848w, https://cdn-images-1.medium.com/max/759/1*3iL0CPy0_7mQOm0I3s3tog@2x.png 1272w, https://cdn-images-1.medium.com/max/759/1*3iL0CPy0_7mQOm0I3s3tog@2x.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>We looked at loanwords like <em>sensei</em> and proper nouns like <em>Nintendo</em>. Have you ever wondered: when a new word gets imported from Japanese into English, how do we convert the Japanese characters into Latin characters?</p><p>Well, there are various different answers, depending on whom and when you ask. Let&#8217;s look at the word &#12300;&#31038;&#38263;&#12301;&#65288;&#12375;&#12419;&#12385;&#12423;&#12358;&#65289;.</p><p>If you ask the Japanese government for an official romanization, they are required by law to give you &#8220;syaty&#244;&#8221;. This became official because it <em>was</em> standard in Japan during the time the law was written. However, if you showed this romanization to an English speaker without any Japanese knowledge, they will probably pronounce it wildly&nbsp;wrong.</p><p>To combat this, Christian missionary and Japanophile (read: OG weeb) James Curtis Hepburn introduced a new romanization system. This system was designed so that English speakers encountering these romanized words would instinctually pronounce them quite closely to their original Japanese pronunciations. So, our word would become &#8220;shach&#333;&#8221; (with the macron indicating a long vowel, as previously discussed). This is much closer to the original pronunciation!</p><p>While the Hepburn system was introduced in 1867, it was revised in 1908. The original version is known as &#8220;traditional Hepburn&#8221; while the revised version is &#8220;modified Hepburn.&#8221; One difference is the treatment of the nasal &#12300;&#12435;&#12301;, so your favorite battered and deep-fried seafood (&#22825;&#12407;&#12425;) would be &#8220;tempura&#8221; in traditional, but &#8220;tenpura&#8221; in modified. (The former reflects the assimilation of the nasal consonant, while the latter is just simpler.)</p><p>Back to the joke. Just like vowels can be extended (like &#8220;sei&#8221; in &#8220;sensei&#8221; and &#8220;dou&#8221; in &#8220;Nintendou&#8221;), consonants can also be extended to take up two mora. Your favorite green drink &#12300;&#25273;&#33590;&#12301;(&#12414;&#12387;&#12385;&#12419;&#65289;has a &#12300;&#12387;&#12301;character in it, elongating the following consonant. In Hepburn, this would be romanized as &#8220;matcha&#8221; (with the elongated &#8220;ch&#8211;&#8221; sound being rendered as &#8220;tch&#8211;&#8221;). However, if you were a <em>true</em> performative male and cared about the integrity of the Japanese language, you would romanize it with Kunrei-Shiki as &#8220;maccha&#8221; (in &#8220;situations for which prior precedent would make a sudden reform difficult&#8221;), or &#8220;mattya&#8221; (if you were really willing to die on this&nbsp;hill).</p><p>We&#8217;ve focused on the syllabary writing systems of Japanese, but now let&#8217;s pay attention to the Chinese characters!</p><h4>3. Radicals and the Zero-Width Joiner</h4><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://cdn-images-1.medium.com/max/763/1*M3f1YNDg32YUH_32ahvaxw@2x.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://cdn-images-1.medium.com/max/763/1*M3f1YNDg32YUH_32ahvaxw@2x.png 424w, https://cdn-images-1.medium.com/max/763/1*M3f1YNDg32YUH_32ahvaxw@2x.png 848w, https://cdn-images-1.medium.com/max/763/1*M3f1YNDg32YUH_32ahvaxw@2x.png 1272w, https://cdn-images-1.medium.com/max/763/1*M3f1YNDg32YUH_32ahvaxw@2x.png 1456w" sizes="100vw"><img src="https://cdn-images-1.medium.com/max/763/1*M3f1YNDg32YUH_32ahvaxw@2x.png" data-attrs="{&quot;src&quot;:&quot;https://cdn-images-1.medium.com/max/763/1*M3f1YNDg32YUH_32ahvaxw@2x.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://cdn-images-1.medium.com/max/763/1*M3f1YNDg32YUH_32ahvaxw@2x.png 424w, https://cdn-images-1.medium.com/max/763/1*M3f1YNDg32YUH_32ahvaxw@2x.png 848w, https://cdn-images-1.medium.com/max/763/1*M3f1YNDg32YUH_32ahvaxw@2x.png 1272w, https://cdn-images-1.medium.com/max/763/1*M3f1YNDg32YUH_32ahvaxw@2x.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>As you may know, many languages other than Chinese use Chinese characters. Korean used to have them in the form of <em>hancha</em>, until my GOAT King Sejong the Great banished them. Japanese still has them in the form of&nbsp;<em>kanji</em>.</p><p>Chinese characters are built on the mixing-and-matching of <em>radicals</em>&#8212;symbolic or ideographic building blocks. For example, you&#8217;ll see the radical &#27701;, meaning water, on the characters &#12300;&#28023;&#12301;(ocean) and&#12300;&#37202;&#12301;(alcohol).</p><p>Pivoting for a second, let&#8217;s talk about emoji. Open Twitter and type the &#128566;&#8205;&#127787;&#65039; (face with clouds) emoji 280 times. 280 is the character limit for a tweet&#8230; so why can&#8217;t we tweet 280 &#128566;&#8205;&#127787;&#65039;&nbsp;emoji?</p><p>It turns out that &#128566;&#8205;&#127787;&#65039; is represented as two separate characters, &#128566; (face without mouth) and &#127787;&#65039; (fog), merged together with a <em>Zero Width Joiner</em>. This Zero Width Joiner (ZWJ) is a special character defined by Unicode (not <a href="https://yoonicode.com/">Yoonicode</a>) that allows the combination of characters to create a new one. Since it is &#8220;zero width&#8221;, it doesn&#8217;t actually get rendered on the screen&#8212;it is a special instruction to your computer&#8217;s text renderer!</p><p>So, my great idea: what if we could use ZWJs to merge any radical we want? For example, what if you could combine the &#20018; (skewer) character with the &#25163; (hand) radical to represent skewers that you pick up with your hand? Or maybe you&#8217;ll combine it with the &#40165; (bird) radical to specify poultry-related kebabs. This would open the floodgates for linguistic innovation in China, Japan, and any other country that uses CJK (Chinese, Japanese, Korean) characters.</p><blockquote><p>Isn&#8217;t it lovely that the character for skewer looks just like a kebab? Now I&#8217;m hungry&#8230;&nbsp;&#20018;&#20018;&#20018;</p></blockquote><h4>Conclusion</h4><p>You&#8217;re here because you wanted three jokes explained to you&#8230; but you&#8217;ve left with new knowledge on Japanese phonetics, romanization, and even some technical details of UTF-8. I&#8217;d call that a&nbsp;win!</p><p>Stay tuned for the next installment of &#8220;Explain The Tweet.&#8221; Subscribe so you don&#8217;t miss&nbsp;it!</p>]]></content:encoded></item><item><title><![CDATA[The Frog in the Boiling Social Media Pot]]></title><description><![CDATA[How we went from sharing photos with friends to scrolling short form content&#8212;and didn&#8217;t even notice.]]></description><link>https://blog.yoonicode.com/p/the-frog-in-the-boiling-social-media-pot-fc25092cb631</link><guid isPermaLink="false">https://blog.yoonicode.com/p/the-frog-in-the-boiling-social-media-pot-fc25092cb631</guid><dc:creator><![CDATA[Eric Yoon]]></dc:creator><pubDate>Fri, 12 Dec 2025 01:21:56 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/ea08b395-b77f-47ad-8ff8-5a0284110c26_1024x628.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p></p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-Lh8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe39ea4ef-0512-4868-aaf6-aad8109db929_1024x628.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-Lh8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe39ea4ef-0512-4868-aaf6-aad8109db929_1024x628.png 424w, https://substackcdn.com/image/fetch/$s_!-Lh8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe39ea4ef-0512-4868-aaf6-aad8109db929_1024x628.png 848w, https://substackcdn.com/image/fetch/$s_!-Lh8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe39ea4ef-0512-4868-aaf6-aad8109db929_1024x628.png 1272w, https://substackcdn.com/image/fetch/$s_!-Lh8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe39ea4ef-0512-4868-aaf6-aad8109db929_1024x628.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-Lh8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe39ea4ef-0512-4868-aaf6-aad8109db929_1024x628.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e39ea4ef-0512-4868-aaf6-aad8109db929_1024x628.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!-Lh8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe39ea4ef-0512-4868-aaf6-aad8109db929_1024x628.png 424w, https://substackcdn.com/image/fetch/$s_!-Lh8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe39ea4ef-0512-4868-aaf6-aad8109db929_1024x628.png 848w, https://substackcdn.com/image/fetch/$s_!-Lh8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe39ea4ef-0512-4868-aaf6-aad8109db929_1024x628.png 1272w, https://substackcdn.com/image/fetch/$s_!-Lh8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe39ea4ef-0512-4868-aaf6-aad8109db929_1024x628.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a><figcaption class="image-caption">Pixabay, CC0&nbsp;1.0</figcaption></figure></div><p><em>Opinions are mine, and do not necessarily represent the views of any social media companies I have worked at in the past or will work for in the&nbsp;future.</em></p><div><hr></div><p>Try to remember Instagram in 2015. What&#8217;s on your home page? Maybe a few vacation photos from your close friends, maybe some candids from your mutuals. How about Twitter? In-jokes and life updates from the select accounts you&nbsp;follow.</p><p>Now, transport yourself back to the present. What does scrolling Instagram, X, or TikTok feel like? You&#8217;re bombarded with short-form content, autoplaying videos, and people SCREAMING to get your attention in the few milliseconds they have before you scroll away. How many of these people do you know? These people are not your friends, nor faces you&#8217;ve ever seen in real life. They took the &#8220;social&#8221; out of social&nbsp;media.</p><p>How did this happen? From 2015 to now, you probably didn&#8217;t notice this change in real time. This shift consisted of a series of subtle but <em>intentional</em> UI and algorithm design changes; and we were none the wiser, like a frog in a boiling&nbsp;pot.</p><div><hr></div><p>Remember this? Although often called an &#8220;infinite scroll,&#8221; 2018 Instagram had an <em>end</em>. Once you ran out of friends&#8217; photos to see, you&#8217;d hit this wall at the bottom of your feed: &#8220;<a href="https://about.instagram.com/blog/announcements/introducing-youre-all-caught-up-in-feed">you&#8217;re all caught&nbsp;up</a>.&#8221;</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BFPH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9509d6f-715b-4d0a-ba49-6ccd480288a5_1024x489.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BFPH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9509d6f-715b-4d0a-ba49-6ccd480288a5_1024x489.jpeg 424w, https://substackcdn.com/image/fetch/$s_!BFPH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9509d6f-715b-4d0a-ba49-6ccd480288a5_1024x489.jpeg 848w, https://substackcdn.com/image/fetch/$s_!BFPH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9509d6f-715b-4d0a-ba49-6ccd480288a5_1024x489.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!BFPH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9509d6f-715b-4d0a-ba49-6ccd480288a5_1024x489.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BFPH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9509d6f-715b-4d0a-ba49-6ccd480288a5_1024x489.jpeg" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e9509d6f-715b-4d0a-ba49-6ccd480288a5_1024x489.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!BFPH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9509d6f-715b-4d0a-ba49-6ccd480288a5_1024x489.jpeg 424w, https://substackcdn.com/image/fetch/$s_!BFPH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9509d6f-715b-4d0a-ba49-6ccd480288a5_1024x489.jpeg 848w, https://substackcdn.com/image/fetch/$s_!BFPH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9509d6f-715b-4d0a-ba49-6ccd480288a5_1024x489.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!BFPH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9509d6f-715b-4d0a-ba49-6ccd480288a5_1024x489.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Come 2020, Instagram quietly adds content below this wall, which they called <em><a href="https://pallyy.com/learn/how-to-turn-off-suggested-posts-on-instagram">suggested content</a></em>. This wasn&#8217;t a big change at the time&#8212;you&#8217;d still see exclusively media from accounts you follow above this &#8220;you&#8217;re all caught&nbsp;up.&#8221;</p><p>Soon, a switch was quietly flipped. The main feed became driven by the &#8220;suggested posts&#8221; algorithm; the old feed was only accessible through a <a href="https://www.theverge.com/2022/1/5/22868889/new-instagram-chronological-feed-algorithm-tests">small toggle at the top of the screen</a>. (Which, of course, reset back to &#8220;suggested&#8221; every time you closed the&nbsp;app.)</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!En29!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ba0f1ae-daf3-42b6-baf1-1b46c0b2bf18_1024x685.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!En29!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ba0f1ae-daf3-42b6-baf1-1b46c0b2bf18_1024x685.png 424w, https://substackcdn.com/image/fetch/$s_!En29!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ba0f1ae-daf3-42b6-baf1-1b46c0b2bf18_1024x685.png 848w, https://substackcdn.com/image/fetch/$s_!En29!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ba0f1ae-daf3-42b6-baf1-1b46c0b2bf18_1024x685.png 1272w, https://substackcdn.com/image/fetch/$s_!En29!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ba0f1ae-daf3-42b6-baf1-1b46c0b2bf18_1024x685.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!En29!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ba0f1ae-daf3-42b6-baf1-1b46c0b2bf18_1024x685.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3ba0f1ae-daf3-42b6-baf1-1b46c0b2bf18_1024x685.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!En29!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ba0f1ae-daf3-42b6-baf1-1b46c0b2bf18_1024x685.png 424w, https://substackcdn.com/image/fetch/$s_!En29!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ba0f1ae-daf3-42b6-baf1-1b46c0b2bf18_1024x685.png 848w, https://substackcdn.com/image/fetch/$s_!En29!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ba0f1ae-daf3-42b6-baf1-1b46c0b2bf18_1024x685.png 1272w, https://substackcdn.com/image/fetch/$s_!En29!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ba0f1ae-daf3-42b6-baf1-1b46c0b2bf18_1024x685.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Image from Instagram, via The&nbsp;Verge.</figcaption></figure></div><p><a href="https://www.theverge.com/2023/1/10/23549368/twitter-for-you-page-tiktok-following-tab">The exact same thing happened with Twitter</a>. The &#8220;For You&#8221; feed was added; a toggle was implemented to go back to the &#8220;Following&#8221; chronological feed; and quietly, this option was made not &#8220;sticky&#8221; so you would have to click it every time you opened the&nbsp;app.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pwDn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99891cc6-284b-415a-8538-dc238cd1395e_602x220.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pwDn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99891cc6-284b-415a-8538-dc238cd1395e_602x220.png 424w, https://substackcdn.com/image/fetch/$s_!pwDn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99891cc6-284b-415a-8538-dc238cd1395e_602x220.png 848w, https://substackcdn.com/image/fetch/$s_!pwDn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99891cc6-284b-415a-8538-dc238cd1395e_602x220.png 1272w, https://substackcdn.com/image/fetch/$s_!pwDn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99891cc6-284b-415a-8538-dc238cd1395e_602x220.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pwDn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99891cc6-284b-415a-8538-dc238cd1395e_602x220.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/99891cc6-284b-415a-8538-dc238cd1395e_602x220.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!pwDn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99891cc6-284b-415a-8538-dc238cd1395e_602x220.png 424w, https://substackcdn.com/image/fetch/$s_!pwDn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99891cc6-284b-415a-8538-dc238cd1395e_602x220.png 848w, https://substackcdn.com/image/fetch/$s_!pwDn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99891cc6-284b-415a-8538-dc238cd1395e_602x220.png 1272w, https://substackcdn.com/image/fetch/$s_!pwDn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99891cc6-284b-415a-8538-dc238cd1395e_602x220.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>During the introduction of each of these subtle UI changes, there was some backlash from power users, yet not much attention from the casual scroller. And this is how we got bait-and-switched into content consuming machines.</p><h4>Some Other&nbsp;Thoughts</h4><ul><li><p>Is it a coincidence that Instagram moved the &#8220;Reels&#8221; button to the exact location where the &#8220;Notifications&#8221; button used to be? Muscle memory is very strong&#8230; and at a company with product designers and user research galore, could this really have been a coincidence?</p></li><li><p>Featuring songs in your &#8220;grid&#8221; posts seems like an innovative feature. But the slow creep of autoplay music and video makes social media feel markedly <em>stressful</em>, at least for me. There is no way to pause content, besides exiting the app, or <em>literally holding your finger to the screen</em>. And with the creeping sense that <a href="https://www.wsj.com/tech/tiktok-algorithm-video-investigation-11626877477">every second spent looking at a post affects your algorithm</a>, there is no&nbsp;respite.</p></li></ul><h4>The Impact</h4><p>Where do you have most of your spontaneous ideas? Personally, I am most inventive in the shower (the one place you literally can&#8217;t use your phone) or before falling asleep (intentionally designated as a no-screens time for me). This is all speculation, but I&#8217;d say that endless content has been a great detriment to our creativity as a society driven by the invention of great ideas. Every minute you spend thinking, you have a small but existent chance of &#8220;striking gold&#8221; with an idea that could change the world; every minute you devote to scrolling instead, you&#8217;re throwing that chance&nbsp;away.</p><h4>What I&#8217;m&nbsp;Doing</h4><p>So&#8230; today, I deleted all of my social media apps. My attention span has been noticeably declining since the moment I downloaded them at the age of 13. I&#8217;m restless in lectures, I instinctively pull out my phone when I&#8217;m waiting for an elevator&#8230; I&#8217;ll still be around to promote my <a href="https://rhythmgamestudio.com/">upcoming games</a> and <a href="https://x.com/ericyoondotcom">post esoteric jokes on Twitter</a>, but I won&#8217;t be consuming any more content. (We&#8217;ll see how long this&nbsp;lasts.)</p>]]></content:encoded></item><item><title><![CDATA[Why do I always interrupt? Or, why am I always interrupted?]]></title><description><![CDATA[An answer to a burning question arises from Thanksgiving dinner.]]></description><link>https://blog.yoonicode.com/p/why-do-i-always-interrupt-or-why-am-i-always-interrupted-0fef8f9d673b</link><guid isPermaLink="false">https://blog.yoonicode.com/p/why-do-i-always-interrupt-or-why-am-i-always-interrupted-0fef8f9d673b</guid><dc:creator><![CDATA[Eric Yoon]]></dc:creator><pubDate>Sun, 30 Nov 2025 07:00:58 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!-zZv!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b12ceff-14c6-430b-aa64-b0c24a0c6348_1280x1280.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I&#8217;ll admit it: I interrupt too much. Often, I&#8217;ll have a conversation that looks something like&nbsp;this.</p><blockquote><p><strong>Me</strong>: &#8220;So, where&#8217;d you get that shirt?&#8221;<br><strong>Other</strong>: &#8220;I picked it up at that store on Broadway, the one that started in Japan with the&#8212;&#8221;<br><strong>Me</strong>: &#8220;Uniqlo?&#8221;<br><strong>Other</strong>: &#8220;&#8230;&#8221;<br><strong>Me</strong>: &#8220;&#8230;&#8221;<br><strong>Other</strong>: &#8220;Yeah, so I picked it up at that store on Broadway&#8230;&#8221;</p></blockquote><p>Notice the moment of awkward silence after I cut the other speaker off. This will occur 10&#8211;20 times in a conversation. But, as I started to pay more attention to conversational flow, I noticed that this only happens with a handful of people. With others, it looks something more like&nbsp;this:</p><blockquote><p><strong>Me</strong>: &#8220;So, where&#8217;d you get that shirt?&#8221;<br><strong>Other</strong>: &#8220;I picked it up at that store on Broadway, the one that started in Japan with the&#8202;&#8212;&#8202;&#8221;<br><strong>Me</strong>: &#8220;Uniqlo?&#8221;<br><strong>Other</strong>: &#8220;Yeah, Uniqlo! I love their summer clothing.&#8221;</p></blockquote><p>Or even like&nbsp;this:</p><blockquote><p><strong>Me</strong>: &#8220;So, where&#8217;d you get that shirt?&#8221;<br><strong>Other</strong>: &#8220;I picked it up at that store on Broadway, the one that started in Japan with the&#8202;&#8212;&#8202;&#8221;<br><strong>Me</strong>: &#8220;Uniqlo?&#8221;<br><strong>Other</strong>: &#8220;Actually no, it was called GU&#8212;&#8221;<br><strong>Me</strong>: &#8220;right, right right&#8212;&#8221;<br><strong>Other</strong>: &#8220;it&#8217;s a sister brand of Uniqlo actually.&#8221;</p></blockquote><p>Despite the multiple interruptions by me, conversation didn&#8217;t come to a halt. It seemed much more natural&#8212;the interruptions made it feel like I was signaling my interest. Compare this feeling to if I let the speaker monologue for 15 seconds without providing any feedback.</p><blockquote><p><strong>Me</strong>: &#8220;So, where&#8217;d you get that shirt?&#8221;<br><strong>Other</strong>: &#8220;I picked it up at that store on Broadway, the one that started in Japan with the red sign. Uniqlo, I think it&#8217;s called. Yeah, they sell these kinds of shirts and they come in all different colors, you should check it out someday.&#8221;<br><strong>Me</strong>: &#8220;Oh, cool. I&#8217;ve heard of it&nbsp;before.&#8221;</p></blockquote><p>Despite my interruptions being a way for me to signal active engagement with the information being relayed, why did it fall flat with some partners, introducing awkward silences? After doing some research, the answer to my question came from Thanksgiving dinner. But not my own family&#8217;s Thanksgiving dinner last Thursday; rather, Dr. Deborah Tannen&#8217;s recordings and transcriptions of Thanksgiving conversation as detailed in her book <em><a href="https://search.library.yale.edu/catalog/991010468317508651?block=Books">Conversational Style</a></em>.</p><div><hr></div><p>The part of this book that&#8217;s relevant to my question is the discussion of two contrasting styles of conversation: <em>High-Involvement</em> vs. <em>High-Considerateness</em>.</p><p>High-Involvement style consists of many different aspects, including an affinity for personal topics, a faster rate of speech, and talk oriented around telling stories. But, the most relevant aspect of High-Involvement conversation style is a high degree of <em>cooperative overlap</em>.</p><p>My interjection of an educated guess <em>&#8220;Uniqlo?&#8221;</em> is an example of this cooperative overlap. Rather than being a bid to &#8220;steal the floor,&#8221; it serves as a way for people who converse like me to demonstrate interest in the topic. Even people who are unfamiliar with the topic at hand can use these interjections to feel as a part of the conversation, &#8220;piggybacking&#8221; off of others&#8217; guesses, somewhat like character C does in this&nbsp;example:</p><blockquote><p><strong>A</strong>: &#8220;I picked it up at that store on Broadway, the one that started in Japan with the&#8202;&#8212;&#8202;&#8221;<br><strong>B</strong>: &#8220;Uniqlo?&#8221;<br><strong>C</strong>: &#8220;Oh, yeah, Uniqlo!&#8221;<br><strong>A</strong>: &#8220;Actually no, it was called GU&#8202;&#8212;&#8202;&#8221;<br><strong>B</strong>: &#8220;right, right right&#8202;&#8212;&#8202;&#8221;</p></blockquote><p>You&#8217;ll even see rapid-fire repetition of quick phrases (<em>&#8220;right, right right&#8221;</em>), which Tannen calls &#8220;machine-gunning.&#8221;</p><p>If this sounds like your ideal conversation, you may be a High-Involvement conversationalist. Tannen makes a precursory observation that the New Yorkers at her Thanksgiving dinner were more likely to be High-Involvement speakers.</p><p>Does this sound like a nightmare for you? You might be a High-Considerateness speaker. Read&nbsp;on&#8230;</p><div><hr></div><p>So, what happened in my original conversation, where the exact same cooperative overlapping led to awkward&nbsp;silence?</p><blockquote><p><strong>Me</strong>: &#8220;So, where&#8217;d you get that shirt?&#8221;<br><strong>Other</strong>: &#8220;I picked it up at that store on Broadway, the one that started in Japan with the&#8202;&#8212;&#8202;&#8221;<br><strong>Me</strong>: &#8220;Uniqlo?&#8221;<br><strong>Other</strong>: &#8220;&#8230;&#8221;<br><strong>Me</strong>:&nbsp;&#8220;&#8230;&#8221;</p></blockquote><p>This interlocutor here believed I was interrupting them because they thought I had something substantial to say, rather than a simple interjection to confirm understanding. They may leave the conversation feeling like they were not being listened to. This is at no fault of their own, mind you&#8212;it&#8217;s simply an incongruency with my High-Involvement style and their High-Considerateness style.</p><p>High-Involvement speech may be a natural skill, but it&#8217;s definitely a learned one: The non-New Yorkers at Tannen&#8217;s dinner table remarked that they were astounded at how many people could talk at once (and still hold an intelligible conversation). Others yet expressed that they previously misunderstood High-Involvement conversation as repeated interruptions and unwelcome bids to&nbsp;speak.</p><div><hr></div><p>So, what can we do? Here, I stray from the research done by Tannen and present my own opinions.</p><p>First, try to identify the type of speaker you&#8217;re talking to! You may be able to make an educated guess based on their cultural upbringing, but the best way is to listen. Do they cooperatively overlap frequently, or do they patiently wait their turn before speaking? You might even be able to use the other qualities of either conversation style, like their propensity to talk about personal topics or their tolerance for silent pauses, to determine which bucket they fit&nbsp;into.</p><p>If you&#8217;re a High-Involvement speaker like me talking to a High-Considerateness partner, you may have to make a conscious effort to hold your interjections and wait for them to finish. If you&#8217;re a High-Considerateness person talking to a High-Involvement interlocutor, try to remember that they aren&#8217;t trying to interrupt you. Finish your sentence&#8212;after all, they are trying to <em>cooperatively overlap</em> with you, which necessarily requires more than one person speaking at&nbsp;once!</p><p>Learning a little about conversation flow from the field of linguistics can help us be better speakers and listeners. So let&#8217;s start practicing now, and we&#8217;ll be ready for next Thanksgiving!</p><div><hr></div><p><em><strong>Referenced:</strong></em></p><p>Tannen, Deborah. <em>Conversational Style: Analyzing Talk Among Friends. Oxford Scholarship Online.</em> New ed. New York: Oxford University Press,&nbsp;2023</p><ul><li><p>Specifically sections &#8220;Features of High-Involvement Style,&#8221; &#8220;The Thanksgiving Conversation,&#8221; and &#8220;Overlap and&nbsp;Pace.&#8221;</p></li><li><p>The Tannen text is available from the <a href="https://search.library.yale.edu/catalog/991010468317508651?block=Books">Yale Library</a> if you are a student, or elsewhere online if&nbsp;not.</p></li></ul>]]></content:encoded></item><item><title><![CDATA[How I Solved Yale’s Scavenger Hunts with Code]]></title><description><![CDATA[After three years at Yale University, I have come to learn that Yale students love a good scavenger hunt.]]></description><link>https://blog.yoonicode.com/p/how-i-solved-yales-scavenger-hunts-with-code-c16d622440b4</link><guid isPermaLink="false">https://blog.yoonicode.com/p/how-i-solved-yales-scavenger-hunts-with-code-c16d622440b4</guid><dc:creator><![CDATA[Eric Yoon]]></dc:creator><pubDate>Tue, 18 Nov 2025 00:20:00 GMT</pubDate><enclosure url="https://cdn-images-1.medium.com/max/1024/1*xeMcQhLvc1QFnyygyaCM0w.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>After three years at Yale University, I have come to learn that Yale students love a good scavenger hunt. <a href="https://www.instagram.com/whalesofyale">Whales of Yale</a> is an Instagram account that hides crochet whales around campus, posting only a photo of the creature&#8217;s surroundings as a hint. <a href="https://www.theveritassearch.com/">The Veritas Search</a> is in its second year, encouraging students to find hidden &#8220;capsules&#8221; to win prizes like a meal with Mark Cuban. Without a lucky stroke of inspiration or special knowledge, chances of finding any of these prizes are slim&#8202;&#8212;&#8202;each prize is discovered within a matter of minutes, with almost 7,000 undergraduates all searching the moment a clue drops. As a Computer Science major, I knew I could use code to gain the upper&nbsp;hand.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://cdn-images-1.medium.com/max/1024/1*xeMcQhLvc1QFnyygyaCM0w.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://cdn-images-1.medium.com/max/1024/1*xeMcQhLvc1QFnyygyaCM0w.png 424w, https://cdn-images-1.medium.com/max/1024/1*xeMcQhLvc1QFnyygyaCM0w.png 848w, https://cdn-images-1.medium.com/max/1024/1*xeMcQhLvc1QFnyygyaCM0w.png 1272w, https://cdn-images-1.medium.com/max/1024/1*xeMcQhLvc1QFnyygyaCM0w.png 1456w" sizes="100vw"><img src="https://cdn-images-1.medium.com/max/1024/1*xeMcQhLvc1QFnyygyaCM0w.png" data-attrs="{&quot;src&quot;:&quot;https://cdn-images-1.medium.com/max/1024/1*xeMcQhLvc1QFnyygyaCM0w.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://cdn-images-1.medium.com/max/1024/1*xeMcQhLvc1QFnyygyaCM0w.png 424w, https://cdn-images-1.medium.com/max/1024/1*xeMcQhLvc1QFnyygyaCM0w.png 848w, https://cdn-images-1.medium.com/max/1024/1*xeMcQhLvc1QFnyygyaCM0w.png 1272w, https://cdn-images-1.medium.com/max/1024/1*xeMcQhLvc1QFnyygyaCM0w.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>The anatomy of a Whales of Yale post looks something like this: a picture of the crochet creature, a small portion of a floor or a wall (if you&#8217;re lucky), and a fun caption. Interestingly, each caption is updated after each whale is found with its former hiding location.</p><p>At first, I thought there might be some pattern to whale drops. After all, the people hiding them are students too. Maybe one of the hiders has class on Science Hill on Mondays and is more likely to hide whales around that region. Maybe whales hidden after 9PM were more likely to be around the dorms. I set out to make an interactive map, plotting each whale&#8217;s hiding location.</p><p>The first step was designing a data pipeline to download these images and obtain their latitude/longitude coordinates. The first step was easy&#8202;&#8212;&#8202;using the python instagrapi library, I was able to mass-download each post, along with their captions.</p><p>Extracting the geocoordinates proved to be a harder problem. First, I needed to figure out a way to extract <em>only</em> the place name (&#8220;Davies&#8221;), out of the caption which may contain other text. Many posts would refer to a location with a colloquial name used by Yale students: for example, &#8220;Davies&#8221; for Davies Auditorium, &#8220;WLH&#8221; for William L. Harkness Hall, or &#8220;LC&#8221; for Linsly-Chittenden Hall.</p><p>The perfect tool for this, I figured, was an LLM! Using the Gemini API, I was able to have each place name extracted from the caption, turned into the official building name, and saved to a&nbsp;.csv file. To make sure the LLM did not return any extra text, I used the Structured Outputs API, instructing Gemini to return two fields: one string containing the place name, and one boolean indicating whether it is confident in its&nbsp;answer.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://cdn-images-1.medium.com/max/1024/1*N3piCHfjC2q7NlNVTKQyOw.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://cdn-images-1.medium.com/max/1024/1*N3piCHfjC2q7NlNVTKQyOw.png 424w, https://cdn-images-1.medium.com/max/1024/1*N3piCHfjC2q7NlNVTKQyOw.png 848w, https://cdn-images-1.medium.com/max/1024/1*N3piCHfjC2q7NlNVTKQyOw.png 1272w, https://cdn-images-1.medium.com/max/1024/1*N3piCHfjC2q7NlNVTKQyOw.png 1456w" sizes="100vw"><img src="https://cdn-images-1.medium.com/max/1024/1*N3piCHfjC2q7NlNVTKQyOw.png" data-attrs="{&quot;src&quot;:&quot;https://cdn-images-1.medium.com/max/1024/1*N3piCHfjC2q7NlNVTKQyOw.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://cdn-images-1.medium.com/max/1024/1*N3piCHfjC2q7NlNVTKQyOw.png 424w, https://cdn-images-1.medium.com/max/1024/1*N3piCHfjC2q7NlNVTKQyOw.png 848w, https://cdn-images-1.medium.com/max/1024/1*N3piCHfjC2q7NlNVTKQyOw.png 1272w, https://cdn-images-1.medium.com/max/1024/1*N3piCHfjC2q7NlNVTKQyOw.png 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><p>With a list of place names, I could now pass them to the Google Maps Places API (New). Provided with some hints that the POI would be in the general New Haven area, the Google Maps API was able to extract the latitude and longitude of each&nbsp;whale.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://cdn-images-1.medium.com/max/1024/1*aiOQ55UVAD7jg2aX36Q72Q.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://cdn-images-1.medium.com/max/1024/1*aiOQ55UVAD7jg2aX36Q72Q.png 424w, https://cdn-images-1.medium.com/max/1024/1*aiOQ55UVAD7jg2aX36Q72Q.png 848w, https://cdn-images-1.medium.com/max/1024/1*aiOQ55UVAD7jg2aX36Q72Q.png 1272w, https://cdn-images-1.medium.com/max/1024/1*aiOQ55UVAD7jg2aX36Q72Q.png 1456w" sizes="100vw"><img src="https://cdn-images-1.medium.com/max/1024/1*aiOQ55UVAD7jg2aX36Q72Q.png" data-attrs="{&quot;src&quot;:&quot;https://cdn-images-1.medium.com/max/1024/1*aiOQ55UVAD7jg2aX36Q72Q.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://cdn-images-1.medium.com/max/1024/1*aiOQ55UVAD7jg2aX36Q72Q.png 424w, https://cdn-images-1.medium.com/max/1024/1*aiOQ55UVAD7jg2aX36Q72Q.png 848w, https://cdn-images-1.medium.com/max/1024/1*aiOQ55UVAD7jg2aX36Q72Q.png 1272w, https://cdn-images-1.medium.com/max/1024/1*aiOQ55UVAD7jg2aX36Q72Q.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>The final step was to create a GUI to display each post. I was able to vibe-code a website, making use of the Mapbox API. Enter the Whales of Yale: Intelligence Map.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://cdn-images-1.medium.com/max/1024/1*_6caGOUli1n-eZj6Q_pk6w.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://cdn-images-1.medium.com/max/1024/1*_6caGOUli1n-eZj6Q_pk6w.png 424w, https://cdn-images-1.medium.com/max/1024/1*_6caGOUli1n-eZj6Q_pk6w.png 848w, https://cdn-images-1.medium.com/max/1024/1*_6caGOUli1n-eZj6Q_pk6w.png 1272w, https://cdn-images-1.medium.com/max/1024/1*_6caGOUli1n-eZj6Q_pk6w.png 1456w" sizes="100vw"><img src="https://cdn-images-1.medium.com/max/1024/1*_6caGOUli1n-eZj6Q_pk6w.png" data-attrs="{&quot;src&quot;:&quot;https://cdn-images-1.medium.com/max/1024/1*_6caGOUli1n-eZj6Q_pk6w.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://cdn-images-1.medium.com/max/1024/1*_6caGOUli1n-eZj6Q_pk6w.png 424w, https://cdn-images-1.medium.com/max/1024/1*_6caGOUli1n-eZj6Q_pk6w.png 848w, https://cdn-images-1.medium.com/max/1024/1*_6caGOUli1n-eZj6Q_pk6w.png 1272w, https://cdn-images-1.medium.com/max/1024/1*_6caGOUli1n-eZj6Q_pk6w.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>After playing with the tool for a while, I realized that there was unfortunately no discernible pattern between weekday or time of day and whale location. Though, the work done to make this map interface seemed useful. My next idea was to add &#8220;reference photos&#8221; to the map. If I saw a brick floor, for example, I could look through the reference photos and find the ones with brick&nbsp;floors.</p><h3>Gathering Intelligence</h3><p>And so, I went on a multi-day expedition to take photos of Yale campus. Not photos of the pretty architecture or beautiful fall colors, mind you&#8202;&#8212;&#8202;I was snapping pics of floors, walls, trees, and furniture.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://cdn-images-1.medium.com/max/1024/1*k6eKElYjHw7H9kooTgEEjw.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://cdn-images-1.medium.com/max/1024/1*k6eKElYjHw7H9kooTgEEjw.png 424w, https://cdn-images-1.medium.com/max/1024/1*k6eKElYjHw7H9kooTgEEjw.png 848w, https://cdn-images-1.medium.com/max/1024/1*k6eKElYjHw7H9kooTgEEjw.png 1272w, https://cdn-images-1.medium.com/max/1024/1*k6eKElYjHw7H9kooTgEEjw.png 1456w" sizes="100vw"><img src="https://cdn-images-1.medium.com/max/1024/1*k6eKElYjHw7H9kooTgEEjw.png" data-attrs="{&quot;src&quot;:&quot;https://cdn-images-1.medium.com/max/1024/1*k6eKElYjHw7H9kooTgEEjw.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://cdn-images-1.medium.com/max/1024/1*k6eKElYjHw7H9kooTgEEjw.png 424w, https://cdn-images-1.medium.com/max/1024/1*k6eKElYjHw7H9kooTgEEjw.png 848w, https://cdn-images-1.medium.com/max/1024/1*k6eKElYjHw7H9kooTgEEjw.png 1272w, https://cdn-images-1.medium.com/max/1024/1*k6eKElYjHw7H9kooTgEEjw.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Building on the work I did for my Instagram pipeline, I made a second pipeline to process these reference photos. First, a script would extract the geocoordinates from each image, using the EXIF data (<a href="https://en.wikipedia.org/wiki/Burger_King_foot_lettuce">&#8230;</a>). Then, I had Gemini take each image and return a set of pre-defined tags.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://cdn-images-1.medium.com/max/1024/1*sWz7VjNpGggmA_siEGVNGQ.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://cdn-images-1.medium.com/max/1024/1*sWz7VjNpGggmA_siEGVNGQ.png 424w, https://cdn-images-1.medium.com/max/1024/1*sWz7VjNpGggmA_siEGVNGQ.png 848w, https://cdn-images-1.medium.com/max/1024/1*sWz7VjNpGggmA_siEGVNGQ.png 1272w, https://cdn-images-1.medium.com/max/1024/1*sWz7VjNpGggmA_siEGVNGQ.png 1456w" sizes="100vw"><img src="https://cdn-images-1.medium.com/max/1024/1*sWz7VjNpGggmA_siEGVNGQ.png" data-attrs="{&quot;src&quot;:&quot;https://cdn-images-1.medium.com/max/1024/1*sWz7VjNpGggmA_siEGVNGQ.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://cdn-images-1.medium.com/max/1024/1*sWz7VjNpGggmA_siEGVNGQ.png 424w, https://cdn-images-1.medium.com/max/1024/1*sWz7VjNpGggmA_siEGVNGQ.png 848w, https://cdn-images-1.medium.com/max/1024/1*sWz7VjNpGggmA_siEGVNGQ.png 1272w, https://cdn-images-1.medium.com/max/1024/1*sWz7VjNpGggmA_siEGVNGQ.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Finally, I plotted these reference photos alongside the Whales of Yale posts on my Intelligence Map. With the help of a way to filter reference photos by tags, I had made a super powerful tool that would let me quickly sort through hundreds of reference photos.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://cdn-images-1.medium.com/max/826/1*c9yUtwglm_hDtQQzNvxL0g.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://cdn-images-1.medium.com/max/826/1*c9yUtwglm_hDtQQzNvxL0g.png 424w, https://cdn-images-1.medium.com/max/826/1*c9yUtwglm_hDtQQzNvxL0g.png 848w, https://cdn-images-1.medium.com/max/826/1*c9yUtwglm_hDtQQzNvxL0g.png 1272w, https://cdn-images-1.medium.com/max/826/1*c9yUtwglm_hDtQQzNvxL0g.png 1456w" sizes="100vw"><img src="https://cdn-images-1.medium.com/max/826/1*c9yUtwglm_hDtQQzNvxL0g.png" data-attrs="{&quot;src&quot;:&quot;https://cdn-images-1.medium.com/max/826/1*c9yUtwglm_hDtQQzNvxL0g.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://cdn-images-1.medium.com/max/826/1*c9yUtwglm_hDtQQzNvxL0g.png 424w, https://cdn-images-1.medium.com/max/826/1*c9yUtwglm_hDtQQzNvxL0g.png 848w, https://cdn-images-1.medium.com/max/826/1*c9yUtwglm_hDtQQzNvxL0g.png 1272w, https://cdn-images-1.medium.com/max/826/1*c9yUtwglm_hDtQQzNvxL0g.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://cdn-images-1.medium.com/max/1024/1*W6uxhpi_WcDzORIW_JtiyQ.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://cdn-images-1.medium.com/max/1024/1*W6uxhpi_WcDzORIW_JtiyQ.png 424w, https://cdn-images-1.medium.com/max/1024/1*W6uxhpi_WcDzORIW_JtiyQ.png 848w, https://cdn-images-1.medium.com/max/1024/1*W6uxhpi_WcDzORIW_JtiyQ.png 1272w, https://cdn-images-1.medium.com/max/1024/1*W6uxhpi_WcDzORIW_JtiyQ.png 1456w" sizes="100vw"><img src="https://cdn-images-1.medium.com/max/1024/1*W6uxhpi_WcDzORIW_JtiyQ.png" data-attrs="{&quot;src&quot;:&quot;https://cdn-images-1.medium.com/max/1024/1*W6uxhpi_WcDzORIW_JtiyQ.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://cdn-images-1.medium.com/max/1024/1*W6uxhpi_WcDzORIW_JtiyQ.png 424w, https://cdn-images-1.medium.com/max/1024/1*W6uxhpi_WcDzORIW_JtiyQ.png 848w, https://cdn-images-1.medium.com/max/1024/1*W6uxhpi_WcDzORIW_JtiyQ.png 1272w, https://cdn-images-1.medium.com/max/1024/1*W6uxhpi_WcDzORIW_JtiyQ.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h3><strong>The Catch</strong></h3><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://cdn-images-1.medium.com/max/1024/1*xeMcQhLvc1QFnyygyaCM0w.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://cdn-images-1.medium.com/max/1024/1*xeMcQhLvc1QFnyygyaCM0w.png 424w, https://cdn-images-1.medium.com/max/1024/1*xeMcQhLvc1QFnyygyaCM0w.png 848w, https://cdn-images-1.medium.com/max/1024/1*xeMcQhLvc1QFnyygyaCM0w.png 1272w, https://cdn-images-1.medium.com/max/1024/1*xeMcQhLvc1QFnyygyaCM0w.png 1456w" sizes="100vw"><img src="https://cdn-images-1.medium.com/max/1024/1*xeMcQhLvc1QFnyygyaCM0w.png" data-attrs="{&quot;src&quot;:&quot;https://cdn-images-1.medium.com/max/1024/1*xeMcQhLvc1QFnyygyaCM0w.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://cdn-images-1.medium.com/max/1024/1*xeMcQhLvc1QFnyygyaCM0w.png 424w, https://cdn-images-1.medium.com/max/1024/1*xeMcQhLvc1QFnyygyaCM0w.png 848w, https://cdn-images-1.medium.com/max/1024/1*xeMcQhLvc1QFnyygyaCM0w.png 1272w, https://cdn-images-1.medium.com/max/1024/1*xeMcQhLvc1QFnyygyaCM0w.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>The day finally came. I got the Instagram &#8220;new post&#8221; notification. The rule I set up on <a href="https://play.google.com/store/apps/details?id=com.samruston.buzzkill&amp;hl=en_US&amp;pli=1">BuzzKill for Android</a> triggered, immediately setting off an alarm. Spotted linoleum floor&#8230; concrete wall&#8230; let&#8217;s apply the&nbsp;tags.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://cdn-images-1.medium.com/max/1024/1*au5ZU-wL-8z7JJTruteUbw.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://cdn-images-1.medium.com/max/1024/1*au5ZU-wL-8z7JJTruteUbw.png 424w, https://cdn-images-1.medium.com/max/1024/1*au5ZU-wL-8z7JJTruteUbw.png 848w, https://cdn-images-1.medium.com/max/1024/1*au5ZU-wL-8z7JJTruteUbw.png 1272w, https://cdn-images-1.medium.com/max/1024/1*au5ZU-wL-8z7JJTruteUbw.png 1456w" sizes="100vw"><img src="https://cdn-images-1.medium.com/max/1024/1*au5ZU-wL-8z7JJTruteUbw.png" data-attrs="{&quot;src&quot;:&quot;https://cdn-images-1.medium.com/max/1024/1*au5ZU-wL-8z7JJTruteUbw.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://cdn-images-1.medium.com/max/1024/1*au5ZU-wL-8z7JJTruteUbw.png 424w, https://cdn-images-1.medium.com/max/1024/1*au5ZU-wL-8z7JJTruteUbw.png 848w, https://cdn-images-1.medium.com/max/1024/1*au5ZU-wL-8z7JJTruteUbw.png 1272w, https://cdn-images-1.medium.com/max/1024/1*au5ZU-wL-8z7JJTruteUbw.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Eureka! It&#8217;s a match. I sprinted to Davies, and saw the bench. Whale #210 captured!</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://cdn-images-1.medium.com/max/1024/1*OEZJVuPi-E1uH31VrFzfbQ.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://cdn-images-1.medium.com/max/1024/1*OEZJVuPi-E1uH31VrFzfbQ.png 424w, https://cdn-images-1.medium.com/max/1024/1*OEZJVuPi-E1uH31VrFzfbQ.png 848w, https://cdn-images-1.medium.com/max/1024/1*OEZJVuPi-E1uH31VrFzfbQ.png 1272w, https://cdn-images-1.medium.com/max/1024/1*OEZJVuPi-E1uH31VrFzfbQ.png 1456w" sizes="100vw"><img src="https://cdn-images-1.medium.com/max/1024/1*OEZJVuPi-E1uH31VrFzfbQ.png" data-attrs="{&quot;src&quot;:&quot;https://cdn-images-1.medium.com/max/1024/1*OEZJVuPi-E1uH31VrFzfbQ.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://cdn-images-1.medium.com/max/1024/1*OEZJVuPi-E1uH31VrFzfbQ.png 424w, https://cdn-images-1.medium.com/max/1024/1*OEZJVuPi-E1uH31VrFzfbQ.png 848w, https://cdn-images-1.medium.com/max/1024/1*OEZJVuPi-E1uH31VrFzfbQ.png 1272w, https://cdn-images-1.medium.com/max/1024/1*OEZJVuPi-E1uH31VrFzfbQ.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h3>The Hunt for the&nbsp;Capsules</h3><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://cdn-images-1.medium.com/max/1024/1*d0UPCwcc4MetZ26bYh5JDw.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://cdn-images-1.medium.com/max/1024/1*d0UPCwcc4MetZ26bYh5JDw.png 424w, https://cdn-images-1.medium.com/max/1024/1*d0UPCwcc4MetZ26bYh5JDw.png 848w, https://cdn-images-1.medium.com/max/1024/1*d0UPCwcc4MetZ26bYh5JDw.png 1272w, https://cdn-images-1.medium.com/max/1024/1*d0UPCwcc4MetZ26bYh5JDw.png 1456w" sizes="100vw"><img src="https://cdn-images-1.medium.com/max/1024/1*d0UPCwcc4MetZ26bYh5JDw.png" data-attrs="{&quot;src&quot;:&quot;https://cdn-images-1.medium.com/max/1024/1*d0UPCwcc4MetZ26bYh5JDw.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://cdn-images-1.medium.com/max/1024/1*d0UPCwcc4MetZ26bYh5JDw.png 424w, https://cdn-images-1.medium.com/max/1024/1*d0UPCwcc4MetZ26bYh5JDw.png 848w, https://cdn-images-1.medium.com/max/1024/1*d0UPCwcc4MetZ26bYh5JDw.png 1272w, https://cdn-images-1.medium.com/max/1024/1*d0UPCwcc4MetZ26bYh5JDw.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>As this was the second Veritas Search, I knew some of the tricks the puzzle creators liked to pull. Last year, there were various hidden clues buried around the different pages of the website. Also, don&#8217;t forget the cryptic pointers posted on the hints&nbsp;page.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://cdn-images-1.medium.com/max/1024/1*B4nHvMMb1IauhYEispvEDg.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://cdn-images-1.medium.com/max/1024/1*B4nHvMMb1IauhYEispvEDg.png 424w, https://cdn-images-1.medium.com/max/1024/1*B4nHvMMb1IauhYEispvEDg.png 848w, https://cdn-images-1.medium.com/max/1024/1*B4nHvMMb1IauhYEispvEDg.png 1272w, https://cdn-images-1.medium.com/max/1024/1*B4nHvMMb1IauhYEispvEDg.png 1456w" sizes="100vw"><img src="https://cdn-images-1.medium.com/max/1024/1*B4nHvMMb1IauhYEispvEDg.png" data-attrs="{&quot;src&quot;:&quot;https://cdn-images-1.medium.com/max/1024/1*B4nHvMMb1IauhYEispvEDg.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://cdn-images-1.medium.com/max/1024/1*B4nHvMMb1IauhYEispvEDg.png 424w, https://cdn-images-1.medium.com/max/1024/1*B4nHvMMb1IauhYEispvEDg.png 848w, https://cdn-images-1.medium.com/max/1024/1*B4nHvMMb1IauhYEispvEDg.png 1272w, https://cdn-images-1.medium.com/max/1024/1*B4nHvMMb1IauhYEispvEDg.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>At this point, I knew what I needed to do. I vibe-coded a bash script that scrapes the HTML page, parses out the filepath of the associated JS script, downloads all JS assets, and sends me a Discord message when there is a change to the website&nbsp;code.</p><p>The website seemed to be made in React, so the bundled code was unfortunately obfuscated and minified. This didn&#8217;t pose a problem to me, though. Using the built-in bash diff command, I was able to have the <em>difference</em>&#8202;&#8212;&#8202;only the lines that changed&#8202;&#8212;&#8202;sent to me in the Discord message&nbsp;body.</p><p>I set up a cronjob to run the script every 15 minutes, awaiting any changes to the website; the sort of &#8220;set it and forget it&#8221; kind of&nbsp;deal.</p><p>I spent a few days getting the occasional ping. Sometimes, it would simply alert me of someone new being added to the winners page. Sometimes, it told me that a new clue was added to the hints page, which gave me an immense advantage over the people who had to manually refresh the page whenever they felt like checking.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://cdn-images-1.medium.com/max/1024/1*58PMigUFtEyRoz97Np-PJw.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://cdn-images-1.medium.com/max/1024/1*58PMigUFtEyRoz97Np-PJw.png 424w, https://cdn-images-1.medium.com/max/1024/1*58PMigUFtEyRoz97Np-PJw.png 848w, https://cdn-images-1.medium.com/max/1024/1*58PMigUFtEyRoz97Np-PJw.png 1272w, https://cdn-images-1.medium.com/max/1024/1*58PMigUFtEyRoz97Np-PJw.png 1456w" sizes="100vw"><img src="https://cdn-images-1.medium.com/max/1024/1*58PMigUFtEyRoz97Np-PJw.png" data-attrs="{&quot;src&quot;:&quot;https://cdn-images-1.medium.com/max/1024/1*58PMigUFtEyRoz97Np-PJw.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://cdn-images-1.medium.com/max/1024/1*58PMigUFtEyRoz97Np-PJw.png 424w, https://cdn-images-1.medium.com/max/1024/1*58PMigUFtEyRoz97Np-PJw.png 848w, https://cdn-images-1.medium.com/max/1024/1*58PMigUFtEyRoz97Np-PJw.png 1272w, https://cdn-images-1.medium.com/max/1024/1*58PMigUFtEyRoz97Np-PJw.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>I was able to decipher some of the hints fairly quickly, but my general lack of athleticism made it so that I couldn&#8217;t run to the hiding spots fast enough. (I was even chased down by a wide-eyed sophomore on a bike&nbsp;once.)</p><p>But then, the day came. I was alerted to an unusual diff; usually, the changes made to the website were only a few lines long, and usually pertained to the hints page or the winners page. This one seemed different. Why was the blurb on the home page being&nbsp;updated?</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://cdn-images-1.medium.com/max/1024/1*RQwHgZgWCh-FjFkJeXLUMg.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://cdn-images-1.medium.com/max/1024/1*RQwHgZgWCh-FjFkJeXLUMg.png 424w, https://cdn-images-1.medium.com/max/1024/1*RQwHgZgWCh-FjFkJeXLUMg.png 848w, https://cdn-images-1.medium.com/max/1024/1*RQwHgZgWCh-FjFkJeXLUMg.png 1272w, https://cdn-images-1.medium.com/max/1024/1*RQwHgZgWCh-FjFkJeXLUMg.png 1456w" sizes="100vw"><img src="https://cdn-images-1.medium.com/max/1024/1*RQwHgZgWCh-FjFkJeXLUMg.png" data-attrs="{&quot;src&quot;:&quot;https://cdn-images-1.medium.com/max/1024/1*RQwHgZgWCh-FjFkJeXLUMg.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://cdn-images-1.medium.com/max/1024/1*RQwHgZgWCh-FjFkJeXLUMg.png 424w, https://cdn-images-1.medium.com/max/1024/1*RQwHgZgWCh-FjFkJeXLUMg.png 848w, https://cdn-images-1.medium.com/max/1024/1*RQwHgZgWCh-FjFkJeXLUMg.png 1272w, https://cdn-images-1.medium.com/max/1024/1*RQwHgZgWCh-FjFkJeXLUMg.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://cdn-images-1.medium.com/max/1024/1*5m4BA2-j_n_0GjqqPGcdYA.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://cdn-images-1.medium.com/max/1024/1*5m4BA2-j_n_0GjqqPGcdYA.png 424w, https://cdn-images-1.medium.com/max/1024/1*5m4BA2-j_n_0GjqqPGcdYA.png 848w, https://cdn-images-1.medium.com/max/1024/1*5m4BA2-j_n_0GjqqPGcdYA.png 1272w, https://cdn-images-1.medium.com/max/1024/1*5m4BA2-j_n_0GjqqPGcdYA.png 1456w" sizes="100vw"><img src="https://cdn-images-1.medium.com/max/1024/1*5m4BA2-j_n_0GjqqPGcdYA.png" data-attrs="{&quot;src&quot;:&quot;https://cdn-images-1.medium.com/max/1024/1*5m4BA2-j_n_0GjqqPGcdYA.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://cdn-images-1.medium.com/max/1024/1*5m4BA2-j_n_0GjqqPGcdYA.png 424w, https://cdn-images-1.medium.com/max/1024/1*5m4BA2-j_n_0GjqqPGcdYA.png 848w, https://cdn-images-1.medium.com/max/1024/1*5m4BA2-j_n_0GjqqPGcdYA.png 1272w, https://cdn-images-1.medium.com/max/1024/1*5m4BA2-j_n_0GjqqPGcdYA.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Upon further inspection, I saw some strange code in the HTML source. Individual letters, spelling out &#8220;STOECKEL&#8221;, were put in their own&nbsp;tags!</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://cdn-images-1.medium.com/max/1024/1*VAg-hGIqUlalDzkJYJct6A.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://cdn-images-1.medium.com/max/1024/1*VAg-hGIqUlalDzkJYJct6A.png 424w, https://cdn-images-1.medium.com/max/1024/1*VAg-hGIqUlalDzkJYJct6A.png 848w, https://cdn-images-1.medium.com/max/1024/1*VAg-hGIqUlalDzkJYJct6A.png 1272w, https://cdn-images-1.medium.com/max/1024/1*VAg-hGIqUlalDzkJYJct6A.png 1456w" sizes="100vw"><img src="https://cdn-images-1.medium.com/max/1024/1*VAg-hGIqUlalDzkJYJct6A.png" data-attrs="{&quot;src&quot;:&quot;https://cdn-images-1.medium.com/max/1024/1*VAg-hGIqUlalDzkJYJct6A.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://cdn-images-1.medium.com/max/1024/1*VAg-hGIqUlalDzkJYJct6A.png 424w, https://cdn-images-1.medium.com/max/1024/1*VAg-hGIqUlalDzkJYJct6A.png 848w, https://cdn-images-1.medium.com/max/1024/1*VAg-hGIqUlalDzkJYJct6A.png 1272w, https://cdn-images-1.medium.com/max/1024/1*VAg-hGIqUlalDzkJYJct6A.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Knowing this referenced Stoeckel Hall (the home of my 9AM music class), I sprinted down Elm St in the rain and searched all over the building. Eventually, I found the capsule tucked away underneath the emergency staircase.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://cdn-images-1.medium.com/max/1024/1*AOWboyqsRKC_NxZpUOD9OA.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://cdn-images-1.medium.com/max/1024/1*AOWboyqsRKC_NxZpUOD9OA.jpeg 424w, https://cdn-images-1.medium.com/max/1024/1*AOWboyqsRKC_NxZpUOD9OA.jpeg 848w, https://cdn-images-1.medium.com/max/1024/1*AOWboyqsRKC_NxZpUOD9OA.jpeg 1272w, https://cdn-images-1.medium.com/max/1024/1*AOWboyqsRKC_NxZpUOD9OA.jpeg 1456w" sizes="100vw"><img src="https://cdn-images-1.medium.com/max/1024/1*AOWboyqsRKC_NxZpUOD9OA.jpeg" data-attrs="{&quot;src&quot;:&quot;https://cdn-images-1.medium.com/max/1024/1*AOWboyqsRKC_NxZpUOD9OA.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://cdn-images-1.medium.com/max/1024/1*AOWboyqsRKC_NxZpUOD9OA.jpeg 424w, https://cdn-images-1.medium.com/max/1024/1*AOWboyqsRKC_NxZpUOD9OA.jpeg 848w, https://cdn-images-1.medium.com/max/1024/1*AOWboyqsRKC_NxZpUOD9OA.jpeg 1272w, https://cdn-images-1.medium.com/max/1024/1*AOWboyqsRKC_NxZpUOD9OA.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>I later learned that the intended solution related to the hint published on that same day: &#8220;Patience is a virtue. Over the view lies the clue.&#8221; Normal seekers were intended to wait 15 seconds on the home page before each highlighted letter would change color. However, with my diff alerter, I bypassed this element of the puzzle altogether!</p><p>With two scavenger hunts conquered, the only thing left for me is to decide what I want to ask Mark&nbsp;Cuban.</p><p><em>This article was originally published on the <a href="https://yalecomputersociety.org/blog/scavenger-hunt">Yale Computer Society blog</a>. Happy&nbsp;hunting!</em></p>]]></content:encoded></item><item><title><![CDATA[Building Unity Games for the Windows Store: The Ultimate Guide]]></title><description><![CDATA[By now, you might&#8217;ve published your game on the MacOS App Store after reading my handy tutorial. Or, you may already be distributing your game for Windows on Steam after learning about it in my guide. Now, it&#8217;s time to publish our games on the Windows Store!]]></description><link>https://blog.yoonicode.com/p/building-unity-games-for-the-windows-store-the-ultimate-guide-8dde6c74e8cb</link><guid isPermaLink="false">https://blog.yoonicode.com/p/building-unity-games-for-the-windows-store-the-ultimate-guide-8dde6c74e8cb</guid><dc:creator><![CDATA[Eric Yoon]]></dc:creator><pubDate>Fri, 17 Oct 2025 07:28:56 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!W88a!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9f7bc88-b7ed-4bfe-aa88-76b84c1d91f4_2000x1160.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!W88a!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9f7bc88-b7ed-4bfe-aa88-76b84c1d91f4_2000x1160.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!W88a!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9f7bc88-b7ed-4bfe-aa88-76b84c1d91f4_2000x1160.jpeg 424w, https://substackcdn.com/image/fetch/$s_!W88a!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9f7bc88-b7ed-4bfe-aa88-76b84c1d91f4_2000x1160.jpeg 848w, https://substackcdn.com/image/fetch/$s_!W88a!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9f7bc88-b7ed-4bfe-aa88-76b84c1d91f4_2000x1160.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!W88a!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9f7bc88-b7ed-4bfe-aa88-76b84c1d91f4_2000x1160.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!W88a!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9f7bc88-b7ed-4bfe-aa88-76b84c1d91f4_2000x1160.jpeg" width="1456" height="844" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e9f7bc88-b7ed-4bfe-aa88-76b84c1d91f4_2000x1160.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:844,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Unity Editor Software Terms Update: Runtime Fee Cancellation | Unity Blog&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Unity Editor Software Terms Update: Runtime Fee Cancellation | Unity Blog" title="Unity Editor Software Terms Update: Runtime Fee Cancellation | Unity Blog" srcset="https://substackcdn.com/image/fetch/$s_!W88a!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9f7bc88-b7ed-4bfe-aa88-76b84c1d91f4_2000x1160.jpeg 424w, https://substackcdn.com/image/fetch/$s_!W88a!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9f7bc88-b7ed-4bfe-aa88-76b84c1d91f4_2000x1160.jpeg 848w, https://substackcdn.com/image/fetch/$s_!W88a!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9f7bc88-b7ed-4bfe-aa88-76b84c1d91f4_2000x1160.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!W88a!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9f7bc88-b7ed-4bfe-aa88-76b84c1d91f4_2000x1160.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>By now, you might&#8217;ve published your game on the MacOS App Store after reading my <a href="https://medium.com/@yoonicode/building-unity-apps-to-macos-the-ultimate-guide-6d13ca2d84d0">handy tutorial</a>. Or, you may already be distributing your game for Windows on Steam after learning about it in <a href="https://medium.com/@yoonicode/publishing-unity-games-on-steam-the-ultimate-guide-5e09fc812c65">my guide</a>. Now, it&#8217;s time to publish our games on the Windows&nbsp;Store!</p><h3>Introductory Knowledge</h3><p>First, note that modern Windows Store apps run on the Universal Windows Platform (UWP). Gone are the days of building an&nbsp;.exe file for each architecture (x86, x64, ARM). Now, you can build one binary with all app versions included, and the Windows Store will automatically download the right one! Since this is such an improvement over the old way of doing things, the Windows Store <em>requires</em> all new app submissions to be UWP-compatible. This means we&#8217;ll have to build for UWP from Unity. This also means you <em>must</em> develop on a Windows machine to be able to publish for Windows Store, since there is no UWP build support from Unity for Mac or&nbsp;Linux.</p><h3>Prerequisites</h3><p>You&#8217;ll need a Microsoft Partner Center account. You need to also have made an Entra ID account, and have made that Entra ID account a tenant in your Partner Center account. (Entra ID = &#8220;work or school account&#8221;, which is distinct from your personal Microsoft account.)</p><p>You&#8217;ll also need Visual Studio for Windows, along with the Windows SDK installed.</p><h3>Building from&nbsp;Unity</h3><p>First, switch your platform to Universal Windows Platform in&nbsp;Unity.</p><p>In the <strong>Player</strong> tab under <strong>Project Settings</strong>, create a test certificate. Specify a password. (Note that this certificate is only used for local debugging; when you associate your app with the Windows Store, it will get replaced.)</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-jYk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F574a4095-3a77-41b8-8210-469a506e3ebc_697x208.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-jYk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F574a4095-3a77-41b8-8210-469a506e3ebc_697x208.png 424w, https://substackcdn.com/image/fetch/$s_!-jYk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F574a4095-3a77-41b8-8210-469a506e3ebc_697x208.png 848w, https://substackcdn.com/image/fetch/$s_!-jYk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F574a4095-3a77-41b8-8210-469a506e3ebc_697x208.png 1272w, https://substackcdn.com/image/fetch/$s_!-jYk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F574a4095-3a77-41b8-8210-469a506e3ebc_697x208.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-jYk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F574a4095-3a77-41b8-8210-469a506e3ebc_697x208.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/574a4095-3a77-41b8-8210-469a506e3ebc_697x208.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!-jYk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F574a4095-3a77-41b8-8210-469a506e3ebc_697x208.png 424w, https://substackcdn.com/image/fetch/$s_!-jYk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F574a4095-3a77-41b8-8210-469a506e3ebc_697x208.png 848w, https://substackcdn.com/image/fetch/$s_!-jYk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F574a4095-3a77-41b8-8210-469a506e3ebc_697x208.png 1272w, https://substackcdn.com/image/fetch/$s_!-jYk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F574a4095-3a77-41b8-8210-469a506e3ebc_697x208.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Important: locate your newly-generated&nbsp;.pfx file and double-click it! This will install it in your Windows credential store.</p><p>In Build Settings (Ctrl+Shift+B), make sure <strong>build configuration</strong> is set to Master&#8221;; set <strong>architecture</strong> to whatever architecture your development machine is using. (We&#8217;ll be able to build binaries for other architectures later!) Also make sure <strong>development build</strong> is unchecked.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cO1Y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2eaf05-b6b9-43d4-854d-bde593b241ff_1024x861.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cO1Y!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2eaf05-b6b9-43d4-854d-bde593b241ff_1024x861.png 424w, https://substackcdn.com/image/fetch/$s_!cO1Y!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2eaf05-b6b9-43d4-854d-bde593b241ff_1024x861.png 848w, https://substackcdn.com/image/fetch/$s_!cO1Y!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2eaf05-b6b9-43d4-854d-bde593b241ff_1024x861.png 1272w, https://substackcdn.com/image/fetch/$s_!cO1Y!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2eaf05-b6b9-43d4-854d-bde593b241ff_1024x861.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cO1Y!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2eaf05-b6b9-43d4-854d-bde593b241ff_1024x861.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8f2eaf05-b6b9-43d4-854d-bde593b241ff_1024x861.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!cO1Y!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2eaf05-b6b9-43d4-854d-bde593b241ff_1024x861.png 424w, https://substackcdn.com/image/fetch/$s_!cO1Y!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2eaf05-b6b9-43d4-854d-bde593b241ff_1024x861.png 848w, https://substackcdn.com/image/fetch/$s_!cO1Y!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2eaf05-b6b9-43d4-854d-bde593b241ff_1024x861.png 1272w, https://substackcdn.com/image/fetch/$s_!cO1Y!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2eaf05-b6b9-43d4-854d-bde593b241ff_1024x861.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Now, build your project! The resulting artifacts will be a Visual Studio solution. At this point, make sure you have the latest version of Visual Studio for Windows installed. (The free version is&nbsp;fine.)</p><h3>Testing your Project in Visual&nbsp;Studio</h3><p>Let&#8217;s make sure our binary works on our own machine before submitting to the&nbsp;Store.</p><p>First, we have to take care of a <a href="https://stackoverflow.com/a/60600054/4699945">known issue</a>. Open the&nbsp;.vcxproj file in Notepad. Delete the &lt;ItemGroup&gt; element which contains an &lt;SDKReference&gt; to WindowsMobile&nbsp;.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Vu6g!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1c60514-2404-46a5-92de-0816d39c056a_1024x462.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Vu6g!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1c60514-2404-46a5-92de-0816d39c056a_1024x462.png 424w, https://substackcdn.com/image/fetch/$s_!Vu6g!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1c60514-2404-46a5-92de-0816d39c056a_1024x462.png 848w, https://substackcdn.com/image/fetch/$s_!Vu6g!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1c60514-2404-46a5-92de-0816d39c056a_1024x462.png 1272w, https://substackcdn.com/image/fetch/$s_!Vu6g!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1c60514-2404-46a5-92de-0816d39c056a_1024x462.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Vu6g!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1c60514-2404-46a5-92de-0816d39c056a_1024x462.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a1c60514-2404-46a5-92de-0816d39c056a_1024x462.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!Vu6g!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1c60514-2404-46a5-92de-0816d39c056a_1024x462.png 424w, https://substackcdn.com/image/fetch/$s_!Vu6g!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1c60514-2404-46a5-92de-0816d39c056a_1024x462.png 848w, https://substackcdn.com/image/fetch/$s_!Vu6g!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1c60514-2404-46a5-92de-0816d39c056a_1024x462.png 1272w, https://substackcdn.com/image/fetch/$s_!Vu6g!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1c60514-2404-46a5-92de-0816d39c056a_1024x462.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Now you can open the&nbsp;.sln file that was built by&nbsp;Unity.</p><p>We&#8217;ll need to tell Visual Studio to use the testing certificate we generated. In your Solution Explorer, open the Package.appxmanifest file. Under <strong>Packaging</strong>, select <strong>Choose Certificate</strong>. Navigate to the certificate you created and enter the password.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xKvh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72adf0ea-4745-4e41-ac79-07c64ab8c0f5_1024x647.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xKvh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72adf0ea-4745-4e41-ac79-07c64ab8c0f5_1024x647.png 424w, https://substackcdn.com/image/fetch/$s_!xKvh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72adf0ea-4745-4e41-ac79-07c64ab8c0f5_1024x647.png 848w, https://substackcdn.com/image/fetch/$s_!xKvh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72adf0ea-4745-4e41-ac79-07c64ab8c0f5_1024x647.png 1272w, https://substackcdn.com/image/fetch/$s_!xKvh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72adf0ea-4745-4e41-ac79-07c64ab8c0f5_1024x647.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xKvh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72adf0ea-4745-4e41-ac79-07c64ab8c0f5_1024x647.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/72adf0ea-4745-4e41-ac79-07c64ab8c0f5_1024x647.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!xKvh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72adf0ea-4745-4e41-ac79-07c64ab8c0f5_1024x647.png 424w, https://substackcdn.com/image/fetch/$s_!xKvh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72adf0ea-4745-4e41-ac79-07c64ab8c0f5_1024x647.png 848w, https://substackcdn.com/image/fetch/$s_!xKvh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72adf0ea-4745-4e41-ac79-07c64ab8c0f5_1024x647.png 1272w, https://substackcdn.com/image/fetch/$s_!xKvh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72adf0ea-4745-4e41-ac79-07c64ab8c0f5_1024x647.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>In your solution view, set the configuration to <strong>Master</strong> and set the platform to whatever architecture your development machine uses. Click <strong>Start without debugging</strong> (the hollow green triangle).</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Xi9I!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd65cb9c4-6118-4b0f-b8c0-2fe09388b2dd_1024x308.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Xi9I!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd65cb9c4-6118-4b0f-b8c0-2fe09388b2dd_1024x308.png 424w, https://substackcdn.com/image/fetch/$s_!Xi9I!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd65cb9c4-6118-4b0f-b8c0-2fe09388b2dd_1024x308.png 848w, https://substackcdn.com/image/fetch/$s_!Xi9I!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd65cb9c4-6118-4b0f-b8c0-2fe09388b2dd_1024x308.png 1272w, https://substackcdn.com/image/fetch/$s_!Xi9I!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd65cb9c4-6118-4b0f-b8c0-2fe09388b2dd_1024x308.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Xi9I!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd65cb9c4-6118-4b0f-b8c0-2fe09388b2dd_1024x308.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d65cb9c4-6118-4b0f-b8c0-2fe09388b2dd_1024x308.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!Xi9I!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd65cb9c4-6118-4b0f-b8c0-2fe09388b2dd_1024x308.png 424w, https://substackcdn.com/image/fetch/$s_!Xi9I!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd65cb9c4-6118-4b0f-b8c0-2fe09388b2dd_1024x308.png 848w, https://substackcdn.com/image/fetch/$s_!Xi9I!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd65cb9c4-6118-4b0f-b8c0-2fe09388b2dd_1024x308.png 1272w, https://substackcdn.com/image/fetch/$s_!Xi9I!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd65cb9c4-6118-4b0f-b8c0-2fe09388b2dd_1024x308.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h3>Publishing to the&nbsp;Store</h3><p>If your game works locally when run through Visual Studio, it&#8217;s time to publish a package to the&nbsp;Store.</p><p>First, let Visual Studio know that your app is associated with a Windows Store product. Right click on your UWP project (<em>not</em> the solution&#8212;it should have the &#8220;++&#8221; icon.) Go to <strong>Publish</strong> &#8594; <strong>Associate App with the&nbsp;Store</strong>.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7trj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F760a15e4-309f-4e39-9cb7-edcc317cccff_953x1439.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7trj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F760a15e4-309f-4e39-9cb7-edcc317cccff_953x1439.png 424w, https://substackcdn.com/image/fetch/$s_!7trj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F760a15e4-309f-4e39-9cb7-edcc317cccff_953x1439.png 848w, https://substackcdn.com/image/fetch/$s_!7trj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F760a15e4-309f-4e39-9cb7-edcc317cccff_953x1439.png 1272w, https://substackcdn.com/image/fetch/$s_!7trj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F760a15e4-309f-4e39-9cb7-edcc317cccff_953x1439.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7trj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F760a15e4-309f-4e39-9cb7-edcc317cccff_953x1439.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/760a15e4-309f-4e39-9cb7-edcc317cccff_953x1439.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!7trj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F760a15e4-309f-4e39-9cb7-edcc317cccff_953x1439.png 424w, https://substackcdn.com/image/fetch/$s_!7trj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F760a15e4-309f-4e39-9cb7-edcc317cccff_953x1439.png 848w, https://substackcdn.com/image/fetch/$s_!7trj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F760a15e4-309f-4e39-9cb7-edcc317cccff_953x1439.png 1272w, https://substackcdn.com/image/fetch/$s_!7trj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F760a15e4-309f-4e39-9cb7-edcc317cccff_953x1439.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><strong>Important: log in with your Entra ID tenant account, not your personal Microsoft account!</strong></p><p>Right-click on your project again; go to <strong>Publish</strong> &#8594; <strong>Create App Packages</strong>. Select <strong>Microsoft Store as &lt;your app&nbsp;name&gt;</strong>.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SOnP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc58aa79-1096-4bdb-8f83-1719e4ad9c4e_1024x879.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SOnP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc58aa79-1096-4bdb-8f83-1719e4ad9c4e_1024x879.png 424w, https://substackcdn.com/image/fetch/$s_!SOnP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc58aa79-1096-4bdb-8f83-1719e4ad9c4e_1024x879.png 848w, https://substackcdn.com/image/fetch/$s_!SOnP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc58aa79-1096-4bdb-8f83-1719e4ad9c4e_1024x879.png 1272w, https://substackcdn.com/image/fetch/$s_!SOnP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc58aa79-1096-4bdb-8f83-1719e4ad9c4e_1024x879.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SOnP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc58aa79-1096-4bdb-8f83-1719e4ad9c4e_1024x879.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fc58aa79-1096-4bdb-8f83-1719e4ad9c4e_1024x879.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!SOnP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc58aa79-1096-4bdb-8f83-1719e4ad9c4e_1024x879.png 424w, https://substackcdn.com/image/fetch/$s_!SOnP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc58aa79-1096-4bdb-8f83-1719e4ad9c4e_1024x879.png 848w, https://substackcdn.com/image/fetch/$s_!SOnP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc58aa79-1096-4bdb-8f83-1719e4ad9c4e_1024x879.png 1272w, https://substackcdn.com/image/fetch/$s_!SOnP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc58aa79-1096-4bdb-8f83-1719e4ad9c4e_1024x879.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Set &#8220;generate app bundle&#8221; to <strong>Always</strong>, to let Visual Studio know to combine your three architectures into one file. <strong>Deselect </strong>ARM (32-bit) support since the latest versions of the Windows SDK do not support it. You may also want to <em>check, then uncheck</em> ARM64 build support (see this <a href="https://developercommunity.visualstudio.com/t/get-merge-failure-for-shared-where-merged-pri-file-0x800/107928#T-N869169">bug&nbsp;report</a>).</p><p>Once your bundle finishes building, run the Windows App Certification Kit tester. Don&#8217;t worry if the tests don&#8217;t pass&#8212;this might just be indicative of quirks on your local machine, and your submission should get through app review just&nbsp;fine.</p><p>Upload the generated unified&nbsp;.msixupload file via the web interface in the Microsoft Partner Center. You&#8217;re&nbsp;done!</p><h3>Troubleshooting</h3><p>Here are some common issues I&#8217;ve found while building to&nbsp;Windows.</p><ul><li><p>&#8220;Unable to start debugging&#8221;: right click on the C++ project; go to Configuration Properties &#8594; Debugging &#8594; selectg Local Windows Debugger. (<a href="https://stackoverflow.com/questions/51937590/cannot-debug-in-vs2017-with-windows-10/51943304#51943304">SO</a>)</p></li><li><p>&#8220;GameAssembly.dll is not a valid Win32 Application&#8221;: in Solution Explorer, right click your C++ project and click &#8220;set as startup project&#8221;. (<a href="https://forum.unity.com/threads/uwp-build-and-debug-on-windows-11-arm64-in-parallels-m1-mac.1233163/">Unity&nbsp;Forums</a>)</p></li></ul><p>Hope this guide helps. Check out my games at <a href="https://yoonicode.com">yoonicode.com</a>!</p>]]></content:encoded></item><item><title><![CDATA[Regarding AI]]></title><description><![CDATA[As a lurker in the tech-adjacent part of the Internet, I can&#8217;t seem to catch a break from reading takes on AI.]]></description><link>https://blog.yoonicode.com/p/regarding-ai-80102679f939</link><guid isPermaLink="false">https://blog.yoonicode.com/p/regarding-ai-80102679f939</guid><dc:creator><![CDATA[Eric Yoon]]></dc:creator><pubDate>Tue, 17 Jun 2025 04:05:11 GMT</pubDate><enclosure url="https://cdn-images-1.medium.com/max/960/0*L21NFxqjBkXHUYzt" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://cdn-images-1.medium.com/max/960/0*L21NFxqjBkXHUYzt" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://cdn-images-1.medium.com/max/960/0*L21NFxqjBkXHUYzt 424w, https://cdn-images-1.medium.com/max/960/0*L21NFxqjBkXHUYzt 848w, https://cdn-images-1.medium.com/max/960/0*L21NFxqjBkXHUYzt 1272w, https://cdn-images-1.medium.com/max/960/0*L21NFxqjBkXHUYzt 1456w" sizes="100vw"><img src="https://cdn-images-1.medium.com/max/960/0*L21NFxqjBkXHUYzt" data-attrs="{&quot;src&quot;:&quot;https://cdn-images-1.medium.com/max/960/0*L21NFxqjBkXHUYzt&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://cdn-images-1.medium.com/max/960/0*L21NFxqjBkXHUYzt 424w, https://cdn-images-1.medium.com/max/960/0*L21NFxqjBkXHUYzt 848w, https://cdn-images-1.medium.com/max/960/0*L21NFxqjBkXHUYzt 1272w, https://cdn-images-1.medium.com/max/960/0*L21NFxqjBkXHUYzt 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a><figcaption class="image-caption">A functional diagram of a ResNet, an innovation that powered the shift towards transformers. CC BY-SA&nbsp;4.0</figcaption></figure></div><p>As a lurker in the tech-adjacent part of the Internet, I can&#8217;t seem to catch a break from reading takes on AI. I&#8217;ve heard it all, ranging from the perspectives of artists and creatives to the hot takes of L5 MANGA SWEs. Now feels like the right time to offer yet another take&#8212;if only so I can look back in 5 years and laugh at how much I got&nbsp;wrong.</p><h4>Regarding Bubbles</h4><p>When a new piece of technology comes out, perhaps the most important question to ask is: &#8220;is this a bubble?&#8221;. While it may seem obvious in hindsight, it&#8217;s incredibly difficult to tell in the moment, despite the efforts of many (financially) interested parties. Perhaps a few years ago, crypto was seen as the hot new thing&#8212;yet most would agree that it was a bubble and is largely irrelevant nowadays, with the exception of some niche applications far from the widespread use cases championed by crypto evangelists. The fate of virtual reality, a similarly-hyped technology, has yet to be determined. Generative AI seems somehow distinct from the former two examples; it seems to fit more in the category of &#8220;steam engine&#8221; and &#8220;World Wide Web&#8221; rather than the likes of &#8220;Non-Fungible Token.&#8221;</p><p>I think a distinction is necessary between the developers of foundation models and the secondary/tertiary repackagers of generative AI. Though they are far from profitable, I do not see OpenAI, Google, or Anthropic going away any time soon. However, my prognosis of &#8220;B2B SaaS&#8221; companies like Cursor, Windsurf, or the viral Cluely (to use a humorous example) is not very positive. &#8220;ChatGPT wrappers&#8221; are a dime-a-dozen and offer little to no added&nbsp;value.</p><p>Let&#8217;s <em>delve</em> into my example of Cursor. While definitely a novel technology, Cursor offers few features that any other company couldn&#8217;t immediately clone. In fact, as someone who never made the jump to Cursor from Microsoft&#8217;s Visual Studio Code, I&#8217;ve personally watched VSCode catch up to Cursor in only a few months. Given that Cursor is a fork of VSCode, this seems like a classic example of Microsoft&#8217;s not-so-secret strategy: <em>embrace, extend, extinguish</em>.</p><p>ChatGPT wrappers are simply too easy to create that I seriously doubt the long-term viability of such companies. On the other hand, OpenAI, Google, and Anthropic&#8217;s value proposition is not one that any company can create overnight. The high costs of training a sufficiently large model creates massive barriers to entry that small companies simply can&#8217;t compete with, which is precisely the reason why I think they&#8217;ll be sticking around. But these same barriers to entry represent some of my largest fears about&nbsp;AI.</p><h4>Regarding Barriers to&nbsp;Entry</h4><p>It&#8217;s easy to understate the power of the open-source software community. To my knowledge, no other industry has such an amazing implicit agreement and expectation of collaboration above profit. For example, Meta decided to open-source React, giving us the most powerful web framework ever made; Google decided to open-source Chromium, giving us Electron apps like Slack and VSCode; and hobbyist devs contribute to libraries like <em>ffmpeg</em> and <em>tz</em>, which hold up modern computing as we know it. I see foundation models as a threat to this open-source ecosystem.</p><p>Perhaps open-source software flourished because code is inherently democratizing. As long as you have a <em>good enough</em> machine, you can run any piece of software. This suddenly becomes untrue as soon as we introduce compute-heavy tasks like training, or even running, a foundation model. Although open-source, local models exist, none will ever come close to the power of OpenAI, Google, or Anthropic and their GPU farms. If AI is truly the next big step in our tech tree, gone are the days of cloning a repo and running it on your own machine. If you want to do anything with powerful AI, get ready to enter your credit card information&#8212;and make sure to stay on OpenAI&#8217;s good&nbsp;side.</p><p>Perhaps I&#8217;ll end this section with an appeal to emotion. Think of any other industry with high barriers to entry in your life. What&#8217;s your general sentiment towards cell service providers? How about airlines? That&#8217;s what AI will be like in a few&nbsp;years.</p><h4>Regarding AI Taking Our&nbsp;Jobs</h4><p>With the risk of sounding like a detached economist, blissfully unaware of the very real lives of actual laborers, I generally am unconcerned with &#8220;AI taking our jobs.&#8221; As a probable future software engineer, I&#8217;m definitely in the crosshairs. But to create policy based on the fear of AI replacing human labor is misguided.</p><p>Although I generally reject the premises of Laissez-Faire ideology, I do think there&#8217;s some truth in the saying <em>a rising tide lifts all boats</em>, albeit with a slightly different interpretation than originally intended. Technology is the rising tide. The Industrial Revolution eliminated dangerous manual labor positions, yet introduced many more jobs that were before unseen. (Although perhaps not less dangerous.) The invention of the computer eliminated plenty of administrative desk jobs, yet created entire industries of IT and software. It may be the case that AI will take jobs, but such is a &#8220;necessary evil&#8221; in the progression of society. People will become more educated and more will be well-equipped for the jobs that AI creates. Holding back AI because of the loss of jobs will slow down the creation of new ones&#8212;jobs that contribute more to&nbsp;society.</p><p>Although we&#8217;re still a ways away from this utopia, the ideal end goal of this progression of technology is the replacement of <em>all</em> jobs that only exist out of necessity. Just like computers [sense 1] were replaced with computers [sense 2], doctors and lawyers will be made unnecessary, freeing up time for humans to do what they were always meant to do: create&nbsp;art.</p><h4>Regarding Computers Making&nbsp;Art</h4><p>Speaking of making art, a new cultural divide is emerging between creatives and technologists. Can a computer create art? <em>Should</em> a computer create art? My position is still forming, so I will instead offer a series of questions.</p><ul><li><p>Is the invention of image-generating AI different than the invention of the camera? What did people think when the camera was invented, and how does that mirror/differ from the sentiment towards image-generating AI&nbsp;now?</p></li><li><p>What is the human brain other than a computer that takes inputs, combines them with memory of previously-seen works (commonly known as &#8220;inspiration&#8221;), and produces&nbsp;outputs?</p></li><li><p>Is an art piece&#8217;s value based solely off of how good it looks, or is there some other mushy factor that gives it&nbsp;worth?</p></li><li><p>Can a computer&nbsp;feel?</p></li></ul><p>Perhaps this discussion is gratuitous. Perhaps &#8220;computers making art&#8221; will be a short-lived fad, overshadowed by something much more impactful, yet much less talked&nbsp;about&#8230;</p><h4>Regarding Non-Generative AI</h4><p>I think recent advances in non-generative AI has largely flown under the radar. Amazing breakthroughs are being made in medical and scientific industries. Have you heard the latest about protein folding or cancer classification? These advances are what is going to drive forward technology and society, not &#8220;Ghibli filter&#8221;&nbsp;bots.</p><h4>Regarding The End of&nbsp;AI</h4><p>Many people point to the exponential curve of AI ability and assert that progress will never slow down. While I&#8217;m not certain, I believe AI development will reach an asymptote due to <em>model collapse</em>.</p><p>Garbage in, garbage out. AI output is being put on the Internet en masse, with no real way to tell whether a piece of content is human&#8211; or AI&#8211;generated. As we all know, large-data models necessitate huge amounts of training data, scraped from Reddit and the likes. But what if Reddit is all AI content in the first place? Studies have shown that training AI on AI output does not improve it. It may be the case that we are approaching the maximum capacity of AI, unless we can solve the Dead Internet&nbsp;problem.</p><h4>Conclusion</h4><p>I&#8217;d love to hear your thoughts, especially if you are deeply immersed in the field of AI. Reach out: eric@yoonicode.com</p>]]></content:encoded></item><item><title><![CDATA[How to integrate Google login with your Discord.js bots]]></title><description><![CDATA[My open-source solution makes it easier than ever to allow your Discord bot&#8217;s users to sign in to Google, Spotify, and other platforms.]]></description><link>https://blog.yoonicode.com/p/how-to-integrate-google-login-with-your-discord-js-bots-783fa5c75d7f</link><guid isPermaLink="false">https://blog.yoonicode.com/p/how-to-integrate-google-login-with-your-discord-js-bots-783fa5c75d7f</guid><dc:creator><![CDATA[Eric Yoon]]></dc:creator><pubDate>Fri, 03 Mar 2023 07:10:40 GMT</pubDate><enclosure url="https://cdn-images-1.medium.com/max/600/1*El-RhfWrA59m47wkxjQ-5w.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>My open-source solution makes it easier than ever to allow your Discord bot&#8217;s users to sign in to Google, Spotify, and other platforms.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://cdn-images-1.medium.com/max/600/1*El-RhfWrA59m47wkxjQ-5w.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://cdn-images-1.medium.com/max/600/1*El-RhfWrA59m47wkxjQ-5w.jpeg 424w, https://cdn-images-1.medium.com/max/600/1*El-RhfWrA59m47wkxjQ-5w.jpeg 848w, https://cdn-images-1.medium.com/max/600/1*El-RhfWrA59m47wkxjQ-5w.jpeg 1272w, https://cdn-images-1.medium.com/max/600/1*El-RhfWrA59m47wkxjQ-5w.jpeg 1456w" sizes="100vw"><img src="https://cdn-images-1.medium.com/max/600/1*El-RhfWrA59m47wkxjQ-5w.jpeg" data-attrs="{&quot;src&quot;:&quot;https://cdn-images-1.medium.com/max/600/1*El-RhfWrA59m47wkxjQ-5w.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://cdn-images-1.medium.com/max/600/1*El-RhfWrA59m47wkxjQ-5w.jpeg 424w, https://cdn-images-1.medium.com/max/600/1*El-RhfWrA59m47wkxjQ-5w.jpeg 848w, https://cdn-images-1.medium.com/max/600/1*El-RhfWrA59m47wkxjQ-5w.jpeg 1272w, https://cdn-images-1.medium.com/max/600/1*El-RhfWrA59m47wkxjQ-5w.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>What if your Discord bot could add songs to Spotify playlists? Or access a user&#8217;s Google Calendar to schedule&nbsp;events?</p><p>While services like Google and Spotify give developers access to this kind of data, developers generally have to set up entire OAuth2 flows, which can be confusing and result in a bad experience for the end&nbsp;user.</p><p>Enter AuthConnect, a library designed specifically for Discord.js bots that makes OAuth2 integration super&nbsp;simple.</p><ul><li><p>&#128221; <strong>Simplifies OAuth2</strong>: The entire flow, from getting permission from your users to getting a token to use for your requests, is handled for&nbsp;you.</p></li><li><p>&#128190; <strong>Built-in data storage solutions</strong>: AuthConnect provides built-in ways to store users&#8217; authentication data, such as on-disk or in Firebase.</p></li><li><p>&#127760; <strong>Fantastic user experience</strong>: All users have to do is click a link and accept the prompt. Everything else is handled between you and AuthConnect.</p></li><li><p>&#128274;<strong>Your data is safe</strong>: AuthConnect cannot make API requests on your behalf and cannot access your users&#8217;&nbsp;data.</p></li><li><p>&#128290; <strong>Multiple server support</strong>: Each server your bot&#8217;s in can have its set of accounts associated with&nbsp;it.</p></li></ul><h4>The Authentication Flow, Simplified</h4><ol><li><p>You call generateAuthURL() and show your users the&nbsp;link.</p></li><li><p>The user authorizes your app and is redirected to our landing page, which sends the result data to your&nbsp;server.</p></li><li><p>You call getAccessToken(); we refresh the token if it's expired then give it to your&nbsp;app.</p></li><li><p>You call an API with your access&nbsp;token!</p></li></ol><h3>Demo: Setting up Google login with AuthConnect</h3><p>What better way to learn than by example? Here&#8217;s step-by-step instructions to use AuthConnect to get authorization from a user to access their Google&nbsp;data.</p><h4>Set up a Google Cloud&nbsp;project</h4><p>From the <a href="https://console.cloud.google.com/">Google Cloud Console</a>, create a new&nbsp;project.</p><p>Head to <strong>APIs &amp; Services</strong> and click on the <strong>Credentials</strong> page. A credential is a set of keys that allows your program/server to interface with Google&nbsp;APIs.</p><p>Click on <strong>Create credentials</strong>, and select type <strong>OAuth Client ID</strong>. When prompted for an application type, choose <strong>Web application</strong>. Give your credential a friendly&nbsp;name.</p><p>Now, add the following as an <strong>authorized redirect URI</strong>, which will allow users to be redirected to the AuthConnect website that beams data back to your&nbsp;bot:</p><pre><code>https://authconnect-djs.web.app/redir.html</code></pre><p>All in all, your credential should look like&nbsp;this:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://cdn-images-1.medium.com/max/1024/1*QPA7VzrcwenADaHE1TYUuw.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://cdn-images-1.medium.com/max/1024/1*QPA7VzrcwenADaHE1TYUuw.png 424w, https://cdn-images-1.medium.com/max/1024/1*QPA7VzrcwenADaHE1TYUuw.png 848w, https://cdn-images-1.medium.com/max/1024/1*QPA7VzrcwenADaHE1TYUuw.png 1272w, https://cdn-images-1.medium.com/max/1024/1*QPA7VzrcwenADaHE1TYUuw.png 1456w" sizes="100vw"><img src="https://cdn-images-1.medium.com/max/1024/1*QPA7VzrcwenADaHE1TYUuw.png" data-attrs="{&quot;src&quot;:&quot;https://cdn-images-1.medium.com/max/1024/1*QPA7VzrcwenADaHE1TYUuw.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://cdn-images-1.medium.com/max/1024/1*QPA7VzrcwenADaHE1TYUuw.png 424w, https://cdn-images-1.medium.com/max/1024/1*QPA7VzrcwenADaHE1TYUuw.png 848w, https://cdn-images-1.medium.com/max/1024/1*QPA7VzrcwenADaHE1TYUuw.png 1272w, https://cdn-images-1.medium.com/max/1024/1*QPA7VzrcwenADaHE1TYUuw.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Once your credential is created, copy down the Client ID and Client Secret that you&#8217;re given. These values identify your app to Google so that no one else can impersonate you.</p><p>Finally, head to the Library tab of the Cloud Console, and enable whichever service you plan to&nbsp;call.</p><h4>Adding the&nbsp;code</h4><p>Now, all we need to do is add AuthConnect to our Discord project! Once you&#8217;ve gotten a <a href="https://discordjs.guide/preparations/#installing-node-js-and-discord-js">Node project created and Discord.js installed</a>, install AuthConnect:</p><pre><code>npm install authconnect-djs</code></pre><p>Now, let&#8217;s start writing the code. First, let&#8217;s import our libraries:</p><pre><code>import AuthConnect from "authconnect-djs";
import {Client, GatewayIntentBits} from "discord.js";</code></pre><p>Let&#8217;s define some constants. This is where you&#8217;ll paste your bot&#8217;s token and the values you got when you set up your Google Cloud credential.</p><p>Scopes define what your app is allowed to request; for example, a user might only authorize your bot to access their Youtube data and nothing else. Check out <a href="https://developers.google.com/identity/protocols/oauth2/scopes">this page</a> to see what scopes you&#8217;ll need, and paste them in the code, separating each scope with a&nbsp;space.</p><pre><code>const DISCORD_TOKEN = "123_your_discord_token_456";
const GOOGLE_CLIENT_ID = "123_your_google_client_id_456";
const GOOGLE_CLIENT_SECRET = "123_your_google_client_secret_456";

const SCOPES_TO_REQUEST = "https://www.googleapis.com/auth/youtube";</code></pre><p>Now, let&#8217;s initialize our&nbsp;bot.</p><pre><code>const bot = new Client({
    intents: [ GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent, GatewayIntentBits.DirectMessages ],
    partials: [ "CHANNEL" ]
});
let auth;

bot.login(DISCORD_TOKEN);</code></pre><p>Let&#8217;s give our bot an &#8220;on ready&#8221; callback, in which we will initialize our AuthConnect object. We&#8217;ll tell AuthConnect to store authentication data in a file, but you can also have it store data <a href="https://github.com/ericyoondotcom/AuthConnectDJS/blob/main/README.md#easy-firebase-firestore-data-storage-solution">in Firebase</a> or <a href="https://github.com/ericyoondotcom/AuthConnectDJS/blob/main/README.md#custom-data-storage-solution">in your own&nbsp;server</a>.</p><pre><code>bot.on("ready", () =&gt; {
    auth = new AuthConnect({
        google: {
            clientId: GOOGLE_CLIENT_ID,
            clientSecret: GOOGLE_CLIENT_SECRET
        }
    });

    auth.useDefaultDataHandlers("./auth-data.json");
    console.log("Bot ready and AuthConnect initialized.")
});</code></pre><p>Now, let&#8217;s allow users to log in when they send a &#8220;login&#8221; command, only if they&#8217;re an admin. We&#8217;ll generate an auth URL and DM it to the&nbsp;admin.</p><pre><code>bot.on("messageCreate", async message =&gt; {
    if(message.guild !== null &amp;&amp; message.content === "login" &amp;&amp; message.member.permissions.has("ADMINISTRATOR")) {
        const url = auth.generateAuthURL("google", message.guild.id, SCOPES_TO_REQUEST);
        message.channel.send("Please check your DMs for a link to log in.");
        message.member.send(`Please visit this URL to log in: ${url}`);
    }
});</code></pre><p>Now that we have the user&#8217;s permission, AuthConnect will give us a token with which to send API requests. let&#8217;s make a request when the user tells us to, for example using the fetch function.</p><pre><code>// this snippet goes inside the messageCreate callback:

// bot.on("messageCreate", async message =&gt; {
  // code from previous snippet here
  if(message.guild !== null &amp;&amp; message.content === "call an API") {
          if(await auth.isGuildLoggedIn("google", message.guild.id)) {
              const token = await auth.getAccessToken("google", message.guild.id);
              
              // You can use this token to call a Google API, such as this Youtube search endpoint:
              /*
              await fetch("https://www.googleapis.com/youtube/v3/search", {
                  headers: {
                      "Authorization": `Bearer ${token}`,
                      "Content-Type": "application/json",
                  }
              });
              */
          } else {
              message.channel.send("This server is not logged in to Google. Have an administrator type `login`.");
          }
      }
// });</code></pre><h4>Putting it all&nbsp;together</h4><p>Your entire file should look like&nbsp;this:</p><pre><code>import AuthConnect from "authconnect-djs";
import {Client, GatewayIntentBits} from "discord.js";

const DISCORD_TOKEN = "123_your_discord_token_456";
const GOOGLE_CLIENT_ID = "123_your_google_client_id_456";
const GOOGLE_CLIENT_SECRET = "123_your_google_client_secret_456";

// Replace this with the scopes you want to request: https://developers.google.com/identity/protocols/oauth2/scopes
const SCOPES_TO_REQUEST = "https://www.googleapis.com/auth/youtube";

const bot = new Client({
    intents: [ GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent, GatewayIntentBits.DirectMessages ],
    partials: [ "CHANNEL" ]
});
let auth;

bot.login(DISCORD_TOKEN);

bot.on("ready", () =&gt; {
    auth = new AuthConnect({
        google: {
            clientId: GOOGLE_CLIENT_ID,
            clientSecret: GOOGLE_CLIENT_SECRET
        }
    });

    // This is where your auth data will be stored on disk.
    auth.useDefaultDataHandlers("./auth-data.json");
    console.log("Bot ready and AuthConnect initialized.")
});

bot.on("messageCreate", async message =&gt; {
    if(message.guild !== null &amp;&amp; message.content === "login" &amp;&amp; message.member.permissions.has("ADMINISTRATOR")) {
        const url = auth.generateAuthURL("google", message.guild.id, SCOPES_TO_REQUEST);
        message.channel.send("Please check your DMs for a link to log in.");
        message.member.send(`Please visit this URL to log in: ${url}`);
    }

    if(message.guild !== null &amp;&amp; message.content === "call an API") {
        if(await auth.isGuildLoggedIn("google", message.guild.id)) {
            const token = await auth.getAccessToken("google", message.guild.id);
            
            // You can use this token to call a Google API, such as this Youtube search endpoint:
            /*
            await fetch("https://www.googleapis.com/youtube/v3/search", {
                headers: {
                    "Authorization": `Bearer ${token}`,
                    "Content-Type": "application/json",
                }
            });
            */
        } else {
            message.channel.send("This server is not logged in to Google. Have an administrator type `login`.");
        }
    }
});</code></pre><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://cdn-images-1.medium.com/max/600/1*El-RhfWrA59m47wkxjQ-5w.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://cdn-images-1.medium.com/max/600/1*El-RhfWrA59m47wkxjQ-5w.jpeg 424w, https://cdn-images-1.medium.com/max/600/1*El-RhfWrA59m47wkxjQ-5w.jpeg 848w, https://cdn-images-1.medium.com/max/600/1*El-RhfWrA59m47wkxjQ-5w.jpeg 1272w, https://cdn-images-1.medium.com/max/600/1*El-RhfWrA59m47wkxjQ-5w.jpeg 1456w" sizes="100vw"><img src="https://cdn-images-1.medium.com/max/600/1*El-RhfWrA59m47wkxjQ-5w.jpeg" data-attrs="{&quot;src&quot;:&quot;https://cdn-images-1.medium.com/max/600/1*El-RhfWrA59m47wkxjQ-5w.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://cdn-images-1.medium.com/max/600/1*El-RhfWrA59m47wkxjQ-5w.jpeg 424w, https://cdn-images-1.medium.com/max/600/1*El-RhfWrA59m47wkxjQ-5w.jpeg 848w, https://cdn-images-1.medium.com/max/600/1*El-RhfWrA59m47wkxjQ-5w.jpeg 1272w, https://cdn-images-1.medium.com/max/600/1*El-RhfWrA59m47wkxjQ-5w.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h4>More about AuthConnect</h4><p>You can view AuthConnect <a href="https://github.com/ericyoondotcom/AuthConnectDJS">on Github</a>! The library can do much more than what we&#8217;ve covered in our example. Check out the README for more detailed instructions.</p>]]></content:encoded></item><item><title><![CDATA[Building Unity Apps to macOS: The Ultimate Guide]]></title><description><![CDATA[Publishing shouldn&#8217;t be this hard.]]></description><link>https://blog.yoonicode.com/p/building-unity-apps-to-macos-the</link><guid isPermaLink="false">https://blog.yoonicode.com/p/building-unity-apps-to-macos-the</guid><dc:creator><![CDATA[Eric Yoon]]></dc:creator><pubDate>Thu, 09 Dec 2021 20:00:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!yaWq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2af37028-92e0-487a-a314-a58b8a7073ef_1909x1185.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!yaWq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2af37028-92e0-487a-a314-a58b8a7073ef_1909x1185.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!yaWq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2af37028-92e0-487a-a314-a58b8a7073ef_1909x1185.png 424w, https://substackcdn.com/image/fetch/$s_!yaWq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2af37028-92e0-487a-a314-a58b8a7073ef_1909x1185.png 848w, https://substackcdn.com/image/fetch/$s_!yaWq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2af37028-92e0-487a-a314-a58b8a7073ef_1909x1185.png 1272w, https://substackcdn.com/image/fetch/$s_!yaWq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2af37028-92e0-487a-a314-a58b8a7073ef_1909x1185.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!yaWq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2af37028-92e0-487a-a314-a58b8a7073ef_1909x1185.png" width="1456" height="904" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2af37028-92e0-487a-a314-a58b8a7073ef_1909x1185.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:904,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Graphics (shader?) bug with 3D URP and macOS - Questions &amp; Answers - Unity  Discussions&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Graphics (shader?) bug with 3D URP and macOS - Questions &amp; Answers - Unity  Discussions" title="Graphics (shader?) bug with 3D URP and macOS - Questions &amp; Answers - Unity  Discussions" srcset="https://substackcdn.com/image/fetch/$s_!yaWq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2af37028-92e0-487a-a314-a58b8a7073ef_1909x1185.png 424w, https://substackcdn.com/image/fetch/$s_!yaWq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2af37028-92e0-487a-a314-a58b8a7073ef_1909x1185.png 848w, https://substackcdn.com/image/fetch/$s_!yaWq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2af37028-92e0-487a-a314-a58b8a7073ef_1909x1185.png 1272w, https://substackcdn.com/image/fetch/$s_!yaWq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2af37028-92e0-487a-a314-a58b8a7073ef_1909x1185.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Publishing shouldn&#8217;t be this hard. While trying to figure out how to build my Unity game to macOS, I encountered dozens of errors and read heaps of StackOverflow posts, documentation pages, and Q&amp;As. So, I&#8217;ve packaged what I&#8217;ve learned in a guide. Here&#8217;s <strong>how to build Unity games to macOS</strong>, for either <strong>sideloading </strong>or for <strong>Mac App Store distribution</strong>.</p><p>This guide will take you through Apple Developer certificates, code signing, packaging an installer, and notarization, and there&#8217;s even a <strong>bash script</strong> for easy automation!</p><div><hr></div><h2><strong>Creating an App Password</strong></h2><p>Before we get started, we&#8217;re going to need an App-Specific Password from Apple. Head to <a href="https://appleid.apple.com/account/manage/section/security">Security Settings</a> on the Apple ID webpage, click App-Specific Passwords, and create one. Take note of the generated password.</p><h2><strong>Downloading Certificates</strong></h2><p>You&#8217;ll need an Apple Developer account to complete this guide, but there are already many great tutorials on how to do this, so I&#8217;m going to assume you&#8217;re already set up.</p><p>The first step is downloading the correct certificates from Apple. Without these, we can&#8217;t tell Apple our app is safe and your users might encounter &#8220;untrusted&#8221; or &#8220;unsafe&#8221; popups.</p><p>You&#8217;ll first have to create your own Certificate Signing Request (CSR) file from Keychain Access on your Mac. This file acts as your private key.</p><p>Choose <strong>Keychain Access</strong> in the menu bar &#10148; <strong>Certificate Assistant</strong> &#10148; <strong>Request a Certificate From a Certificate Authority</strong>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!iwIx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3651f33-d72a-4f19-9367-6142242785d8_1400x528.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!iwIx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3651f33-d72a-4f19-9367-6142242785d8_1400x528.png 424w, https://substackcdn.com/image/fetch/$s_!iwIx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3651f33-d72a-4f19-9367-6142242785d8_1400x528.png 848w, https://substackcdn.com/image/fetch/$s_!iwIx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3651f33-d72a-4f19-9367-6142242785d8_1400x528.png 1272w, https://substackcdn.com/image/fetch/$s_!iwIx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3651f33-d72a-4f19-9367-6142242785d8_1400x528.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!iwIx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3651f33-d72a-4f19-9367-6142242785d8_1400x528.png" width="1400" height="528" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c3651f33-d72a-4f19-9367-6142242785d8_1400x528.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:528,&quot;width&quot;:1400,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Screenshot of menu option&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Screenshot of menu option" title="Screenshot of menu option" srcset="https://substackcdn.com/image/fetch/$s_!iwIx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3651f33-d72a-4f19-9367-6142242785d8_1400x528.png 424w, https://substackcdn.com/image/fetch/$s_!iwIx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3651f33-d72a-4f19-9367-6142242785d8_1400x528.png 848w, https://substackcdn.com/image/fetch/$s_!iwIx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3651f33-d72a-4f19-9367-6142242785d8_1400x528.png 1272w, https://substackcdn.com/image/fetch/$s_!iwIx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3651f33-d72a-4f19-9367-6142242785d8_1400x528.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>You&#8217;ll want to enter your email address; you can give the request a name in the Common Name field.</p><ul><li><p>Leave the &#8220;CA Email Address&#8221; field blank.</p></li><li><p>Select &#8220;Request is: Saved to disk.&#8221;</p></li><li><p>Check &#8220;Let me specify key pair information&#8221;.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!WN6G!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa8f3133-8de6-4263-a796-15f403025f17_1400x1065.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!WN6G!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa8f3133-8de6-4263-a796-15f403025f17_1400x1065.png 424w, https://substackcdn.com/image/fetch/$s_!WN6G!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa8f3133-8de6-4263-a796-15f403025f17_1400x1065.png 848w, https://substackcdn.com/image/fetch/$s_!WN6G!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa8f3133-8de6-4263-a796-15f403025f17_1400x1065.png 1272w, https://substackcdn.com/image/fetch/$s_!WN6G!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa8f3133-8de6-4263-a796-15f403025f17_1400x1065.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!WN6G!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa8f3133-8de6-4263-a796-15f403025f17_1400x1065.png" width="1400" height="1065" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fa8f3133-8de6-4263-a796-15f403025f17_1400x1065.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1065,&quot;width&quot;:1400,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!WN6G!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa8f3133-8de6-4263-a796-15f403025f17_1400x1065.png 424w, https://substackcdn.com/image/fetch/$s_!WN6G!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa8f3133-8de6-4263-a796-15f403025f17_1400x1065.png 848w, https://substackcdn.com/image/fetch/$s_!WN6G!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa8f3133-8de6-4263-a796-15f403025f17_1400x1065.png 1272w, https://substackcdn.com/image/fetch/$s_!WN6G!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa8f3133-8de6-4263-a796-15f403025f17_1400x1065.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Press Continue and choose a file location. On the next screen, keep Key Size set to 2048 bits and Algorithm set to RSA.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kTQd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0cea3f8-8080-45e0-85a6-0a92e9e65e84_1368x1020.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kTQd!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0cea3f8-8080-45e0-85a6-0a92e9e65e84_1368x1020.png 424w, https://substackcdn.com/image/fetch/$s_!kTQd!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0cea3f8-8080-45e0-85a6-0a92e9e65e84_1368x1020.png 848w, https://substackcdn.com/image/fetch/$s_!kTQd!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0cea3f8-8080-45e0-85a6-0a92e9e65e84_1368x1020.png 1272w, https://substackcdn.com/image/fetch/$s_!kTQd!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0cea3f8-8080-45e0-85a6-0a92e9e65e84_1368x1020.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kTQd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0cea3f8-8080-45e0-85a6-0a92e9e65e84_1368x1020.png" width="1368" height="1020" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e0cea3f8-8080-45e0-85a6-0a92e9e65e84_1368x1020.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1020,&quot;width&quot;:1368,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!kTQd!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0cea3f8-8080-45e0-85a6-0a92e9e65e84_1368x1020.png 424w, https://substackcdn.com/image/fetch/$s_!kTQd!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0cea3f8-8080-45e0-85a6-0a92e9e65e84_1368x1020.png 848w, https://substackcdn.com/image/fetch/$s_!kTQd!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0cea3f8-8080-45e0-85a6-0a92e9e65e84_1368x1020.png 1272w, https://substackcdn.com/image/fetch/$s_!kTQd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0cea3f8-8080-45e0-85a6-0a92e9e65e84_1368x1020.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Press Continue. You&#8217;ll want to keep your .certSigningRequest file around in case you ever need to request additional certificates in the future.</p><p>Head to <a href="https://developer.apple.com/account/resources/certificates/list">Certificates, Identifiers, and Profiles</a> on the Apple Developer account settings page. You&#8217;ll need to generate two certificates depending on where you plan on distributing your app.</p><p>If you want to <strong>sideload</strong> your app (i.e. sending a file to friends or publishing through a non-Apple marketplace), create 1) a<strong> Developer ID Application</strong> certificate and 2) a <strong>Developer ID Installer</strong> certificate.</p><p>If you want to upload your app to the <strong>Mac App Store</strong>, create 1) a <strong>Mac App Distribution</strong> certificate and 2) a <strong>Mac Installer Distribution</strong> certificate.</p><p>To create these certificates, you&#8217;ll have to upload the .certSigningRequest file you generated. After you download these certificates, simply double-click them to add them to Keychain Access.</p><p>Take note of the names of these certificates&#8212;you can view this by opening the quick preview (press spacebar). They should look like &#8220;Developer ID Application: John Doe (XXXXXXXXXX)&#8221; or &#8220;3rd Party Mac Developer Application: John Doe (XXXXXXXXXX)&#8221; depending on which certificates you created. The code in parentheses is called your <strong>provider short name</strong>.</p><h2><strong>Declaring Entitlements</strong></h2><p>We first need to make a list of entitlements. This file tells Apple what capabilities and requirements your app has. Create a file at the root of your project directory called <code>YourGameName.entitlements</code> . Copy the text below into the file:</p><pre><code>&lt;?xml version=&#8221;1.0&#8221; encoding=&#8221;UTF-8&#8221;?&gt;
&lt;!DOCTYPE plist PUBLIC &#8220;-//Apple//DTD PLIST 1.0//EN&#8221; &#8220;<a href="http://www.apple.com/DTDs/PropertyList-1.0.dtd">http://www.apple.com/DTDs/PropertyList-1.0.dtd</a>&#8220;&gt;
&lt;plist version=&#8221;1.0&#8221;&gt;
    &lt;dict&gt;
        &lt;key&gt;com.apple.security.app-sandbox&lt;/key&gt;
        &lt;true/&gt;
        &lt;key&gt;com.apple.security.cs.allow-jit&lt;/key&gt;
        &lt;true/&gt;
&lt;/dict&gt;
&lt;/plist&gt;</code></pre><p>You can add any additional entitlements that your app might need. For example, if your game connects to the Internet, include the <code>com.apple.security.network.client</code> key and add <code>&lt;true/&gt;</code> below. Here&#8217;s a <a href="https://developer.apple.com/documentation/bundleresources/entitlements">complete list of entitlements</a>.</p><h2><strong>Code Signing</strong></h2><p>First, build out your .app file from Unity with Mac, PC, and Linux Standalone as your platform. You may also need to grant execution permissions by running this Terminal command:</p><pre><code>chmod -R a+xr &#8220;<strong>Path/To/Your/Game</strong>.app&#8221;</code></pre><p>Code sign your app using this XCode command (you may have to open XCode for the first time and install developer tools). Run this command from your project&#8217;s root folder.</p><pre><code>codesign --deep --force --verify --verbose --timestamp --options runtime --entitlements &#8220;<strong>YourGameName</strong>.entitlements&#8221; --sign &#8220;<strong>Developer ID</strong> Application: <strong>John Doe</strong> (<strong>XXXXXXXXXX</strong>)&#8221; &#8220;<strong>Path/To/Your/Game</strong>.app&#8221;</code></pre><p>Fields that you need to edit are bolded. Change <code>Developer ID Application</code> to <code>3rd Party Mac Developer Application</code> if you&#8217;re deploying to the Mac App Store (in other words, this should be the name of your Application certificate).</p><h2><strong>Creating a .pkg Installer</strong></h2><p>There are a few types of containers an app can be shipped in&#8212;a .zip file, a .dmg disk image, or a .pkg installer. A .pkg file is what the Mac App Store expects and is in general the most frictionless for users.</p><p>Use the built-in XCode command below to create a .pkg and codesign it all in one step (both the inside .app and its .pkg need to be signed). We specify that we want our app to be installed to the user&#8217;s Applications folder, but you can change this as you wish.</p><pre><code>productbuild --component &#8220;<strong>Path/To/Your/Game</strong>.app&#8221; /Applications --sign &#8220;<strong>Developer ID</strong> Installer: <strong>John Doe</strong> (<strong>XXXXXXXXXX</strong>)&#8221; &#8220;<strong>Your/Build/Folder/YourGameName</strong>.pkg&#8221;</code></pre><blockquote><p><em>Note that the certificate name argument in this command is not the same as the one you used to codesign your app! This should start with either </em><code>Developer ID Installer</code><em> or </em><code>3rd Party Mac Developer Installer</code><em> .</em></p></blockquote><h2><strong>Notarization (for sideloading only)</strong></h2><p>Starting with macOS 10.14.5, Apple requires sideloaded apps to be notarized as an additional layer of protection. You do not need to complete this step if you only intend to distribute through the Mac App Store.</p><p>First, let&#8217;s upload our app for notarization to Apple servers:</p><pre><code>xcrun notarytool submit --apple-id &#8220;<strong>your.apple.id@example.com</strong>&#8220; --team-id &#8220;<strong>XXXXXXXXXX</strong>&#8220; --password &#8220;<strong>your-apps-pass-word</strong>&#8220; &#8220;<strong>Path/To/YourPackage</strong>.pkg&#8221; --wait</code></pre><p>Remember, your <code>team-id</code> is the code in parentheses at the end of your certificate names.</p><p>Wait for the command to finish. Run one last command to &#8220;staple&#8221; the notarization info to your package:</p><pre><code>xcrun stapler staple &#8220;<strong>Path/To/YourPackage</strong>.pkg&#8221;</code></pre><p>You&#8217;re now ready to distribute your .pkg to anywhere for sideloading!</p><h2><strong>Uploading to the Mac App Store</strong></h2><p>If you&#8217;re looking to distribute your app through the Mac App Store, uploading your package is easy. After you&#8217;ve created and configured your app in App Store Connect, you can upload your first build using XCode:</p><pre><code>xcrun altool --upload-app --file &#8220;<strong>Path/To/YourPackage</strong>.pkg&#8221; --type macos --username &#8220;<strong>your.apple.id@example.com</strong>&#8220; --password &#8220;<strong>your-apps-pass-word</strong>&#8220;</code></pre><h2><strong>Automating With a Bash Script</strong></h2><p>I&#8217;ve written a bash script to automate this entire process. Simply copy into a file at the root of your project directory, <code>chmod +x yourscript.sh</code> , and fill in the variables at the top.</p><pre><code>#!/bin/bashAPPLE_ID=&#8221;<strong><a href="mailto:emjyoon@gmail.com">y</a>our.apple.id@example.com</strong>&#8220;
DEV_ID_APPLICATION_CERT_NAME=&#8221;Developer ID Application: <strong>John Doe</strong> (<strong>XXXXXXXXXX</strong>)&#8221;
DEV_ID_INSTALLER_CERT_NAME=&#8221;Developer ID Installer: <strong>John Doe </strong>(<strong>XXXXXXXXXX</strong>)&#8221;
APPLE_APPLICATION_CERT_NAME=&#8221;3rd Party Mac Developer Application: <strong>John Doe</strong> (<strong>XXXXXXXXXX</strong>)&#8221;
APPLE_INSTALLER_CERT_NAME=&#8221;3rd Party Mac Developer Installer: <strong>John Doe</strong> (<strong>XXXXXXXXXX</strong>)&#8221;
APP_PWD=&#8221;<strong>your-apps-pass-word</strong>&#8220;
TEAM_SHORT_NAME=&#8221;<strong>XXXXXXXXXX</strong>&#8220;
APP_LOCATION=&#8221;<strong>Path/To/Your/Game.app</strong>&#8220;
PKG_LOCATION=&#8221;<strong>Your/Build/Folder/GameName</strong>.pkg&#8221;
ENTITLEMENTS_FILE=&#8221;<strong>YourGameName</strong>.entitlements&#8221;chmod -R a+xr &#8220;$APP_LOCATION&#8221;read -p &#8220;Do you want to package app for sideloading or for the Mac App Store? (mac/sideload) &#8220; targetif [ &#8220;$target&#8221; == &#8220;mac&#8221; ]; then
    APPLICATION_CERT_NAME=&#8221;$APPLE_APPLICATION_CERT_NAME&#8221;
    INSTALLER_CERT_NAME=&#8221;$APPLE_INSTALLER_CERT_NAME&#8221;
else
    APPLICATION_CERT_NAME=&#8221;$DEV_ID_APPLICATION_CERT_NAME&#8221;
    INSTALLER_CERT_NAME=&#8221;$DEV_ID_INSTALLER_CERT_NAME&#8221;
fiecho &#8220;Code signing...&#8221;
codesign --deep --force --verify --verbose --timestamp --options runtime --entitlements &#8220;$ENTITLEMENTS_FILE&#8221; --sign &#8220;$APPLICATION_CERT_NAME&#8221; &#8220;$APP_LOCATION&#8221;echo &#8220;Generating pkg and signing...&#8221;
productbuild --component &#8220;$APP_LOCATION&#8221; /Applications --sign &#8220;$INSTALLER_CERT_NAME&#8221; &#8220;$PKG_LOCATION&#8221;if [ &#8220;$target&#8221; != &#8220;mac&#8221; ]; then
    echo &#8220;Uploading for notarization... check back here in a few minutes.&#8221;
    xcrun notarytool submit --apple-id &#8220;$APPLE_ID&#8221; --team-id &#8220;$TEAM_SHORT_NAME&#8221; --password &#8220;$APP_PWD&#8221; &#8220;$PKG_LOCATION&#8221; --waitecho &#8220;Stapling notarization...&#8221;
    xcrun stapler staple &#8220;$PKG_LOCATION&#8221;
fiif [ &#8220;$target&#8221; == &#8220;mac&#8221; ]; then
    read -n1 -p &#8220;Do you want to upload to App Store now? (y/n) &#8220; choice
    echo &#8220;&#8221;if [ &#8220;$choice&#8221; == &#8220;y&#8221; ]; then
        echo &#8220;Uploading to app store...&#8221;
        xcrun altool --upload-app --file &#8220;$PKG_LOCATION&#8221; --type macos --username &#8220;$APPLE_ID&#8221; --password &#8220;$APP_PWD&#8221;
    fi
fiecho &#8220;Finished&#8221;</code></pre><h2><strong>Additional Reading</strong></h2><p>Here are some of the StackOverflow posts and documentation I read trying to get this all set up! Take a look if you&#8217;re stuck.</p><p><a href="https://stackoverflow.com/questions/12126496/how-to-obtain-certificate-signing-request">SO: How to obtain Certificate Signing Request</a><br><a href="https://docs.unity3d.com/Manual/HOWTO-PortToAppleMacStore.html">Unity Docs: Delivering your application to the Mac App Store</a><br><a href="https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution">Apple Docs: Notarizing macOS Software Before Distribution</a><br><a href="https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution/customizing_the_notarization_workflow">Apple Docs: Customizing the Notarization Workflow</a><br><a href="https://stackoverflow.com/questions/56890749/macos-notarize-in-script">SO: macOS: Notarize in Script?</a><br><a href="https://developer.apple.com/forums/thread/107976">Apple Forums: How to notarize app at CI Build?</a><br><a href="https://support.apple.com/en-us/HT204397">Apple Support: Using app-specific passwords</a><br><a href="https://www.davidebarranca.com/2019/04/notarizing-installers-for-macos-catalina/">Notarizing installers for macOS Catalina</a><br><a href="https://gist.github.com/dpid/270bdb6c1011fe07211edf431b2d0fe4">How to notarize a Unity build for macOs 10.15 Catalina</a><br><a href="https://developer.apple.com/forums/thread/662300">Getting a &#8220;certificate is not trusted&#8221; error for iOS Distribution Certificate</a></p><h2><strong>Changelog</strong></h2><ul><li><p>2023&#8211;11&#8211;28: Updated script to use notarytool instead of the deprecated altool notary feature.</p></li><li><p>2023&#8211;12&#8211;02: Added JIT entitlement.</p></li></ul><p>Hope this guide helps. You can check out out my work at <a href="https://yoonicode.com/">yoonicode.com</a>.</p>]]></content:encoded></item><item><title><![CDATA[Publishing Unity Games on Steam: The Ultimate Guide]]></title><description><![CDATA[Steam is one of the most popular game publishing platforms today, yet Steam developers haven&#8217;t made it exactly easy to publish apps to the platform, even in 2022.]]></description><link>https://blog.yoonicode.com/p/publishing-unity-games-on-steam-the</link><guid isPermaLink="false">https://blog.yoonicode.com/p/publishing-unity-games-on-steam-the</guid><dc:creator><![CDATA[Eric Yoon]]></dc:creator><pubDate>Thu, 02 May 0002 08:53:58 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!rO8G!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f3e8072-79bb-4e23-803e-54ec54a11fa0_1920x1080.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rO8G!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f3e8072-79bb-4e23-803e-54ec54a11fa0_1920x1080.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rO8G!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f3e8072-79bb-4e23-803e-54ec54a11fa0_1920x1080.jpeg 424w, https://substackcdn.com/image/fetch/$s_!rO8G!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f3e8072-79bb-4e23-803e-54ec54a11fa0_1920x1080.jpeg 848w, https://substackcdn.com/image/fetch/$s_!rO8G!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f3e8072-79bb-4e23-803e-54ec54a11fa0_1920x1080.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!rO8G!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f3e8072-79bb-4e23-803e-54ec54a11fa0_1920x1080.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rO8G!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f3e8072-79bb-4e23-803e-54ec54a11fa0_1920x1080.jpeg" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0f3e8072-79bb-4e23-803e-54ec54a11fa0_1920x1080.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Welcome to Steam&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Welcome to Steam" title="Welcome to Steam" srcset="https://substackcdn.com/image/fetch/$s_!rO8G!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f3e8072-79bb-4e23-803e-54ec54a11fa0_1920x1080.jpeg 424w, https://substackcdn.com/image/fetch/$s_!rO8G!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f3e8072-79bb-4e23-803e-54ec54a11fa0_1920x1080.jpeg 848w, https://substackcdn.com/image/fetch/$s_!rO8G!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f3e8072-79bb-4e23-803e-54ec54a11fa0_1920x1080.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!rO8G!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f3e8072-79bb-4e23-803e-54ec54a11fa0_1920x1080.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Steam is one of the most popular game publishing platforms today, yet Steam developers haven&#8217;t made it exactly easy to publish apps to the platform, even in 2022. Here&#8217;s how to publish Mac and Windows</p><h2><strong>Glossary</strong></h2><p>Steam has lots of confusing terminology that you should get used to.</p><ul><li><p>Steamworks: Steam&#8217;s game publishing platform for developers.</p></li><li><p>Steamworks.NET: a C# library used to implement Steam features in your game.</p></li><li><p>SteamPipe: a command-line utility to upload your game builds to Steam.</p></li><li><p>Depot: think of a depot as an SKU for your game. There could be a depot for Windows, a depot for Mac, or a depot for French-speaking Mac users.</p></li></ul><h2><strong>Getting Started with Steamworks</strong></h2><p>Head over to <a href="http://partner.steamgames.com/">partner.steamgames.com</a> and create a developer account. This guide will not go over account creation, but the website is fairly straightforward to use. Once you have an account, pay a product submission fee and create a new application.</p><h2><strong>Adding Libraries to Unity</strong></h2><p>Steam has lots of great platform features such as achievements, cloud saves, and the Steam Overlay. We want to be able to harness this power in our game!</p><p>We will be using the open-source <a href="https://steamworks.github.io/">Steamworks.NET</a> library to add this functionality to our game.</p><ol><li><p>Download the latest Steamworks.NET .unitypackage file from the <a href="https://github.com/rlabrecque/Steamworks.NET/releases">repository&#8217;s releases tab</a>. Double-click the package and select all files to import it into your game.</p></li><li><p>At the root of your Unity project (<em>not</em> in your Assets folder), you will find a new file called steam_appid.txt. Go to your Steamworks application page, copy the App ID in parentheses (which identifies your app to Steam), and replace the &#8220;400&#8221; found in the file with your App ID.</p></li><li><p>Open up the <em>SteamManager.cs</em> file imported by Steamworks.NET under Assets/Scripts/Steamworks.NET. Around line 99, replace <code>AppId_t.Invalid</code> with <code>(AppId_t)xxxxxxx</code> , where <code>xxxxxxx</code> is the App ID that you copied.</p></li><li><p>Create a new empty GameObject in your scene and add the SteamManager script to it.</p></li></ol><p>Now, you&#8217;re ready to build your Unity app.</p><h2><strong>Building Your App</strong></h2><p>Build your app for Mac and Windows normally. If you are building for Universal Windows Platform, you&#8217;ll want to build for Standalone instead.</p><p>When building Mac apps, you need to staple a certificate and notarization to your package so users don&#8217;t get &#8220;app not trusted&#8221; errors. <a href="https://medium.com/@yoonicode/building-unity-apps-to-macos-the-ultimate-guide-6d13ca2d84d0">Follow my guide for preparing sideloaded apps here</a>.</p><h2><strong>Steamworks Configuration</strong></h2><p>On your Application Dashboard in Steamworks, you&#8217;ll see two checklists: a Store Presence checklist and a Build checklist. To get your game published, you&#8217;ll have to complete both checklists and submit your app in both review queues.</p><p>To complete the store presence checklist, you&#8217;ll have to upload some artwork and fill out some forms, but this guide won&#8217;t cover this process.</p><p>We will be overviewing how to complete each step in the Build checklist to publish your app.</p><h3><strong>Installation Setup</strong></h3><p>On your Application Dashboard, click <em>Edit Steamworks Settings</em>. Go to <em>Installation</em> &gt; <em>General Installation</em>. Create two launch options:</p><p><strong>Launch Option 0<br></strong>Executable: <code>release/YourGame.exe</code><br>Operating System: <em>Windows</em></p><p><strong>Launch Option 1<br></strong>Executable: <code>YourGame.app</code><br>Operating System: macOS</p><h3><strong>Depot Setup</strong></h3><p>Go to your <em>Edit Steamworks Settings</em> page. Go to <em>SteamPipe</em> &gt;<mark data-color="rgb(232, 243, 232)" style="background-color: rgb(232, 243, 232); color: rgb(0, 0, 0);"> </mark><em>Depots</em>. Create two depots: one for Mac and one for Windows, setting the Operating System field properly. Take note of your depot numbers; all but the last digit will match your App ID. For example, if your App ID is <code>1234560</code> , your depots will be <code>1234561</code> and <code>1234562</code> .</p><p>Important: now head to the Publish tab and click <em>Prepare for Publishing</em>. Click <em>Publish to Steam </em>and type the secret key <code>STEAMWORKS</code> . Click <em>Really Publish</em>.</p><h3><strong>Permissions Setup</strong></h3><p>In the header, head to <em>Users &amp; Permissions</em> &gt; <em>Manage Groups</em>. Create a new group. Grant all permissions to the group, add your application to the group, and add yourself to the member list.</p><p>This step is often overlooked in tutorials, but not doing so will result in a permissions error when you try to upload your build.</p><h3><strong>Package Setup</strong></h3><p>Back in your Application Dashboard, click <em>All Associated Packages, DLC, Demos and Tools</em>. For each package in <em>Store/Free to Play</em> or <em>Promotional or special use</em>, click on the package and add the two depots that you created.</p><h2><strong>Uploading your Builds</strong></h2><p>There are two methods to upload builds to Steam. You can either use the Web interface and upload ZIPs, or you can use the SteamPipe CLI utility.</p><ul><li><p>The web interface only allows uploads of up to 2048MB.</p></li><li><p>The web interface does not show error info. If you run into an error, use SteamPipe instead for extended logs.</p></li><li><p>SteamPipe is supposed to work on Mac and Windows, but I could only figure out how to run it on Windows. Your mileage may vary.</p></li><li><p>There seems to be an issue uploading macOS apps using Steampipe, in which certification and notarization gets lost in the process. If your app becomes unrunnable when uploading from Steampipe, try using the Web interface instead.</p></li></ul><h3><strong>Method 1: Using the Web Interface</strong></h3><p>Create two zips: one containing your Mac .app folder/file, and one containing a folder called <em>release</em> that contains your .exe file. Head to <code>partner.steamgames.com/apps/depotuploads/xxxxxxx</code> where <code>xxxxxxx</code> is your App ID. Upload both ZIPs.</p><h3><strong>Method 2: Using Steampipe</strong></h3><p>Download the latest version of the Steamworks SDK <a href="https://partner.steamgames.com/doc/sdk">from this page</a>.</p><p>Inside <code>tools/ContentBuilder/content</code> , create two folders: <code>mac</code> and <code>windows</code> . Place your .app build into the Mac folder. In the Windows folder, create a folder called <em>release </em>that contains your .exe file.</p><p>Now, let&#8217;s open up a few files in your favorite code editor and make some modifications.</p><p><code>tools/ContentBuilder/run_build.bat</code><strong> </strong>: replace the contents of the file with the following and replace bolded elements:</p><pre><code>builder\steamcmd.exe +login <strong>your_steam_username</strong> <strong>your_steam_password</strong> +run_app_build ..\scripts\app_build_<strong>YourAppID</strong>.vdf</code></pre><p><code>tools/ContentBuilder/scripts/depot_build_1001.vdf</code><strong> </strong>: rename the file, replacing &#8220;1001&#8221; with your Mac depot ID.</p><ul><li><p>Set &#8220;DepotID&#8221; to your depot ID.</p></li><li><p>Under &#8220;FileMapping&#8221;, set &#8220;LocalPath&#8221; to <code>.\mac\*</code> .</p></li></ul><p>In the end, your file should look like:</p><pre><code>
&#8220;DepotBuild&#8221;
{
  &#8220;DepotID&#8221; &#8220;<strong>xxxxxx1</strong>&#8220;
  &#8220;FileMapping&#8221;
  {
    &#8220;LocalPath&#8221; &#8220;<strong>.\mac\*</strong>&#8220;
    &#8220;DepotPath&#8221; &#8220;.&#8221;
    &#8220;Recursive&#8221; &#8220;1&#8221;
  }
}</code></pre><p><code>tools/ContentBuilder/scripts/depot_build_1002.vdf</code><strong> </strong>: rename the file, replacing &#8220;1002&#8221; with your Windows depot ID.</p><ul><li><p>Set &#8220;DepotID&#8221; to your depot ID.</p></li><li><p>Under &#8220;FileMapping&#8221;, set &#8220;LocalPath&#8221; to <code>.\windows\*</code> .</p></li></ul><p>In the end, your file should look like:</p><pre><code>&#8220;DepotBuild&#8221;
{
  &#8220;DepotID&#8221; &#8220;<strong>xxxxxx2</strong>&#8220;
  &#8220;FileMapping&#8221;
  {
    &#8220;LocalPath&#8221; &#8220;<strong>.\windows\*</strong>&#8220;
    &#8220;DepotPath&#8221; &#8220;.&#8221;
    &#8220;Recursive&#8221; &#8220;1&#8221;
  }
}</code></pre><p><code>tools/ContentBuilder/scripts/app_build_1000.vdf</code><strong> </strong>: rename the file, replacing &#8220;1000&#8221; with your App ID.</p><ul><li><p>Fill in the &#8220;AppID&#8221; field with your App ID.</p></li><li><p>Set &#8220;Preview&#8221; to <code>"0"</code> .</p></li><li><p>Comment out (put a <code>//</code> before the line) the &#8220;Local&#8221; and &#8220;SetLive&#8221; fields.</p></li><li><p>Change &#8220;ContentRoot&#8221; to <code>"..\content\"</code>.</p></li><li><p>Replace each entry in &#8220;Depots&#8221; to have your depot number, followed by the name of the depot file from the previous steps.</p></li></ul><p>In the end, your file should look like:</p><pre><code>&#8220;AppBuild&#8221;
{
  &#8220;AppID&#8221; &#8220;<strong>xxxxxxx</strong>&#8220;
  &#8220;Desc&#8221; &#8220;<strong>My Game 1.0.0</strong>&#8220;
  &#8220;Preview&#8221; &#8220;<strong>0</strong>&#8220;
 <strong> //</strong> &#8220;Local&#8221; &#8220;..\..\ContentServer\htdocs&#8221;
  <strong>//</strong> &#8220;SetLive&#8221; &#8220;AlphaTest&#8221;
  &#8220;ContentRoot&#8221; &#8220;<strong>..\content\</strong>&#8220;
  &#8220;BuildOutput&#8221; &#8220;D:\output\&#8221;
  &#8220;Depots&#8221;
  {
    &#8220;<strong>xxxxxx1</strong>&#8220; &#8220;depot_build_<strong>xxxxxx1</strong>.vdf&#8221;
    &#8220;<strong>xxxxxx2</strong>&#8220; &#8220;depot_build_<strong>xxxxxx2</strong>.vdf&#8221;
  }
}</code></pre><p>Double click <strong>run_build.bat</strong> and watch the Command Prompt window. You may have to enter a 2FA Steam Guard code. If any errors occur, they will be logged in the <strong>output</strong> folder. Your build should be uploaded to Steam.</p><h2><strong>Setting Your Build Live</strong></h2><p>Back in Steamworks under <em>Edit Steamworks Settings &gt; SteamPipe &gt; Builds</em>, there should be a new build listed. Under <em>Set build live</em>, click &#8220;default&#8221; as your branch and click <em>Preview Change</em>. Click <em>Set Build Live Now</em>.</p><p>Finally, click on the Publish tab, and go through the same process you did before to deploy your changes to the Steam store.</p><p>If you go to your Steam client, you should see that a new app appeared in your library! Wait 3 minutes and click install on your app.</p><p>Verify that your app files correctly installed on your machine and that you can run your app. On Windows, your files should be in <code>C:\Program Files (x86)\Steam\steamapps\common\Your App Name</code> . On Mac, your files should be in <code>~/Library/Application Support/Steam/steamapps/common/Your App Name</code> .</p><h2><strong>Additional Reading</strong></h2><p>Thanks to the many tutorials and posts that helped me figure this out myself. I&#8217;ve linked some posts that helped me through this process. Take a look if you&#8217;re stuck.</p><ul><li><p><a href="https://www.reddit.com/r/Unity3D/comments/l0sakf/steamcmd_builds_in_preview_mode_but_fails/">Steamcmd builds in preview mode, but fails otherwise</a></p></li><li><p><a href="https://www.youtube.com/watch?v=SoNH-v6aU9Q">Building your content in Steampipe</a></p></li><li><p><a href="https://www.youtube.com/watch?v=rK5Fr5hhslM">Preparing your Unity game for Steam</a></p></li></ul><h2><strong>Conclusion</strong></h2><p>Thank you for reading, and I hope this guide helps. You can check out my work at <a href="https://yoonicode.com/">yoonicode.com</a>.</p>]]></content:encoded></item></channel></rss>