<?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">
    <channel>
        <title><![CDATA[Yuhao.app]]></title>
        <description><![CDATA[Yuhao.app]]></description>
        <link>https://yuhao.app</link>
        <generator>RSS for Node</generator>
        <lastBuildDate>Thu, 12 Mar 2026 19:25:04 GMT</lastBuildDate>
        <atom:link href="https://yuhao.app/rss.xml" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Peeker’s Advantage in Asymmetrical Network Latency]]></title>
            <description><![CDATA[<p></p><p>Peeker’s advantage is the edge a moving player (P) gains when swinging into line of sight against a holding player (H). It exists in all server-authoritative shooters due to latency. A common claim is that peeker’s advantage depends only on the holder’s connection [1]. That is correct only if the peeker’s latency is uniform. If the peeker’s uplink differs between “peek” and “shot,” the advantage grows.</p><p>Mettler, Tang, and Chen [2] provided more detailed explanation of Peeker’s Advantage in symmetrical network conditions. </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.cms.yuhao.app/content/images/2025/10/image.png" class="kg-image" alt="" loading="lazy" width="1552" height="950" srcset="https://blog.cms.yuhao.app/content/images/size/w600/2025/10/image.png 600w, https://blog.cms.yuhao.app/content/images/size/w1000/2025/10/image.png 1000w, https://blog.cms.yuhao.app/content/images/2025/10/image.png 1552w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">[1]&nbsp;Peeker's advantage in symmetry </span></figcaption></figure><h2 id="setup"><strong>Setup</strong></h2><p></p><p>One server&nbsp;<strong>S</strong>, two clients:</p><ul><li><strong>Holder H</strong>: uplink&nbsp;<em>uₕ</em>, downlink&nbsp;<em>dₕ</em>, round-trip time&nbsp;<em>Lₕ = uₕ + dₕ</em>.</li><li><strong>Peeker P</strong>: uplink while revealing&nbsp;<em>Lps</em>&nbsp;(“peek packet”), uplink while firing&nbsp;<em>Lpa</em>&nbsp;(“shot packet”).</li></ul><p>Both have the same human reaction time&nbsp;<em>R</em>. The server resolves hits. First valid shot at the server decides the duel.</p><h2 id="peekers-advantage"><strong>Peeker's Advantage</strong></h2><p></p><p>t1 =&gt; P swings into sight.</p><p>t2 =&gt; P’s reveal reaches S after<em>Lps</em>&nbsp;and reaches H after&nbsp;<em>Lps + dₕ</em>. H first sees P at this moment.</p><p>t3 =&gt; H reacts for<em>R</em>. H’s shot then travels uplink&nbsp;<em>uₕ</em>. So H’s shot arrives at server at</p><p>  <strong>tH = Lps + dₕ + R + uₕ</strong>.</p><p>t4 =&gt; P sees H instantly at swing time. P reacts for&nbsp;<em>R</em>. P’s shot travels uplink&nbsp;<em>Lpa</em>. So P’s shot arrives at server at</p><p>  <strong>tP = R + Lpa</strong>.</p><h2 id="peeker%E2%80%99s-advantage-formula"><strong>Peeker’s Advantage Formula</strong></h2><p></p><p>Define the advantage&nbsp;<em>D</em>&nbsp;as the time gap between H’s and P’s first shots arriving at the server:</p><p>  <strong>D = tH – tP</strong>.</p><h3 id="case-1-uniform-peeker-latency"><strong>Case 1. Uniform Peeker Latency</strong></h3><p></p><p>If peek and shot uplinks are equal (<em>Lps = Lpa</em>):</p><p>  D = (Lps + dₕ + R + uₕ) – (R + Lps)</p><p>  = uₕ + dₕ</p><p>  = Lₕ.</p><p>So with uniform latency, the advantage equals the holder’s round-trip. This is the source of the saying “only your ping matters.”</p><h3 id="case-2-asymmetrical-peeker-uplink"><strong>Case 2. Asymmetrical Peeker Uplink</strong></h3><p></p><p>If peeker’s uplink while revealing is higher than while firing, define the delta</p><p>  <strong>Lpd = Lps – Lpa &gt; 0</strong>.</p><p>Plugging in:</p><p>  D = (uₕ + dₕ) + (Lps – Lpa)</p><p>  = Lₕ + Lpd.</p><h2 id="result"><strong>Result</strong></h2><p></p><ul><li><strong>Uniform peeker latency</strong>: advantage =&nbsp;<em>Lₕ</em>.</li><li><strong>Asymmetrical uplink</strong>&nbsp;(<em>Lps &gt; Lpa</em>): advantage =&nbsp;<em>Lₕ + Lpd</em>.</li></ul><p>In words: the peeker gains not only the holder’s round-trip but also the extra head start equal to the difference between peek uplink and shot uplink.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.cms.yuhao.app/content/images/2025/10/image-1.png" class="kg-image" alt="" loading="lazy" width="1408" height="982" srcset="https://blog.cms.yuhao.app/content/images/size/w600/2025/10/image-1.png 600w, https://blog.cms.yuhao.app/content/images/size/w1000/2025/10/image-1.png 1000w, https://blog.cms.yuhao.app/content/images/2025/10/image-1.png 1408w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Peeker's advantage in asymmetry </span></figcaption></figure><h2 id="next-steps">Next Steps</h2><ul><li>Empirical validation/simulation</li><li>We examined <strong>Lps – Lpa &gt; 0</strong> grows peeker's advantage. Naturally <strong>Lps + Lpa &gt; 0 </strong>shrink peeker's advantage. How about that! Maybe peeker's advantage does have a solution after all (with serious tradeoff ofc).</li><li>People has been using network throttle to cheat for ages, maybe it's time for intelligent network throttle. Maybe they already exist.</li><li>How to mitigate and defend against such cheat.</li></ul><h2 id="references"><strong>References</strong></h2><p>[1]&nbsp;M. deWet and D. Straily, “Peeking into VALORANT’s netcode,” Riot Games Technology, Jul. 28, 2020. [Online]. Available: https://technology.riotgames.com/news/peeking-valorants-netcode</p><p>[2] C. Mettler, D. Tang, and Z. Chen,&nbsp;<em>A study on the effects of network latency on peeker’s advantage in FPS games</em>, Interactive Qualifying Project Report, Worcester Polytechnic Institute, 2023. [Online]. Available: https://web.cs.wpi.edu/~claypool/iqp/fps-lag-22/final-report.pdf</p><h2 id="citing-this"><strong>Citing This</strong></h2><p></p><pre><code class="language-plaintext">@article{chen2025peeker,
  title   = {Peeker’s Advantage in Asymmetrical Network Latency},
  author  = {Chen, Yuhao and Yang, Tianchi},
  year    = {2025}
}</code></pre><h2 id=""></h2>]]></description>
            <link>https://yuhao.app/blog/peekers-advantage-in-asymmetrical-network-latency</link>
            <guid isPermaLink="true">https://yuhao.app/blog/peekers-advantage-in-asymmetrical-network-latency</guid>
            <pubDate>Fri, 03 Oct 2025 10:53:10 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[An Update On The Blog]]></title>
            <description><![CDATA[<p>Hi, this is Yuhao. Due to a billing oversight, the DigitalOcean instance hosting the blog CMS was deleted. Unfortunately, the Coolify backup was not set up correctly, so the restoration process has taken longer than expected, and the available backup is incomplete.</p><p>Thankfully, I still have the drafts for all published posts on&nbsp;<a href="https://yuhao.app/blog">yuhao.app/blog</a>, and I’ll be manually restoring them over the coming days.</p><p>I sincerely apologize for this oversight and appreciate your patience as I work to bring everything back online.</p>]]></description>
            <link>https://yuhao.app/blog/digitalocean-incident</link>
            <guid isPermaLink="true">https://yuhao.app/blog/digitalocean-incident</guid>
            <pubDate>Fri, 29 Aug 2025 06:58:19 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Pointers and References in C++]]></title>
            <description><![CDATA[<p>This summer, I am brushing up my C++ by going through Alex's excellent tutorial at <a>learncpp.com</a>. I recently went through its chapter on <a href="https://www.learncpp.com/cpp-tutorial/introduction-to-compound-data-types/">Pointers and References</a>, and I cleared a lot of my previous confusion on the topic. Here are some notes I took.</p><h2 id="references-in-c">References in C++</h2><pre><code class="language-cpp">int        // a normal int type (not an reference)
int&amp;       // an lvalue reference to an int object
const int&amp; // a constant lvalue reference
</code></pre><p>Both <code>T&amp; ref</code> and <code>T &amp;ref</code> are valid ways to define a reference but the first one is preferred.</p><pre><code class="language-cpp">int x {5};
int&amp; ref {x};

ref = 6;
std::cout &lt;&lt; x &lt;&lt; '\n'; // 6
</code></pre><p>Modify a reference will modify the object it refers too</p><pre><code class="language-cpp">int x {5};
int&amp; ref {x};

int y {6};
ref = y;
std::cout &lt;&lt; x &lt;&lt; '\n'; // 6
</code></pre><p>You can not reseat a reference</p><pre><code class="language-cpp">const int x {5};
// int&amp; ref {x}; &lt;-- this is not allowed
const int&amp; ref {x}; // this is allowed and preferred way to reference object, unless you explicitly need to modify a value through reference.
</code></pre><p><code>const T&amp;</code> also can be init with literal (or other rvalue), for example, <code>const int&amp; {5}</code> where as <code>T&amp;</code> couldn’t. Note that 5, a temporary value, it's lifetime is extended by <code>const T&amp;</code></p>
<!--kg-card-begin: html-->
<table>
<thead>
<tr>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td><code>T&amp;</code></td>
<td><code>const T&amp;</code></td>
</tr>
<tr>
<td>Modifiable Lvalue</td>
<td>✅</td>
<td>✅</td>
</tr>
<tr>
<td>Rvalue</td>
<td>⛔️</td>
<td>✅</td>
</tr>
<tr>
<td>Constant Lvalue</td>
<td>⛔️</td>
<td>✅</td>
</tr>
<tr>
<td>Can modify original object</td>
<td>✅</td>
<td>⛔️</td>
</tr>
</tbody>
</table>
<!--kg-card-end: html-->
<h3 id="what-the-hell-is-l-value-and-r-value">What the hell is l-value and r-value?</h3><pre><code class="language-cpp">int x { 5 }; // 5 is an rvalue expression
int y { x }; // x is an lvalue expression
const double d{ 1.2 }; // 1.2 is an rvalue expression
const double e { d }; // d is a non-modifiable lvalue expression
</code></pre><ol><li>More formal explanation:<ul><li>Lvalue expressions evaluate to an identifiable object.</li><li>Rvalue expressions evaluate to a value.</li></ul></li><li>More straightforward (to me) explanation:<ul><li>A lvalue that stands for locate value is a variable that holds a value in memory</li><li>A rvalue is a variable itself and that it has no memory allocated.</li></ul></li></ol><h2 id="pointers-in-c">Pointers in C++</h2><h3 id="dereference-operator">Dereference operator <code>*</code></h3><pre><code class="language-cpp">#include &lt;iostream&gt;

int main()
{
    int x{ 5 };
    std::cout &lt;&lt; x &lt;&lt; '\n';  // print the value of variable x
    std::cout &lt;&lt; &amp;x &lt;&lt; '\n'; // print the memory address of variable x

    std::cout &lt;&lt; *(&amp;x) &lt;&lt; '\n'; // print the value at the memory address of variable x (parentheses not required, but make it easier to read)

    return 0;
}

// 5
// 0027FEA0
// 5
</code></pre><h3 id="pointers">Pointers</h3><p>A pointer can be declared via <code>T* x</code>, and a pointer declared but not initialized is called a wild pointer. You can initialize a pointer via <code>T* {&amp;x}</code>.</p><h4 id="assignment-in-pointer">Assignment in pointer</h4><p>We can use assignment with pointers in two different ways:</p><ol><li><code>*ptr = 6;</code> To change what the pointer is pointing at (by assigning the pointer a new address)</li><li><code>ptr = &amp;x;</code> To change the value being pointed at (by assigning the dereferenced pointer a new value)</li></ol><pre><code class="language-cpp">#include &lt;iostream&gt;

int main()
{
    int x{ 5 };'
    int* ptr{ &amp;x }; // ptr initialized to point at x

    std::cout &lt;&lt; *ptr &lt;&lt; '\n'; // print the value at the address being pointed to (x's address)

    int y{ 6 };
    ptr = &amp;y; // // change ptr to point at y

    std::cout &lt;&lt; *ptr &lt;&lt; '\n'; // print the value at the address being pointed to (y's address)

    return 0;
}
</code></pre><ul><li><code>&amp;x</code> return a pointer not the literal address to <code>x</code></li><li>On a 32 bit architecture, a pointer is 4 bits</li></ul><h3 id="null-pointer">Null Pointer</h3><p>When you initialize a pointer like <code>int* ptr{}</code>, you get a null pointer.</p><p>You can also assign a pointer with <code>ptr = nullptr</code> to assign it with null pointer.</p><p>You **can but should avoid&nbsp;**initialize a nullptr with <code>T* ptr{0};</code> or <code>T* ptr{NULL};</code>.</p><p>You can test whether a pointer is a null pointer by <code>if (ptr == nullptr)</code> or just <code>if (ptr)</code>.</p><ul><li>Note: Testing whether a pointer is not a null pointer does not alway guarantee a pointer is safe to deference. <strong>A dangling pointer to a destroyed item does not automatically set to nullptr. Therefore it’s your responsibility to detect these cases and ensure those pointer are set to nullptr.</strong></li></ul><h3 id="pointers-and-const">Pointers and const</h3><pre><code class="language-cpp">const int x {5};
int* ptr { &amp;x }; // compile error: cannot convert from const int*
</code></pre><p>You cannot set a normal pointer to a pointer at a const variable.</p><h3 id="const-pointers">Const pointers</h3><p>A const pointer Is a pointer whose address cannot be changed — <code>T* const ptr {&amp;x};</code>.</p><p>You can dereference <code>*ptr</code> and modify the original object <code>x</code> given x is a non constant.</p><h3 id="const-const-pointer-to-a-const-value">Const Const pointer to a const value</h3><p>You can declare by <code>const T* const ptr { &amp;x };</code> even if <code>T x</code> is a non const. In this case the nether the pointer accept assignment nor dereferenced pointer accept assignment.</p><h3 id="wth-here-is-a-cheat-sheet">WTH? Here is a cheat sheet</h3>
<!--kg-card-begin: html-->
<table>
<thead>
<tr>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td><code>int x {5}</code></td>
<td><code>const x {5}</code></td>
</tr>
<tr>
<td><code>int* ptr {&amp;x}</code></td>
<td>Pointer and dereferenced pointer accept assignment</td>
<td>Declaration not allowed</td>
</tr>
<tr>
<td><code>const int* ptr {&amp;x}</code></td>
<td>Pointer accept assignment but dereferenced pointer don’t</td>
<td>Pointer accept assignment but dereferenced pointer don’t</td>
</tr>
<tr>
<td><code>int* const ptr {&amp;x}</code></td>
<td>Dereferenced&nbsp; pointer accept assignment but pointer don’t</td>
<td>Declaration not allowed</td>
</tr>
<tr>
<td><code>const int* const ptr {&amp;x}</code></td>
<td>Neither pointer nor dereferenced pointer accept assignment</td>
<td>Neither pointer nor dereferenced pointer accept assignment</td>
</tr>
</tbody>
</table>
<!--kg-card-end: html-->
<h3 id="even-simpler-cheat-sheet">Even simpler cheat sheet</h3>
<!--kg-card-begin: html-->
<table>
<thead>
<tr>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Declaration</strong>****</td>
<td><code>int x</code></td>
<td><code>const int x</code></td>
</tr>
<tr>
<td><code>int* ptr = &amp;x</code></td>
<td>*ptr = ... ✅ptr = ... ✅</td>
<td>🚫 illegal declaration</td>
</tr>
<tr>
<td><code>const int* ptr = &amp;x</code></td>
<td>*ptr = ... ❌ptr = ... ✅</td>
<td>*ptr = ... ❌ptr = ... ✅</td>
</tr>
<tr>
<td><code>int* const ptr = &amp;x</code></td>
<td>*ptr = ... ✅ptr = ... ❌</td>
<td>🚫 illegal declaration</td>
</tr>
<tr>
<td><code>const int* const ptr = &amp;x</code></td>
<td>*ptr = ... ❌ptr = ... ❌</td>
<td>*ptr = ... ❌ptr = ... ❌</td>
</tr>
</tbody>
</table>
<!--kg-card-end: html-->
<ul><li>*ptr = ... → assigning to the pointee</li><li>ptr = ... → reassigning the pointer itself</li><li>✅ = assignment allowed</li><li>❌ = assignment not allowed</li><li>🚫 = declaration is invalid (compile error)</li></ul><h2 id="pass-by-reference-and-pass-by-address">Pass by Reference and Pass by Address</h2><h3 id="passy-by-reference">Passy by reference</h3><pre><code class="language-cpp">void addOne(int&amp; y) // y is bound to the actual object x
{
    ++y; // this modifies the actual object x
}

// int x{5};
// addOne(x);
</code></pre><pre><code class="language-cpp">#include &lt;iostream&gt;

void printAddresses(int val, int&amp; ref)
{
    std::cout &lt;&lt; "The address of the value parameter is: " &lt;&lt; &amp;val &lt;&lt; '\n';
    std::cout &lt;&lt; "The address of the reference parameter is: " &lt;&lt; &amp;ref &lt;&lt; '\n';
}

int main()
{
    int x { 5 };
    std::cout &lt;&lt; "The address of x is: " &lt;&lt; &amp;x &lt;&lt; '\n';
    printAddresses(x, x);

    return 0;
}

// The address of x is: 0x7ffd16574de0
// The address of the value parameter is: 0x7ffd16574de4
// The address of the reference parameter is: 0x7ffd16574de0
</code></pre><p><code>T funcName(T&amp; x)</code> and <code>T funcName(const T&amp; x)</code> follow pretty much same rule as <code>const T&amp;</code> and <code>T&amp;</code>, a reference to non-const (which can only bind to modifiable lvalues), a reference to const can bind to modifiable lvalues, non-modifiable lvalues, and rvalues. But value modification is not allowed for <code>T funcName(const T&amp; x)</code>.</p><h3 id="pass-by-address">Pass by Address</h3><pre><code class="language-cpp">void addOne(int* y) // y is bound to the actual object x
{
    ++y; // this modifies the actual object x
}

int x{5};
addOne(&amp;x);
</code></pre><h3 id="pass-by-value-by-reference-and-by-address">Pass by value? By reference? And by address</h3>
<!--kg-card-begin: html-->
<table>
<thead>
<tr>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Feature</strong>****</td>
<td><strong>Pass by Value</strong>****</td>
<td><strong>Pass by Reference</strong>****</td>
<td><strong>Pass by Address</strong>****</td>
</tr>
<tr>
<td><strong>Syntax</strong>****</td>
<td>void foo(int x)</td>
<td>void foo(int&amp; x)</td>
<td>void foo(int* x)</td>
</tr>
<tr>
<td><strong>Argument Type</strong>****</td>
<td>Copy of the actual value</td>
<td>Alias to the original variable</td>
<td>Pointer to the original variable</td>
</tr>
<tr>
<td><strong>Called with</strong>****</td>
<td>foo(a)</td>
<td>foo(a)</td>
<td>foo(&amp;a)</td>
</tr>
<tr>
<td><strong>Can modify original?</strong>****</td>
<td>❌ No</td>
<td>✅ Yes</td>
<td>✅ Yes (via dereferencing)</td>
</tr>
<tr>
<td><strong>Memory Use</strong>****</td>
<td>More (creates a copy)</td>
<td>Less (no copy)</td>
<td>Less (only pointer is copied)</td>
</tr>
<tr>
<td><strong>Null Safety</strong>****</td>
<td>Always safe</td>
<td>Always safe</td>
<td>❌ Must check for nullptr</td>
</tr>
<tr>
<td><strong>Typical Use Cases</strong>****</td>
<td>When you don’t want to modify input</td>
<td>When you want to modify input</td>
<td>When dealing with dynamic memory / APIs</td>
</tr>
<tr>
<td><strong>Example Call</strong>****</td>
<td>foo(5);</td>
<td>foo(a);</td>
<td>foo(&amp;a);</td>
</tr>
<tr>
<td><strong>Inside Function Access</strong>****</td>
<td>Use as-is (x)</td>
<td>Use as-is (x)</td>
<td>Dereference (*x)</td>
</tr>
</tbody>
</table>
<!--kg-card-end: html-->
<ul><li>Note:<br>**Prefer <code>void foo(T* const value)</code> over <code>void foo(T* value)</code>.&nbsp;**And yes you can<code>void foo(const T* const value)</code> and <code>void foo(const T* const value)</code>, it follows the same rule referenced in the cheat sheet.</li></ul><h3 id="when-to-use-pass-by-value-vs-pass-by-reference">When to use pass by value vs pass by reference</h3><ul><li>Fundamental types and enumerated types are cheap to copy, so they are typically passed by value.</li><li>Class types can be expensive to copy (sometimes significantly so), so they are typically passed by const reference.<br>Actually got asked this question in a Tesla interview</li></ul><h3 id="pass-by-reference-vs-by-address">Pass by reference vs by address</h3><p>Pass by const reference has a few other advantages over pass by address.</p><p>First, because an object being passed by address must have an address, only lvalues can be passed by address (as rvalues don’t have addresses). Pass by const reference is more flexible, as it can accept lvalues and rvalues.</p><p>Second, the syntax for pass by reference is natural, as we can just pass in literals or objects. With pass by address, our code ends up littered with ampersands (&amp;) and asterisks (*).</p><p>In modern C++, most things that can be done with pass by address are better accomplished through other methods. Follow this common maxim: “<strong>Pass by reference when you can, pass by address when you must</strong>”.</p><h3 id="pass-by-address-copies-the-address">Pass by address copies the address</h3><pre><code class="language-cpp">// Consider
void foo(int* ptr)
{
    ptr = nullptr;
}

int x{ 5};
int* ptr{ &amp;x };
foo(x);

std::cout &lt;&lt; "ptr is " &lt;&lt; (ptr ? "non-null\n" : "null\n"); // ptr is non-null
</code></pre><p>Therefore reassign a passed by pointer to another address does not reassign the original pointer (because <code>foo()</code> copies reference).</p><h3 id="pass-by-address-by-reference">Pass by address by reference</h3><p>Instead, if you want achieve above, you can:</p><pre><code class="language-cpp">void bar(int*&amp; ptr)
{
    ptr = nullptr;
}
</code></pre><h2 id="return-by-reference-and-address">Return by reference and address</h2><p>Similar to pass by value, return by value also returns a copy of the object:</p><pre><code class="language-cpp">std::string returnByValue();
</code></pre><pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;string&gt;

const std::string&amp; getProgramName() // returns a const reference
{
    static const std::string s_programName { "Calculator" }; // has static duration, destroyed at end of program

    return s_programName;
}

int main()
{
    std::cout &lt;&lt; "This program is named " &lt;&lt; getProgramName();

    return 0;
}

// This program is named Calculator
</code></pre><p>Because <code>getProgramName()</code> returns a const reference, when the line return <code>s_programName&nbsp;</code>is executed, <code>getProgramName()</code> will return a const reference to s_programName (thus avoiding making a copy). That const reference can then be used by the caller to access the value of <code>s_programName</code>, which is printed.</p><p>**Using return by reference has one major caveat: the programmer must be sure that the object being referenced outlives the function returning the reference.&nbsp;**Otherwise, the reference being returned will be left dangling (referencing an object that has been destroyed), and use of that reference will result in undefined behavior.</p><pre><code class="language-cpp">
const std::string&amp; getProgramName()
{
    const std::string programName { "Calculator" }; // now a non-static local variable, destroyed when function ends

    return programName;
}
</code></pre><p>This will result in previous program undefined since programName is now destroyed at the end of the function.</p><h3 id="lifetime-extension-doesn%E2%80%99t-work-across-function-boundaries">Lifetime extension doesn’t work across function boundaries</h3><pre><code class="language-cpp">#include &lt;iostream&gt;

const int&amp; returnByConstReference(const int&amp; ref)
{
    return ref;
}

int main()
{
    // case 1: direct binding
    const int&amp; ref1 { 5 }; // extends lifetime
    std::cout &lt;&lt; ref1 &lt;&lt; '\n'; // okay

    // case 2: indirect binding
    const int&amp; ref2 { returnByConstReference(5) }; // binds to dangling reference
    std::cout &lt;&lt; ref2 &lt;&lt; '\n'; // undefined behavior

    return 0;
}
</code></pre><p>In this case, a temporary object is created to hold value 5, which function parameter ref binds to. The function just returns this reference back to the caller, which then uses the reference to initialize ref2. Because this is not a direct binding to the temporary object (as the reference was bounced through a function), lifetime extension doesn’t apply. This leaves ref2 dangling, and its subsequent use is undefined behavior.</p><h3 id="don%E2%80%99t-return-non-const-static-local-variables-by-reference">Don’t return non-const static local variables by reference</h3><p>You are allowed to do so but will often result in unintended behavior:</p><pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;string&gt;

const int&amp; getNextId()
{
    static int s_x{ 0 }; // note: variable is non-const
    ++s_x; // generate the next id
    return s_x; // and return a reference to it
}

int main()
{
    const int&amp; id1 { getNextId() }; // id1 is a reference
    const int&amp; id2 { getNextId() }; // id2 is a reference

    std::cout &lt;&lt; id1 &lt;&lt; id2 &lt;&lt; '\n';

    return 0;
}

</code></pre><h3 id="assigninginitializing-a-normal-variable-with-a-returned-reference-makes-a-copy">Assigning/initializing a normal variable with a returned reference makes a copy</h3><p>If a function returns a reference, and that reference is used to initialize or assign to a non-reference variable, the return value will be copied (as if it had been returned by value).</p><pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;string&gt;

const int&amp; getNextId()
{
    static int s_x{ 0 };
    ++s_x;
    return s_x;
}

int main()
{
    const int id1 { getNextId() }; // id1 is a normal variable now and receives a copy of the value returned by reference from getNextId()
    const int id2 { getNextId() }; // id2 is a normal variable now and receives a copy of the value returned by reference from getNextId()

    std::cout &lt;&lt; id1 &lt;&lt; id2 &lt;&lt; '\n';

    return 0;
}

// 12
</code></pre><h3 id="it%E2%80%99s-okay-to-return-reference-parameters-by-reference">It’s okay to return reference parameters by reference</h3><pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;string&gt;

// Takes two std::string objects, returns the one that comes first alphabetically
const std::string&amp; firstAlphabetical(const std::string&amp; a, const std::string&amp; b)
{
	return (a &lt; b) ? a : b; // We can use operator&lt; on std::string to determine which comes first alphabetically
}

int main()
{
	std::string hello { "Hello" };
	std::string world { "World" };

	std::cout &lt;&lt; firstAlphabetical(hello, world) &lt;&lt; '\n';

	return 0;
}

// Hello
</code></pre><h3 id="it%E2%80%99s-okay-for-an-rvalue-passed-by-const-reference-to-be-returned-by-const-reference">It’s okay for an rvalue passed by const reference to be returned by const reference</h3><p>When an argument for a const reference parameter is an rvalue, it’s still okay to return that parameter by const reference.<br>This is because rvalues are not destroyed until the end of the full expression in which they are created.</p><pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;string&gt;

const std::string&amp; foo(const std::string&amp; s)
{
    return s;
}

std::string getHello()
{
    return "Hello"; // implicit conversion to std::string
}

int main()
{
    const std::string s{ foo(getHello()) };

    std::cout &lt;&lt; s;

    return 0;
}
</code></pre><h3 id="the-caller-can-modify-values-through-the-reference">The caller can modify values through the reference</h3><p>This is very confusing behavior. Hence imho, make you return <code>const *</code></p><pre><code class="language-cpp">#include &lt;iostream&gt;

// takes two integers by non-const reference, and returns the greater by reference
int&amp; max(int&amp; x, int&amp; y)
{
    return (x &gt; y) ? x : y;
}

int main()
{
    int a{ 5 };
    int b{ 6 };

    max(a, b) = 7; // sets the greater of a or b to 7

    std::cout &lt;&lt; a &lt;&lt; b &lt;&lt; '\n';

    return 0;
}
</code></pre><h3 id="return-by-address">Return By Address</h3><p>Return by address works almost identically to return by reference, except a pointer to an object is returned instead of a reference to an object. Return by address has the same primary caveat as return by reference -- the object being returned by address must outlive the scope of the function returning the address, otherwise the caller will receive a dangling pointer.</p><p>The major advantage of return by address over return by reference is that we can have the function return nullptr if there is no valid object to return. For example, let’s say we have a list of students that we want to search. If we find the student we are looking for in the list, we can return a pointer to the object representing the matching student. If we don’t find any students matching, we can return nullptr to indicate a matching student object was not found.<br>The major disadvantage of return by address is that the caller has to remember to do a nullptr check before dereferencing the return value, otherwise a null pointer dereference may occur and undefined behavior will result. Because of this danger, return by reference should be preferred over return by address unless the ability to return “no object” is needed.</p><h3 id="wth-sheet-again">WTH Sheet, again</h3><pre><code class="language-cpp">const std::string&amp; foo(const std::string&amp; s) {
    return s;
}
</code></pre>
<!--kg-card-begin: html-->
<table>
<thead>
<tr>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Code</strong>****</td>
<td><strong>Safe?</strong>****</td>
<td><strong>Why</strong>****</td>
</tr>
<tr>
<td>const std::string s{ foo("Hello") };</td>
<td>✅</td>
<td>"Hello" is converted to a temporary std::string. foo() returns a reference to it, and s is <strong>copy-constructed</strong> from it <strong>before the temporary dies</strong>.</td>
</tr>
<tr>
<td>const std::string**&amp;** s{ foo("Hello") };</td>
<td>❌</td>
<td>"Hello" becomes a temporary std::string, bound inside foo, but the returned reference points to that temporary, which <strong>dies after the full expression</strong> → ref is <strong>dangling</strong>****</td>
</tr>
<tr>
<td>std::string temp = "Hello"; const std::string&amp; ref = foo(temp);</td>
<td>✅</td>
<td>temp is a named variable. foo(temp) returns a reference to it, which is safely bound to ref — <strong>no temporary</strong>, <strong>no lifetime issue</strong>****</td>
</tr>
<tr>
<td>const std::string&amp; ref = "Hello";</td>
<td>✅</td>
<td>"Hello" is promoted to a temporary std::string, but since it is <strong>directly bound to a const reference</strong>, the lifetime is <strong>extended</strong> — valid</td>
</tr>
</tbody>
</table>
<!--kg-card-end: html-->
<p>In short <code>const std::string s{ foo("Hello") };</code> good as it make a copy before temporary dies.</p><p><code>const std::string&amp; s{ foo("Hello") };</code> bad because temporary will die after the full expression. The difference is &amp; if you still couldn’t tell.</p>]]></description>
            <link>https://yuhao.app/blog/pointers-and-references-in-c</link>
            <guid isPermaLink="true">https://yuhao.app/blog/pointers-and-references-in-c</guid>
            <pubDate>Fri, 29 Aug 2025 08:01:46 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[★Making of LetgO  🎈]]></title>
            <description><![CDATA[<p>Recently, a team I contributed to as a minor collaborator - as interaction designer -<a href="https://itch.io/jam/tgcxcoreblazer/rate/3623907">submitted</a> a game to the <a href="https://itch.io/jam/tgcxcoreblazer">thatgamecompany × COREBLAZER GAME JAM 2025</a>. The director of the game is my friend Ebay. I first met him through Cooper and Justin, who worked with Ebay on a different project at USC — a game called <a href="https://store.steampowered.com/app/3518380/Myth_of_Lumi/">Myth of Lumi</a>.</p><p>Ebay later became my Student Assistant in CTIN 534, a class taught by <a href="https://store.steampowered.com/app/3518380/Myth_of_Lumi/">Peter Brinson</a>. One day, I happened to run into him and we ended up having a long conversation. That’s when he pitched me this new game — a journey about a balloon.</p><figure class="kg-card kg-image-card"><img src="https://blog.cms.yuhao.app/content/images/2025/08/image-10.png" class="kg-image" alt="" loading="lazy" width="2000" height="1120" srcset="https://blog.cms.yuhao.app/content/images/size/w600/2025/08/image-10.png 600w, https://blog.cms.yuhao.app/content/images/size/w1000/2025/08/image-10.png 1000w, https://blog.cms.yuhao.app/content/images/size/w1600/2025/08/image-10.png 1600w, https://blog.cms.yuhao.app/content/images/2025/08/image-10.png 2264w" sizes="(min-width: 720px) 720px"></figure><p><br>The game is called Balloon. You play as a little red balloon floating through the air. You’re light, fragile, and can’t really control where you’re going—just drifting with the wind. All you can do is gently pull on the string to try and steer. The heart of the game lies in how you interact with the people you meet along the way. Like in real life, different people respond differently to hope: a kid might run toward you with joy, a tired office worker might glance up and smile, and a little girl might kick you like a soccer ball. The balloon reflects the people it passes — it’s a simple, poetic way to explore how people feel about hope itself. The whole experience plays out like a quiet, interactive poem.<br></p><figure class="kg-card kg-image-card"><img src="https://blog.cms.yuhao.app/content/images/2025/08/image-11.png" class="kg-image" alt="" loading="lazy" width="2000" height="1120" srcset="https://blog.cms.yuhao.app/content/images/size/w600/2025/08/image-11.png 600w, https://blog.cms.yuhao.app/content/images/size/w1000/2025/08/image-11.png 1000w, https://blog.cms.yuhao.app/content/images/size/w1600/2025/08/image-11.png 1600w, https://blog.cms.yuhao.app/content/images/2025/08/image-11.png 2264w" sizes="(min-width: 720px) 720px"></figure><p><br>When I first heard the pitch, it immediately reminded me of Flower by <a href="https://jenovachen.info">Jenova Chen</a> — one of the more well-known game designers to come out of USC. Fittingly, Ebay later told me the game received a lot of mentorship and feedback from <a href="https://cinema.usc.edu/directories/profile.cfm?id=6513&amp;first=&amp;last=&amp;title=">Tracy Fullerton</a>, who mentored Jenova back in the day.</p><figure class="kg-card kg-image-card"><img src="https://blog.cms.yuhao.app/content/images/2025/08/image-12.png" class="kg-image" alt="" loading="lazy" width="1024" height="768" srcset="https://blog.cms.yuhao.app/content/images/size/w600/2025/08/image-12.png 600w, https://blog.cms.yuhao.app/content/images/size/w1000/2025/08/image-12.png 1000w, https://blog.cms.yuhao.app/content/images/2025/08/image-12.png 1024w" sizes="(min-width: 720px) 720px"></figure><p>I immediately expressed interest in working on the project — but instead of taking on my usual role as an engineer, I told Ebay I was more interested in helping design the interactions. Partly because the concept really resonated with me, and partly because the engineering side was already in very good hands. The team had some incredibly talented developers, led by Shuyang — a graphics specialist and recent USC grad who also worked on Myth of Lumi.</p><figure class="kg-card kg-image-card"><img src="https://blog.cms.yuhao.app/content/images/2025/08/image-13.png" class="kg-image" alt="" loading="lazy" width="2000" height="1333" srcset="https://blog.cms.yuhao.app/content/images/size/w600/2025/08/image-13.png 600w, https://blog.cms.yuhao.app/content/images/size/w1000/2025/08/image-13.png 1000w, https://blog.cms.yuhao.app/content/images/size/w1600/2025/08/image-13.png 1600w, https://blog.cms.yuhao.app/content/images/size/w2400/2025/08/image-13.png 2400w" sizes="(min-width: 720px) 720px"></figure><p>Working with Ebay on this project taught me so much, especially because of his incredible attention to detail. He really focused on the finer points, like the exact background setting and the era of the game. We spent a lot of time finding that perfect balance between making the world relatable to a modern audience while also giving it a kind of timeless, almost nostalgic feel.</p><p>As an interaction designer, my job was to create detailed interaction design documents. These included everything from how characters look — their height, their clothing, their overall appearance — so that artists could turn those ideas into concept art and eventually 3D models. I also had to document the behaviors of each character or NPC — like what they do when they’re idle, or how they react when they see the balloon. Are they going to jump up and try to grab it? Are they going to tie a message to it and send it along to someone else? All of these details had to be described clearly so that the engineers could bring them to life in code.</p><p>But the most important part of this process was thinking about the characters’ backstories and, ultimately, their relationship to hope. Each character’s attitude toward hope shapes how they respond to the balloon, and that’s really what makes the game feel like a living, breathing poem.</p><p>But the real heroes of this project were the artists, engineers, and especially my friend Justin, who worked as the level designer. In just about a month, the artists created these incredibly detailed 3D characters with a super charming art style, full of life and personality. The engineers managed to implement a ton of features that brought the story to life, packing all these emotional highs and lows into a simple 15-minute experience. We had moments where the wind would push the balloon, characters would grab it and run off, and obstacles would pop up, all making the game feel dynamic and engaging.</p><p>Justin, our level designer, really thought through the emotional journey we wanted players to experience. He focused on how to teach players to interact with the balloon naturally, making sure they understood the mechanics and could enjoy the game fully. And I can’t forget the amazing musicians who created the score that tied everything together and gave the game its poetic heart.<br></p><figure class="kg-card kg-image-card"><img src="https://blog.cms.yuhao.app/content/images/2025/08/image-14.png" class="kg-image" alt="" loading="lazy" width="794" height="446" srcset="https://blog.cms.yuhao.app/content/images/size/w600/2025/08/image-14.png 600w, https://blog.cms.yuhao.app/content/images/2025/08/image-14.png 794w" sizes="(min-width: 720px) 720px"></figure><p><br>Of course, none of this would have happened without Ebay, who worked tirelessly — sometimes with barely any sleep — to bring it all together. And, impressively, he managed all this while also working as a translator with me during the Seasun Games visit to USC. I’m incredibly proud of what our team created for the game jam.</p><p>Update: We ended up receive a nomination from the game jam and the team is invited to see Jenova Chen. Unfortunately, I wasn't able to meet him as I wasn't in China during the time. But here are some fun pictures from my good friend Justin Huang:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.cms.yuhao.app/content/images/2025/08/image-15.png" class="kg-image" alt="" loading="lazy" width="1920" height="1080" srcset="https://blog.cms.yuhao.app/content/images/size/w600/2025/08/image-15.png 600w, https://blog.cms.yuhao.app/content/images/size/w1000/2025/08/image-15.png 1000w, https://blog.cms.yuhao.app/content/images/size/w1600/2025/08/image-15.png 1600w, https://blog.cms.yuhao.app/content/images/2025/08/image-15.png 1920w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Members that was able to travel to Shanghai</span></figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.cms.yuhao.app/content/images/2025/08/image-16.png" class="kg-image" alt="" loading="lazy" width="1080" height="1440" srcset="https://blog.cms.yuhao.app/content/images/size/w600/2025/08/image-16.png 600w, https://blog.cms.yuhao.app/content/images/size/w1000/2025/08/image-16.png 1000w, https://blog.cms.yuhao.app/content/images/2025/08/image-16.png 1080w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Justin's "holy artifact"</span></figcaption></figure>]]></description>
            <link>https://yuhao.app/blog/making-of-letgo</link>
            <guid isPermaLink="true">https://yuhao.app/blog/making-of-letgo</guid>
            <pubDate>Fri, 29 Aug 2025 07:56:14 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Translating Disney]]></title>
            <description><![CDATA[<p>A week ago I got paid to go to Disneyland. I was invited to be a translator for a group of executives from Amazing Seasun Games who were visiting USC for a two-week summer program. Professor David White, their guide and video game producer and veteran, has been to the park over 300 times. Me on the other hand, have only visited Disneyland and California Adventure once with family. So this turned out to be quite a learning experience for me as well, and here are a few notes I took.</p><figure class="kg-card kg-image-card"><img src="https://blog.cms.yuhao.app/content/images/2025/08/image-4.png" class="kg-image" alt="" loading="lazy" width="1024" height="768" srcset="https://blog.cms.yuhao.app/content/images/size/w600/2025/08/image-4.png 600w, https://blog.cms.yuhao.app/content/images/size/w1000/2025/08/image-4.png 1000w, https://blog.cms.yuhao.app/content/images/2025/08/image-4.png 1024w" sizes="(min-width: 720px) 720px"></figure><p>Disneyland isn’t just a theme park. It’s structured storytelling. Every object, path, and landmark is placed intentionally. David pointed out the “Weenie” — a visual magnet, like the castle, that pulls guests through space. It’s basic spatial psychology, but executed at scale.</p><p></p><figure class="kg-card kg-image-card"><img src="https://blog.cms.yuhao.app/content/images/2025/08/image-5.png" class="kg-image" alt="" loading="lazy" width="1024" height="768" srcset="https://blog.cms.yuhao.app/content/images/size/w600/2025/08/image-5.png 600w, https://blog.cms.yuhao.app/content/images/size/w1000/2025/08/image-5.png 1000w, https://blog.cms.yuhao.app/content/images/2025/08/image-5.png 1024w" sizes="(min-width: 720px) 720px"></figure><p>The original park was built at a smaller scale on purpose. Doors, windows, fences—slightly undersized so children feel like they are grownups. Quite cool!</p><figure class="kg-card kg-image-card"><img src="https://blog.cms.yuhao.app/content/images/2025/08/image-6.png" class="kg-image" alt="" loading="lazy" width="480" height="360"></figure><p>Even old rides like Snow White are built narratively. The queue introduces characters. The ride pays it off. It’s a common story structure—setup, delivery, resolution. But the ride that really demonstrates that is Rise of the Resistance in Star Wars: Galaxy's Edge. Rise of the Resistance is both a technological marvel and a storytelling masterpiece. It employs almost all narrative techniques as well as technologies available to themed entertainment industry.<br></p><figure class="kg-card kg-image-card"><img src="https://blog.cms.yuhao.app/content/images/2025/08/image-7.png" class="kg-image" alt="" loading="lazy" width="1024" height="768" srcset="https://blog.cms.yuhao.app/content/images/size/w600/2025/08/image-7.png 600w, https://blog.cms.yuhao.app/content/images/size/w1000/2025/08/image-7.png 1000w, https://blog.cms.yuhao.app/content/images/2025/08/image-7.png 1024w" sizes="(min-width: 720px) 720px"></figure><p>Underneath Sleeping Beauty Castle is a special spot—where Walt Disney himself once stood.</p><figure class="kg-card kg-image-card"><img src="https://blog.cms.yuhao.app/content/images/2025/08/image-8.png" class="kg-image" alt="" loading="lazy" width="2000" height="813" srcset="https://blog.cms.yuhao.app/content/images/size/w600/2025/08/image-8.png 600w, https://blog.cms.yuhao.app/content/images/size/w1000/2025/08/image-8.png 1000w, https://blog.cms.yuhao.app/content/images/size/w1600/2025/08/image-8.png 1600w, https://blog.cms.yuhao.app/content/images/size/w2400/2025/08/image-8.png 2400w" sizes="(min-width: 720px) 720px"></figure><p>Walt Disney love trains, and that's why there are so many trains in the park. He also had a model train built at the backyard of his home</p><figure class="kg-card kg-image-card"><img src="https://blog.cms.yuhao.app/content/images/2025/08/image-9.png" class="kg-image" alt="" loading="lazy" width="768" height="1024" srcset="https://blog.cms.yuhao.app/content/images/size/w600/2025/08/image-9.png 600w, https://blog.cms.yuhao.app/content/images/2025/08/image-9.png 768w" sizes="(min-width: 720px) 720px"></figure><p>You can buy a giant turkey leg in the park, and it's one of the juciest turkey I had (they usually are so dry).</p>]]></description>
            <link>https://yuhao.app/blog/translating-disney</link>
            <guid isPermaLink="true">https://yuhao.app/blog/translating-disney</guid>
            <pubDate>Fri, 29 Aug 2025 07:51:24 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[★Villains]]></title>
            <description><![CDATA[<figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/V-ETDTXUnB0?start=623&amp;feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" title="Aaron Sorkin Answers Screenwriting Questions From Twitter | Tech Support | WIRED"></iframe></figure><p>Aaron Sorkin, when asked how to portray a villain characters, says</p><blockquote>"You (the author) cannot think of them as a villain. You can't judge the character… You have to be able to empathize with that character. Find something about that character that is like you too. And you have to write that character like they're making their case to God why they should be allowed to heaven. "</blockquote><p>There was an attack last weekend at the No King’s protest in Salt Lake City, Utah, where a bystander—fashion designer Arthur Foals An Loo—was shot and killed. The incident received little attention because, over the same weekend, a man named Vance Luther Boelter assassinated Minnesota legislator Melissa Hortman and her husband. Earlier that morning, Boelter had also shot and critically injured State Senator John Hoffman and his wife. Boelter also killed Hortman's family rescued dog Gilbert — a golden retriever, who was ‘too happy-go-lucky’ to be a service dog.</p><p><a href="https://x.com/paulg/status/1934326916221165663">Mike Lee</a>, a U.S. Senator from Utah, tweeted, “This is what happens. When Marxists don’t get their way,” baselessly suggesting that Boelter was a Marxist. However, as many people—including <a href="https://x.com/paulg/status/1934326916221165663">Paul Graham</a>—have pointed out, Boelter was actually a conservative who voted for Trump in the last election.</p><p>I find it very hard to portray Senator Lee and <a href="https://www.nytimes.com/interactive/2022/11/05/us/politics/pelosi-attack-misinfo-republican-politicians.html">his friends</a> as villains.</p>]]></description>
            <link>https://yuhao.app/blog/villains</link>
            <guid isPermaLink="true">https://yuhao.app/blog/villains</guid>
            <pubDate>Fri, 29 Aug 2025 07:49:46 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[★Lessons from The Nest]]></title>
            <description><![CDATA[<p>I recently went to The Nest — an immersive theater experience by Hatch Escapes — with a couple of friends. If you're around LA, I highly recommend it; the experience is both immersive and intimate.</p><figure class="kg-card kg-image-card"><img src="https://blog.cms.yuhao.app/content/images/2025/08/image-3.png" class="kg-image" alt="" loading="lazy" width="2000" height="1500" srcset="https://blog.cms.yuhao.app/content/images/size/w600/2025/08/image-3.png 600w, https://blog.cms.yuhao.app/content/images/size/w1000/2025/08/image-3.png 1000w, https://blog.cms.yuhao.app/content/images/size/w1600/2025/08/image-3.png 1600w, https://blog.cms.yuhao.app/content/images/size/w2400/2025/08/image-3.png 2400w" sizes="(min-width: 720px) 720px"></figure><p>I won't spoil anything, but one of the best moments from the experience was picking up the phone and talking to one of the characters. In a barely lit room filled with detailed props, I was truly transported to the fictional world crafted by the creators. Rest assured, though, The Nest isn't a scary experience at all; it has nothing to do with horror. Nor is it a difficult experience. Right from the start, the staffer told us the experience only has light puzzle elements that mostly serve to enhance the narrative.</p><p>But what's most intriguing to me is that its story is actually quite straightforward — no major twists or turns, no complicated plot devices. What the story truly excels at is clearly conveying a simple narrative to the player through innovative means.</p><p>As an inexperienced writer, one of my most common mistake is trying to make a story novel but ended up making it complicated. I am fortunate enough to attend writing classes of many great movie/game writers at USC. Many of them say every story is a remix of a handful of stores. What this means to me is that one should tell the simplest version of a story and let the audience fill in the gaps.</p><p>Circling back to The Nest, it's an experience designed to last around 90 minutes, with the majority of that time dedicated to players solving puzzles. I'd estimate only about 30 minutes are actually spent on storytelling. Knowing this constraint, the creators wrote a story with the simplest construct. However, by placing this straightforward narrative within a well-crafted and detailed set, the team understood that this was more than enough to truly immerse players.</p>]]></description>
            <link>https://yuhao.app/blog/lessons-from-the-nest</link>
            <guid isPermaLink="true">https://yuhao.app/blog/lessons-from-the-nest</guid>
            <pubDate>Fri, 29 Aug 2025 07:46:08 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Super Hero Movies]]></title>
            <description><![CDATA[<p>I went to watch <em>Thunderbolt* (2025)</em> tonight and it made me excited about what’s next in MCU. I very much look forward to The Fantastic Four and the Avengers film coming next.</p>]]></description>
            <link>https://yuhao.app/blog/super-hero-movies</link>
            <guid isPermaLink="true">https://yuhao.app/blog/super-hero-movies</guid>
            <pubDate>Fri, 29 Aug 2025 07:45:18 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[★Bullies]]></title>
            <description><![CDATA[<p>In early April, the Department of Homeland Security under the Trump administration abruptly and unjustly terminated my SEVIS record. SEVIS is a database used by DHS to verify whether a student is eligible to study in the United States. Losing SEVIS status means an immediate loss of legal standing, the inability to enroll in classes, and the risk of deportation. I’m only able to write about this now because the administration reversed its decision three weeks later.</p><p>When I received the news on April 7th, I had already been studying in the U.S. for nearly a decade. I first came here as a high school exchange student and attended Poston Butte High School, a public school in Arizona. I was the only Chinese student at the school, and the cultural shock was intense. Many other exchange students at different schools returned home early, but I barely managed to hang on and adapt.</p><p>That year was the first time in my life I discovered my potential. Despite the cultural differences, I found myself better suited to life in America than back home. I decided to continue my studies in the U.S. and transferred to Valley Catholic High School in Portland for the remaining two years. There, I was able to take AP classes and challenge myself academically. Switching from a large public school to a private Catholic school gave me one of the most unique perspectives on American education and culture. I was shocked by how unequal America is, especially given how wealthy the country is.<br></p><figure class="kg-card kg-image-card"><img src="https://blog.cms.yuhao.app/content/images/2025/08/image.png" class="kg-image" alt="" loading="lazy" width="1914" height="1216" srcset="https://blog.cms.yuhao.app/content/images/size/w600/2025/08/image.png 600w, https://blog.cms.yuhao.app/content/images/size/w1000/2025/08/image.png 1000w, https://blog.cms.yuhao.app/content/images/size/w1600/2025/08/image.png 1600w, https://blog.cms.yuhao.app/content/images/2025/08/image.png 1914w" sizes="(min-width: 720px) 720px"></figure><p><br>Ironically, I ended up taking almost all the required courses for a CS degree anyway. But at the time, I lived by the motto “leave no way out,” so I deliberately prevented myself from pursuing a double major. It’s hard to say in hindsight whether that choice was brave or simply naive.</p><figure class="kg-card kg-image-card"><img src="https://blog.cms.yuhao.app/content/images/2025/08/image-1.png" class="kg-image" alt="" loading="lazy" width="2000" height="1500" srcset="https://blog.cms.yuhao.app/content/images/size/w600/2025/08/image-1.png 600w, https://blog.cms.yuhao.app/content/images/size/w1000/2025/08/image-1.png 1000w, https://blog.cms.yuhao.app/content/images/size/w1600/2025/08/image-1.png 1600w, https://blog.cms.yuhao.app/content/images/size/w2400/2025/08/image-1.png 2400w" sizes="(min-width: 720px) 720px"></figure><p><br>UCSC’s AGPM program turned out to be an incredible experience. It was (at the time) ranked among the top 10 game design programs in the country, with outstanding faculty like Robin Hunicke and Elizabeth Swensen. In fact, when I later decided to apply to graduate school, it was Professor Swensen who encouraged me to apply to USC and kindly wrote me a recommendation letter. I remain deeply grateful to her. At UCSC I made two amazing platformers that I remain very proud of WALL-B and Fragments of You. And a slew of mediocre stub games.</p><p>Another Professor I own a lot to is Professor James E Davis. He let me joined his computer graphic research lab - AVIS - as an undergraduate research assistant. He once told me “I have a very promising career ahead of me”. That and what he’s done for me motivated me until today. I had the opportunity to lead an undergraduate student research team under him. He also sponsored me to compete twice in Apple Swift Student Challenge and won both time.</p><p>You may noticed I didn’t mention any of my high school teachers. It’s because I became pretty depressed during high school, so I ended up blocking most of my memories from around that time. Sadly, I forgotten most of their name as a result. Thank you! My 10th degree chemistry teacher, you were excellent. My French teacher — thank you for being easy on me. My 11th degree Math teacher Kipp Johnson, I actually remembered your name because how much I revered you. My English teacher, you are so warm and gentle, you are the reason why I still have a habit of reading. My World History and Government teacher, I hate that you made me memorize the name of every country on earth. And my AP CS teacher, sorry I hacked your website and stole the midterm. Last but not least I’d like to thank my host families Jennifer, Jonathan and Veronica.</p><figure class="kg-card kg-image-card"><img src="https://blog.cms.yuhao.app/content/images/2025/08/image-2.png" class="kg-image" alt="" loading="lazy" width="960" height="540" srcset="https://blog.cms.yuhao.app/content/images/size/w600/2025/08/image-2.png 600w, https://blog.cms.yuhao.app/content/images/2025/08/image-2.png 960w" sizes="(min-width: 720px) 720px"></figure><p>After UCSC I was admitted to USC as an Interactive Media &amp; Games Division MS student. I was supposed to come to the U.S. in Fall of 2023. But during that summer, I was diagnosed with ulcerative colitis (UC) and had an infection so bad I had to be hospitalized for three months three. I ended up missing the Fall 2023 window.</p><p>After I healed, the ensuing year almost became a year of heartbreak. I led a team to raise money from VC, we made it very far only to be excluded at the last round. I was invited to Cupertino by Apple to attend WWDC only to not being able to make it. And throughout the entire year, I was convinced I will not be able to pursue my degree at USC.</p><p>When I finally entered the U.S. on August 2024, I cried in the LAX.</p><p>When I learned the news that my SEVIS was cancelled few weeks ago, I was furious (I still am) — I have endured so many hardships in the past decade. And throughout the entire time I followed the American law. I had no arrest, no charges, and no criminal history. Only to be cancelled without any notification or reasoning.</p><p>I learned about due process and rights in America in 11th grade thanks to my government teacher. I learned the same way all American learned their right.</p><p>This year, I learned those rights doesn’t apply to me. As long as the executive branch have the power to arbitrarily terminate any students’ Visa. We do not enjoy freedom of speech nor due process. What happened to me is cruel and unusual.</p><p>In fact, the existence of this very article may put myself at risk. But if there is one thing I learned in America, that is — you stand against bullies.</p><p>Lastly I like to thank everyone that helped me through past few weeks, it was genuinely difficult, and this time I like to remember them before I forgot. Thanks Professor Danny Bilson, Professor Peter Brinson, Professor Debbie Yuen, Assistant Dean Marcus Anderson, Professor Mark Bolas, Cooper, Justin, Hanwen, Aria, Jerry, E, Chellie, Jason, Ari, Miles, Anthony, Tielong, Xiao, Ebay, Rae, Lisa, Kiwi, Chuke, Olivia, JC, Wenxuan, and everyone else I couldn’t name here. Thank you for making me feel like I belong.</p>]]></description>
            <link>https://yuhao.app/blog/bullies</link>
            <guid isPermaLink="true">https://yuhao.app/blog/bullies</guid>
            <pubDate>Fri, 29 Aug 2025 07:43:05 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[What happened to Only Paranoid Survives?]]></title>
            <description><![CDATA[<p>I am halfway through Tae Kim’s <em>The Nvidia Way</em>, and it’s the 2007 to early 2010s. Nvidia has introduced CUDA and worked with companies like Adobe and Autodesk to enable parallel computing to massively make their applications faster. And I just can’t stop thinking — <em>Oh my god, how is Intel letting this happening</em>. It’s absurd that it’s Intel’s Andy Grove coined the term <em>Only Paranoid Survive</em>, and 1 CEO later that’s all down the shitter.</p><p>Needlessly to say, Intel had another giant miss during the same era — iPhone. The most common version of the Intel’s iPhone story is Apple has approached Intel to design a iPhone chip and Intel passed/not winning it. Apparently, according to <a href="https://stratechery.com/2022/an-interview-with-father-of-the-ipod-tony-fadell/">Tony Fadell</a> . This narrative was not true at all, Apple never considered Intel since their chips were so inefficient. But the point still stands, Intel happily stand on the sidelines and let Samsung then TSMC took this one.</p><p>Here what happened, Intel saw they had deep moats in CPU for decades. So they ignored all the emerging market segments that had lower profit margins and niche addressable market. And when those segments become too big to ignore, they wrongfully believed they can easily integrate new capabilities (integrated graphics) or easily scale down. They allowed their competitors to survive and strive from below. Ironically, the exact same thing happened to Intel in the 80s. When the Intel had to <a href="https://timeline.intel.com/1985/farewell-to-dram">withdraw from their then main business DRAM</a> and focus on logics. Intel forgot <em>Only Paranoid Survives</em>, and proceeded to getting killed in Mobile, GPU, PC, Cloud, and AI.</p>]]></description>
            <link>https://yuhao.app/blog/what-happened-to-only-paranoid-survives</link>
            <guid isPermaLink="true">https://yuhao.app/blog/what-happened-to-only-paranoid-survives</guid>
            <pubDate>Fri, 29 Aug 2025 07:42:26 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Learning to sing alone]]></title>
            <description><![CDATA[<p>In the past, learning to sing alone is one of the biggest hurdles for me in regard to guitar. I can never find the rhythm. Also the moment I started to sing, my playing become messy too. This time though, I decide I want to overcome this hurdle. After two days of practice that turned my fingertips to black. I finally be able to sing alone <em>A Horse With No Name</em> poorly while playing guitar. <a href="https://yuhao.app/video/RhLEn00IxhQDtKDPnE6dj00G01iMKwdZvzsFShZ97r01YA8">You can follow my progress here.</a></p>]]></description>
            <link>https://yuhao.app/blog/learning-to-sing-alone</link>
            <guid isPermaLink="true">https://yuhao.app/blog/learning-to-sing-alone</guid>
            <pubDate>Fri, 29 Aug 2025 07:41:09 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Establishing a Movement Shooter]]></title>
            <description><![CDATA[<p>My friend Coop and I are building a movement shooter together. Shooter as a genre is very popular, and never lacks well designed game. So it is challenging to build something new, novel, while maintain a good sense of design. It’s gonna be a long journey before we get to there. In the meantime, I would like document all the design thinking behind this game. Below is one of the first pieces of deign document written for this game. Cooper wrote it as an email while he was on plane from New York to Los Angeles.</p><hr><p><strong>Yuhao:</strong></p><p>After Peter’s lecture on turning our limitations into features of the game, I realized the best approach is to eliminate any heavy art-related elements. I was also thinking about the mechanics from your previous game, which relied heavily on physics. Right now, in our current design, “physics” mainly show up when a player inputs something, and there’s only minimal interaction with the environment. That got me wondering how we could introduce stronger physics-based interactions between players—and also how to address one of my biggest concerns: finding a compelling gameplay reason for players to move so fast or chain their movements to maintain momentum, aside from just the thrill of speed.</p><p>When I look at movement shooters like Doom Eternal or Quake, I notice Doom Eternal doesn’t really emphasize going “very fast,” but rather continuous movement for dodging bullets and chaining weapon usage. Meanwhile, Quake focuses on speed to grab resources quickly and launch surprise attacks. We both love moving fast, maintaining momentum, and especially chaining different movement mechanics to get massive bursts of speed. But I’m still not fully convinced we’ve found a unique gameplay motivation for that speed beyond the usual “surprise attack” or “resource race.”</p><p>Then I thought about Ace Combat—the dogfights between two high-speed fighter jets. In those games, you don’t get to fire your weapon too often, and controlling your position is key. That concept of a dogfight reminded me of Smash Bros., where aerial movement is crucial to return to the stage after being knocked out. I started wondering if that dogfight idea could serve as the main goal in our game. It seems promising, especially if we replace the traditional health bar with a knockback meter.</p><p>So here’s the idea: a Smash Bros. + movement shooter hybrid. Picture a 1v1 match on a floating island arena with no walls, so players can fall off. Each player has a different ability—say, Player A has a grappling hook, Player B has an air dash—and they only have their bare fists as a “weapon.” Instead of health, there’s a knockback meter that increases each time you get hit, and the higher it is, the farther you’ll be knocked back. The objective is to knock your opponent off the island.</p><p>As the match starts, both players dash toward specific areas to pick up weapons or equipment—things like an air-blast gun (similar to Lucio’s right-click in Overwatch), a grenade that creates walls (like Sage’s wall in Valorant), or a throwable jump pad to alter the level for the whole game. Each item has limited uses (maybe 1–3), so players have to keep searching for more. You can only carry one or two at a time. The “first phase” is grabbing these items, and the “second phase” is the dogfight, using everything you’ve collected. If we make the movement system flexible and momentum-based, I think we’ll see a lot of cool, emergent plays.</p><p>The game cycles between these two phases—collecting and fighting—until a “knockout phase” occurs. For example, if Player B’s meter is high and they get knocked off, they’ll have to use every ability and gadget to get back. That tests how well they know their own tools. If they recover, the fight goes on; if they fail, they fall and lose, or we could do a Smash Bros.-style stock system.</p><p>I believe this setup is straightforward and addresses my concern about motivation for fast movement. I’m not entirely sure if everything will work perfectly, but it combines what we both love, and it seems like a fresh take. I don’t know any shooter that does this, and it fits our goal of pushing everything to the limit instead of making something mediocre.</p><p><strong>Coop</strong></p>]]></description>
            <link>https://yuhao.app/blog/establishing-a-movement-shooter</link>
            <guid isPermaLink="true">https://yuhao.app/blog/establishing-a-movement-shooter</guid>
            <pubDate>Fri, 29 Aug 2025 07:40:19 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Learning to strum again]]></title>
            <description><![CDATA[<p>haven’t touched, or seen, my guitar, or any guitar, since the pandemic. Now that I have her again, I decided to learn a song —— A Horse With No Name by America. The song is very friendly, I was able to pick it up pretty quick. The song only has two chords Em and D6/9, I still remember several chords from back then, so I had no trouble with those. But it turned out I can no longer keep a beat while strumming. It took me roughly an hour to learn this strum, and with a little more practice I am now able to do it somewhat consistently. I tried to sing alone but I struggle to find the rhythm. That’s problem for another day. In the meantime, <a href="https://yuhao.app/video/MvBHjc3X02AE3r9AXBdSucsRFvI5lUjAhJ9pvk9svJsY">here is what I can do so far ⭐️</a>.</p>]]></description>
            <link>https://yuhao.app/blog/learning-to-strum-again</link>
            <guid isPermaLink="true">https://yuhao.app/blog/learning-to-strum-again</guid>
            <pubDate>Fri, 29 Aug 2025 07:39:17 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Game testing and software testing]]></title>
            <description><![CDATA[<p>One of the things I am always wondering is why don’t software do playtesting like the way gaming does. Being in both fields, I found user experience research in game and software are quite different:</p><p>In software, testing usually happens in productions, either during official or beta releases. These tests are highly data driven, large scale, and often invisible to the participants. Takes A/B testing for example, a method that compare two (or more) design variations, rolls out to hundreds of thousands of live users; key outcome metrics like conversion, click rates, and etc. are measured to highlight any statistical significances. And afterward product manager would analyze these data and provide insights and assumptions into potential behavior changes, as well as actionable decisions and tasks. While these testing are great at revealing users preferences. They often fail to provide larger context in design; require you to have a sizable audience to start with; and they can stifle innovative idea as user preferences could be wrong. For example, another form a testing common used in software is user testing, And if we had conduct one of this on smartphone users back in 2007, asking whether they preferred BlackBerry’s physical keyboard or newly created iOS’s on-screen keyboard. Odds are, the physical keyboard would have won by a landslide, given its familiarity and track record. But had those early tests dictated the product direction, the breakthrough of the modern software keyboard might never have taken off.</p><p>Which is why I believe that playtesting—the favorite methodology of game designers—should be adopted in software development as well. The goal of playtesting is to provide designers with an empirical understanding of their product. Playtesting begins as soon as you start building and continues throughout the entire development and design process.</p><p>These tests are conducted on a very small scale, often involving colleagues, friends, and family members. The rules are straightforward:</p><ol><li>Think Aloud: Testers need to verbalize their thoughts while using the product.</li><li>Minimal Guidance: You refrain from explaining or guiding them throughout the process, unless they become truly stuck.</li><li>Inquire About Decisions: Ask them how they think and why they clicked one button instead of another.</li><li>Regular Sessions: Conduct playtesting sessions regularly and frequently—weekly, every other day, or even daily.</li><li>Open to Feedback: Be open to disagreeing with what testers say.</li><li>Team Involvement: Ensure that you and everyone on your team are present to observe the testing.</li></ol><p>That’s all there is to it!</p><p>For those immersed in data-driven design, it will be difficult to wrap your head around why playtesting is an effective tool without actually trying it. However, I can share why I believe it’s invaluable:</p><ol><li>Identify Design Flaws: Watching a user struggle with your design makes the issues painfully clear and obvious.</li><li>Discover New Ideas: You often uncover new ideas by observing how others interact with your product.</li><li>Enhance Team Engagement: Your team becomes more engaged with the product through the playtesting process. I can’t tell you how motivated it is to watch user responds to your work. And it lights people asses on fire when they realize the product have major flaws.</li></ol><p>Simply, it will just tell you which design needs more work and motivate you to do it. Moreover, the 3 points I just gave you are what I personally found valuable. If you want to learn more I recommend this video by Game Maker’s Toolkit:</p><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/9Yomqk0C6kE?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" title="Valve's &quot;Secret Weapon&quot;"></iframe></figure>]]></description>
            <link>https://yuhao.app/blog/game-testing-and-software-testing</link>
            <guid isPermaLink="true">https://yuhao.app/blog/game-testing-and-software-testing</guid>
            <pubDate>Fri, 29 Aug 2025 07:38:16 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Complicated V.S. Complex]]></title>
            <description><![CDATA[<p>Recently, I ran into an interesting explanation of how to distinguish a production process that’s complicated versus complex. A complicated process is a linear process that takes many steps to make, and each step is difficult in its own right. And a complex process is a system that consist of many simple modules, and it’s difficulty lie in the integration between these modules.</p><p>I learnt this definition from my Professor Peter Brinson, and he was teaching about game production process. For example, a narrative game would often be a more complicated process and is difficult to pivot once you get started. You can’t really pivot a story and expect to keep most of the script. Whereas, a platformer would be complex and easier to pivot half-way through. You can change your core mechanics and rest of your system would work just fine.</p><p>But I found these concepts are useful for other process too, like startups. Generally they can be divided into two categories. Those who tackle complicated problems (like semiconductors), and those who tackle the complex problems (like software).</p>]]></description>
            <link>https://yuhao.app/blog/complicated-vs-complex</link>
            <guid isPermaLink="true">https://yuhao.app/blog/complicated-vs-complex</guid>
            <pubDate>Fri, 29 Aug 2025 07:37:40 GMT</pubDate>
        </item>
    </channel>
</rss>