<?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[Hao Luo Dev Notes]]></title><description><![CDATA[Hao Luo Dev Notes]]></description><link>https://haoluo.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Tue, 03 Nov 2026 04:29:24 GMT</lastBuildDate><atom:link href="https://haoluo.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Prompt Notes for Image-to-Image Pet Portraits: Keeping a Dog Recognizable When It Becomes a Person]]></title><description><![CDATA[Turning a photo of a dog into a human portrait is a fun image-to-image problem with a surprisingly hard failure mode: the result is a nice-looking person…]]></description><link>https://haoluo.hashnode.dev/prompt-notes-for-image-to-image-pet-portraits-keeping-a-dog-recognizable-when-it-becomes-a-person</link><guid isPermaLink="true">https://haoluo.hashnode.dev/prompt-notes-for-image-to-image-pet-portraits-keeping-a-dog-recognizable-when-it-becomes-a-person</guid><category><![CDATA[artificial-intelligenceprompt-engineering]]></category><category><![CDATA[image generation]]></category><dc:creator><![CDATA[Hao Luo]]></dc:creator><pubDate>Tue, 03 Nov 2026 02:13:46 GMT</pubDate><content:encoded><![CDATA[<p>Turning a photo of a dog into a human portrait is a fun image-to-image problem with a surprisingly hard failure mode: the result is a nice-looking person who has nothing to do with the dog. These are my working notes on what actually carries identity across that jump, written from the point of view of someone building prompts and input pipelines rather than training models.</p>
<h2>1. Decide what "the same" means</h2>
<p>A dog and a person share almost no geometry, so pixel-level similarity is the wrong target. What people recognise is a handful of traits:</p>
<ul>
<li><strong>Eyes</strong>: colour, shape, and especially the direction and softness of the gaze.</li>
<li><strong>Colour palette</strong>: coat colours and markings, which map naturally to hair colour, skin tone, clothing and accessories.</li>
<li><strong>Expression and energy</strong>: a calm senior Labrador and a hyper terrier should not produce the same face.</li>
</ul>
<p>If you write these down as explicit attributes before generation, you can check the output against them instead of judging "vibes".</p>
<h2>2. Extract attributes, then prompt with them</h2>
<p>A reliable pattern is two steps:</p>
<ol>
<li>Describe the input photo in structured terms (eye colour, coat colours and where they appear, ear shape, mood).</li>
<li>Build the generation prompt from that description, translating each trait into a human equivalent, for example a tan-and-black coat becoming dark hair with warm brown highlights, or a white blaze becoming a light scarf or streak.</li>
</ol>
<p>Keeping the mapping explicit makes results more consistent across retries, and it lets the user override a single trait without rewriting everything.</p>
<h2>3. Give the user a few strong controls, not twenty weak ones</h2>
<p>In practice four controls cover most intent: gender (or automatic), age group, visual style (realistic, cinematic, illustrated, editorial), and personality. Personality is the underrated one: words like "loyal", "playful" or "goofy" change posture and expression far more than adding adjectives about the face.</p>
<h2>4. Input quality matters more than prompt length</h2>
<p>Most bad outputs come from bad inputs. The photos that work best are a single dog, front-facing, with both eyes visible, good light, and no heavy filters. Side profiles and group shots force the model to guess, and guesses drift toward a generic face. A short checklist shown before upload saves more credits than any prompt trick.</p>
<h2>5. Video is a different problem</h2>
<p>For a short reveal clip, the same identity attributes apply, but you also need to describe motion and camera direction separately (for example a slow push-in, then a turn toward camera). Mixing appearance and motion into one long sentence tends to weaken both.</p>
<h2>6. Privacy defaults</h2>
<p>Pet photos often include people, homes and locations in the background. Reasonable defaults are: keep the image as a local preview until the user explicitly presses generate, screen prompts for safety, and make deletion of uploads and results easy to request.</p>
<h2>Try it</h2>
<p>I put these ideas into a small web app, <a href="https://dogtohuman.com/">DogHuman AI</a>, which turns one dog photo into a human portrait or short video and has demo dogs you can try without signing up. Even if you build your own pipeline, the attribute-first approach above is the part I would keep.</p>
]]></content:encoded></item><item><title><![CDATA[How to Calculate the Four Pillars (BaZi) in Code: Solar Terms, Stems and Branches]]></title><description><![CDATA[The Chinese Four Pillars system (BaZi, 八字) turns a birth moment into four pairs of characters. Each pair is a Heavenly Stem plus an Earthly Branch, so the…]]></description><link>https://haoluo.hashnode.dev/how-to-calculate-the-four-pillars-bazi-in-code-solar-terms-stems-and-branches</link><guid isPermaLink="true">https://haoluo.hashnode.dev/how-to-calculate-the-four-pillars-bazi-in-code-solar-terms-stems-and-branches</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[algorithms]]></category><category><![CDATA[webdev]]></category><dc:creator><![CDATA[Hao Luo]]></dc:creator><pubDate>Wed, 28 Oct 2026 04:39:10 GMT</pubDate><content:encoded><![CDATA[<p>The Chinese Four Pillars system (BaZi, 八字) turns a birth moment into four pairs of characters. Each pair is a Heavenly Stem plus an Earthly Branch, so the chart has eight characters in total. Computing them looks like calendar trivia, but it is a fun exercise in modular arithmetic and in why "just use the date" often fails. Here is how the pieces fit together.</p>
<h2>The 60-cycle of stems and branches</h2>
<p>There are 10 Heavenly Stems (甲 Jia, 乙 Yi, 丙 Bing, 丁 Ding, 戊 Wu, 己 Ji, 庚 Geng, 辛 Xin, 壬 Ren, 癸 Gui) and 12 Earthly Branches (子 Zi, 丑 Chou, 寅 Yin, 卯 Mao, 辰 Chen, 巳 Si, 午 Wu, 未 Wei, 申 Shen, 酉 You, 戌 Xu, 亥 Hai).</p>
<p>Stems and branches advance together, one step at a time. Because lcm(10, 12) = 60, the combined pair repeats every 60 steps. Only pairs with matching parity (yang stem with yang branch) occur, which is why you get 60 combinations instead of 120. So every pillar can be represented as an index from 0 to 59: stem = index % 10, branch = index % 12. Index 0 is Jia-Zi, index 1 is Yi-Chou, and so on.</p>
<h2>Year and month pillars: solar terms, not Jan 1</h2>
<p>A common bug is using the Gregorian year or the lunar new year for the year pillar. BaZi uses the solar calendar: the year changes at Li Chun (立春, "Start of Spring"), around February 3 to 5, when the sun reaches ecliptic longitude 315 degrees. Someone born on January 20 belongs to the previous BaZi year.</p>
<p>Months work the same way. The 12 month pillars start at the 12 "Jie" solar terms (Li Chun, Jing Zhe, Qing Ming, and so on), not at lunar months and not on the 1st of the Gregorian month. The month branch is fixed by the term: Li Chun to Jing Zhe is the Tiger (Yin) month, then Rabbit, Dragon, and so on. The month stem is then derived from the year stem with a fixed rule (for a Jia or Ji year, the Tiger month starts with Bing).</p>
<p>The catch: solar term moments are astronomical events, with a specific minute that varies each year. If someone is born on the day of a term, you need the exact timestamp of the term to know which side of the boundary they fall on.</p>
<h2>Day pillar: a day-count offset</h2>
<p>The day pillar has no astronomical rule. The 60-day cycle has simply been running without interruption for thousands of years. So you pick a reference date whose day pillar you know, count the days between it and the target date, and take the result modulo 60.</p>
<p>For example, 1949-10-01 is commonly cited as a Jia-Zi day (index 0). Verify any reference against a trusted almanac before relying on it.</p>
<h2>Hour pillar: 2-hour branches and the five-rat rule</h2>
<p>A day is split into twelve 2-hour periods, each with a branch. The Rat (Zi) hour runs 23:00 to 01:00, Ox (Chou) 01:00 to 03:00, and so on. The hour branch index is therefore floor((hour + 1) / 2) % 12.</p>
<p>The hour stem follows the "five rat" rule (五鼠遁): the stem of the Zi hour depends on the day stem. For Jia or Ji days it is Jia, for Yi or Geng days Bing, for Bing or Xin days Wu, for Ding or Ren days Geng, and for Wu or Gui days Ren. Equivalently, the Zi-hour stem is (dayStem % 5) * 2, and each following hour adds one stem. There is also a convention question about whether the late Zi hour (23:00 to 24:00) belongs to the current or the next day.</p>
<h2>A JavaScript snippet for the day pillar</h2>
<pre><code class="language-javascript">const STEMS = ["Jia","Yi","Bing","Ding","Wu","Ji","Geng","Xin","Ren","Gui"];
const BRANCHES = ["Zi","Chou","Yin","Mao","Chen","Si","Wu","Wei","Shen","You","Xu","Hai"];

// Reference: 1949-10-01 is a Jia-Zi day (index 0)
const REFERENCE_UTC = Date.UTC(1949, 9, 1);
const OFFSET = 0;

function dayPillar(year, month, day) {
  // month is 1-12; using UTC midnight avoids DST problems
  const target = Date.UTC(year, month - 1, day);
  const daysSinceReference = Math.round((target - REFERENCE_UTC) / 86400000);
  const index = (((daysSinceReference + OFFSET) % 60) + 60) % 60;
  return { index, stem: STEMS[index % 10], branch: BRANCHES[index % 12] };
}

console.log(dayPillar(2000, 1, 1)); // check against an almanac
</code></pre>
<p>The double modulo handles dates before the reference, where JavaScript's % returns negative numbers.</p>
<h2>What real implementations need</h2>
<p>This snippet only covers the easy part. A production-quality calculator also needs precise solar-term timestamps (from an ephemeris or a good table, down to the minute), careful timezone handling (convert the birth time to the correct local time, and often to true solar time based on longitude), and a decision about the late-Zi-hour convention. Historical timezone and daylight saving changes are the usual source of off-by-one-pillar bugs.</p>
<p>I built a free calculator that does this at <a href="https://bazi-calculator.app/">https://bazi-calculator.app/</a>. If you spot a case where your results differ, comparing the solar-term boundary is the first thing to check.</p>
]]></content:encoded></item></channel></rss>