<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title/><link>https://changshenghsun.com/</link><atom:link href="https://changshenghsun.com/index.xml" rel="self" type="application/rss+xml"/><description/><generator>HugoBlox Kit (https://hugoblox.com)</generator><language>en-us</language><lastBuildDate>Mon, 24 Oct 2022 00:00:00 +0000</lastBuildDate><image><url>https://changshenghsun.com/media/icon_hu_d41247041d33f7ba.png</url><title/><link>https://changshenghsun.com/</link></image><item><title>GridStage</title><link>https://changshenghsun.com/projects/gridstage/</link><pubDate>Sat, 20 Jun 2026 00:00:00 +0000</pubDate><guid>https://changshenghsun.com/projects/gridstage/</guid><description>&lt;p&gt;&lt;strong&gt;2026 — in active development&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="why-i-built-this"&gt;Why I built this&lt;/h2&gt;
&lt;p&gt;As a dancer, formations were always the part nobody wanted to handle. How do you
place everyone so the stage actually looks right? Will two people run into each
other halfway through a transition? Those questions bothered me every time we
put a piece together. I went looking for an open-source tool and there was
none — and I was not about to pay a subscription for the commercial ones. So I
built &lt;strong&gt;GridStage&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="what-it-is"&gt;What it is&lt;/h2&gt;
&lt;p&gt;A top-down 2D stage where you place performers, add formations along a timeline
synced to the music, and preview the walk-in transitions in 2D or 3D. It exports
walk-chart PDFs (one page per dancer), videos, and GIFs. Several people can edit
the same piece at once — live cursors, presence, and undo that only reverts your
own changes — over a CRDT, a data structure where concurrent edits merge without
a central referee.
The part I care most about is the vision pipeline: pause a rehearsal video on a
formation, click the four stage corners once, and the app detects the dancers,
maps their foot positions onto the stage floor, and drops them into the editor
as a normal editable formation. All of it runs in the browser.&lt;/p&gt;
&lt;h2 id="where-it-stands"&gt;Where it stands&lt;/h2&gt;
&lt;p&gt;v0.8.6 · 130 commits · ~16k lines of strict-mode TypeScript in a pnpm monorepo ·
24 unit-test files plus a Playwright end-to-end suite. Three ways to run it, none
requiring an account: a Windows/macOS desktop app, an installable PWA that works
offline on a phone, and a Docker self-host stack.&lt;/p&gt;
&lt;p&gt;Measured, not claimed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;60 performers × 4 formations&lt;/strong&gt; in a permanent end-to-end stress test —
dragging stays accurate and playback holds ~57 fps (CI floor 20).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Video → formation capture&lt;/strong&gt; runs entirely client-side (YOLOX-nano through
onnxruntime-web, WebGPU with a wasm fallback): 6 of 7 dancers recovered from a
real six-dancer rehearsal photo, ~1.8 s per frame on CPU alone. Zero server
cost, and no one&amp;rsquo;s rehearsal footage leaves their laptop.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Against &lt;strong&gt;ArrangeUs&lt;/strong&gt;, the category leader, and the other commercial formation
apps I audited before starting, these are the things they do not do at all
(checked July 2026; their feature lists do move):&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;GridStage&lt;/th&gt;
&lt;th&gt;ArrangeUs &amp;amp; other commercial apps&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Real-time multi-user editing&lt;/td&gt;
&lt;td&gt;CRDT (Yjs) — live cursors, presence, per-user undo&lt;/td&gt;
&lt;td&gt;one editor at a time, files passed around&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Formations captured from a rehearsal video&lt;/td&gt;
&lt;td&gt;on-device detection + homography&lt;/td&gt;
&lt;td&gt;nothing on the market does this&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rehearsal-vs-plan review&lt;/td&gt;
&lt;td&gt;per-dancer drift, C-position centering, left–right asymmetry&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transition collision warnings&lt;/td&gt;
&lt;td&gt;Hungarian matching + sweep-line crossing detection&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3D preview&lt;/td&gt;
&lt;td&gt;camera presets + follow-a-performer&lt;/td&gt;
&lt;td&gt;limited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Video / GIF export with music&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;limited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Price and licence&lt;/td&gt;
&lt;td&gt;free, MIT, self-hostable&lt;/td&gt;
&lt;td&gt;subscription, closed source&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The place I am clearly behind is distribution, not capability: ArrangeUs has
457k+ users and years of tutorials, GridStage has an install page.&lt;/p&gt;
&lt;h2 id="whats-next"&gt;What&amp;rsquo;s next&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Building a user community.&lt;/strong&gt; The capability gap is closed; the distribution
one is not. Demo videos and an in-app guide are already in progress, and the
next step is getting the editor in front of real dance teams and cheer squads
and running on their feedback — the work that decides whether GridStage stays
a portfolio piece or becomes a tool people actually choreograph with.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Accounts and cloud sync.&lt;/strong&gt; Today a piece lives on one machine and travels as
a &lt;code&gt;.gridstage&lt;/code&gt; file. This is the largest remaining gap against commercial
tools, and the one architectural decision I still owe the project — self-host
or a hosted backend.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Full rehearsal-vs-plan deviation report.&lt;/strong&gt; The first cut compares one paused
frame against the plan. Scanning a whole rehearsal into a per-formation error
timeline is the version that closes the plan → rehearse → correct loop, and
it is the hardest part for anyone to copy.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stage lighting and cue sheets.&lt;/strong&gt; Colored lights on the 2D stage and a 3D
wash, cues on the timeline, exported as a printable cue sheet — the other half
of what a stage manager actually needs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Plugins and a community template library&lt;/strong&gt;, so formation libraries can grow
without me writing every one of them.&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>MakeNTU</title><link>https://changshenghsun.com/projects/makentu/</link><pubDate>Fri, 08 May 2026 00:00:00 +0000</pubDate><guid>https://changshenghsun.com/projects/makentu/</guid><description>&lt;p&gt;&lt;strong&gt;May 8–10, 2026&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="the-brief"&gt;The brief&lt;/h2&gt;
&lt;p&gt;AUO makes display panels, and the sponsor prompt came down to a single
question: if the windshield itself becomes the display, what is actually worth
putting on it? The easy answer is a bigger speedometer. We treated it as an
interface problem instead — the glass should show what the driver&amp;rsquo;s current
state calls for, and stay out of the way otherwise.&lt;/p&gt;
&lt;h2 id="what-we-built"&gt;What we built&lt;/h2&gt;
&lt;p&gt;A first-person driving simulator that runs entirely in the browser, built on
real map data: the Xinyi district road network pulled live from OpenStreetMap
Overpass, routes from OSRM, and procedurally generated buildings filling the
blocks in between. Four scenarios ship — city, highway, coastal drive, and a
parked rest stop.&lt;/p&gt;
&lt;p&gt;The windshield is composed in four layers, so the result reads as glass rather
than as a game overlay:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;What is in it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;4 · Glass&lt;/td&gt;
&lt;td&gt;Vignette, film grain, top tint, A-pillars and mirror silhouettes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3 · HUD&lt;/td&gt;
&lt;td&gt;Frosted DOM/SVG panels — speed, compass, nav card, ETA, climate, now playing, minimap&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2 · AR&lt;/td&gt;
&lt;td&gt;POI cards projected into screen space onto building facades, fading when occluded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1 · World&lt;/td&gt;
&lt;td&gt;Three.js — roads, buildings, cabin, traffic agents, route arrows, destination pillar&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;And the subsystems that make it more than a renderer:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Subsystem&lt;/th&gt;
&lt;th&gt;How it works&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Driver monitoring&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;MediaPipe FaceLandmarker blendshapes feed one state machine with two outputs. Hard warning: both eyes shut past 1.2 s, cooldown-gated so it does not machine-gun at a driver who is genuinely asleep. Continuous 0–1 fatigue score: rolling PERCLOS (a one-minute EMA of eyelid closure) combined with yawn rate — a jaw held open past 0.55 for 800 ms counts as a yawn, over a two-minute window.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fatigue-driven HUD&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The score is the interesting half. As fatigue climbs the HUD raises contrast on rear traffic, sheds non-essential chrome, and drifts wake-up particles across the glass — the display responds to the driver instead of shouting at them.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Head-pose lane-change intent&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Looking more than 18° to one side for 800 ms reads as a shoulder check, and the panel surfaces rear traffic in that adjacent lane. Releases at a looser 8° with a 500 ms cooldown — hysteresis, so a brief glance forward does not flicker the panel on and off.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Door-opening safety gate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;In rest mode the car is parked roadside with traffic flowing past. Asking to get out forward-simulates the traffic schedule: if any vehicle will come within 12 m of the door in the next 4 s the gate stays red, otherwise a tap confirms.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Voice + AI reservation call&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Speech recognition is always listening. Say 「找餐廳」and five nearby POIs come back from Overpass; pick one by number and the in-car assistant dials it, speaking a reservation script over TTS while the overlay renders the transcript as chat bubbles. Phone numbers carry a separate spoken form so Chinese TTS reads them digit by digit instead of turning 09 into a place value.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Four-screen cabin&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Each screen runs the same app with &lt;code&gt;?role=driver / passenger / left / right&lt;/code&gt;. The driver publishes state snapshots to a small WebSocket relay that fans them out unparsed; each role applies its own camera offset — passenger 0.45 m inboard of the right door, side windows yawed ±90° — and keeps its own mouse-look on top, so a passenger can still turn their head independently.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Physical steering wheel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You drive it with an actual wheel. Steering angle comes off a six-axis IMU (three-axis accelerometer plus gyroscope) mounted on the wheel itself, so the rotation is read directly from how the wheel moves — no shaft encoder or mechanical end-stops to fabricate in three days. An Arduino Nano packages the reading as one JSON line per packet at 115200 baud, roughly 20 packets a second, which the browser reads through Web Serial. Every value is clamped on arrival so a noisy reading cannot push the vehicle physics past its own caps, and the 60 fps render interpolates between packets rather than stepping.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
&lt;figure id="figure-demoing-to-the-judges--hands-on-the-laser-cut-control-rig-the-simulator-running-on-the-screen-in-front-of-me"&gt;
&lt;div class="flex justify-center "&gt;
&lt;div class="w-full" &gt;
&lt;img alt="Demoing the simulator to the judges with hands on the laser-cut control rig"
srcset="https://changshenghsun.com/projects/makentu/judging-demo_hu_ba6de5e9835c4b8.webp 320w, https://changshenghsun.com/projects/makentu/judging-demo_hu_769bc8dca1b8db81.webp 480w, https://changshenghsun.com/projects/makentu/judging-demo_hu_cbdeeb749b3a6359.webp 760w"
sizes="(max-width: 480px) 100vw, (max-width: 768px) 90vw, (max-width: 1024px) 80vw, 760px"
src="https://changshenghsun.com/projects/makentu/judging-demo_hu_ba6de5e9835c4b8.webp"
width="760"
height="507"
loading="lazy" data-zoomable /&gt;&lt;/div&gt;
&lt;/div&gt;&lt;figcaption&gt;
Demoing to the judges — hands on the laser-cut control rig, the simulator running on the screen in front of me.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id="my-role"&gt;My role&lt;/h2&gt;
&lt;p&gt;I was the team lead. The sponsor prompt named a display, not a product, so most
of the work up front was deciding what a windshield should actually do — I ran
that ideation with the team, and then led the software side through to a working
demo. My own commits landed the highway, coastal and rest-stop scenarios, the
driver-monitoring pipeline and everything the fatigue score drives, collision
handling, the head-pose lane-change intent, and the exit gate.&lt;/p&gt;
&lt;p&gt;Roughly 20k lines of TypeScript went in over the three days, with
194 unit tests across 16 files covering the pure logic — the state machines,
geometry and traffic simulation are all written as pure functions precisely so
they could be tested at hackathon speed instead of debugged through the UI.&lt;/p&gt;
&lt;p&gt;
&lt;figure id="figure-team-37-nothingunique--劉允中-賴泓安-鄭竣陽-胡軒綸-張勝勛--at-our-bench-on-the-auo-track"&gt;
&lt;div class="flex justify-center "&gt;
&lt;div class="w-full" &gt;
&lt;img alt="The five-person team at our bench during the hackathon"
srcset="https://changshenghsun.com/projects/makentu/team-bench_hu_c3d440bc2ec8763f.webp 320w, https://changshenghsun.com/projects/makentu/team-bench_hu_c0affe0bea0380a6.webp 480w, https://changshenghsun.com/projects/makentu/team-bench_hu_1461225f7144b0f0.webp 760w"
sizes="(max-width: 480px) 100vw, (max-width: 768px) 90vw, (max-width: 1024px) 80vw, 760px"
src="https://changshenghsun.com/projects/makentu/team-bench_hu_c3d440bc2ec8763f.webp"
width="760"
height="507"
loading="lazy" data-zoomable /&gt;&lt;/div&gt;
&lt;/div&gt;&lt;figcaption&gt;
Team 37, NoThingUnique — 劉允中, 賴泓安, 鄭竣陽, 胡軒綸, 張勝勛 — at our bench on the AUO track.
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id="results"&gt;Results&lt;/h2&gt;
&lt;p&gt;First place, AUO corporate award.&lt;/p&gt;</description></item><item><title>KPOP 舞台演出</title><link>https://changshenghsun.com/post/kpop-dance/</link><pubDate>Mon, 23 Mar 2026 00:00:00 +0000</pubDate><guid>https://changshenghsun.com/post/kpop-dance/</guid><description>&lt;h2 id="緣起"&gt;緣起&lt;/h2&gt;
&lt;p&gt;都是一群很可愛的人們啊！大一的時候揪了一群人一起來跳女舞，真的是我做過最快樂的決定。&lt;/p&gt;
&lt;p&gt;去年的大一女舞只能說第一次吧，只能說一個人吧！有很多做的不夠好的地方。&lt;/p&gt;
&lt;!-- TODO(Ivan): 這裡缺大一那次的樣子。
跳的是哪一首？為什麼是女舞？當時是誰揪誰？
還有「一個人」是什麼意思——是只有你在扛負責人的事嗎？
把去年講清楚，今年的對比才有力道。 --&gt;
&lt;h2 id="練習"&gt;練習&lt;/h2&gt;
&lt;p&gt;再來是大二 KPOP，必須感謝三位負責人（idk 你們怎麼分工，但感覺就是三位）潘葦軒、石晏禎、張宸嘉，第一次選歌跑去圖書館開會到底是怎樣啦！是要多鬧！&lt;/p&gt;
&lt;p&gt;但必須說練 KPOP 是我過去這幾個月內心感到最踏實最無憂無慮的一段時間，照著你們排好的步調，盡可能地達成你們的期望，真的真的很喜歡跟一群自己很喜歡的人們一起完成一件喜歡的事。&lt;/p&gt;
&lt;p&gt;然後感謝林若潔帶我去挑衣服！真的很好看，難得帥了一次之後還要帶我去挑衣服哇！&lt;/p&gt;
&lt;!-- TODO(Ivan): 這裡可以補練習的細節。
練了多久？一週幾次？最卡的一段舞是哪裡、後來怎麼解決的？
「照著你們排好的步調」——被帶著跑跟自己當負責人的感覺差在哪？ --&gt;
&lt;h2 id="表演當天"&gt;表演當天&lt;/h2&gt;
&lt;!-- TODO(Ivan): 當天完全還沒寫。
上台前、燈亮、下台之後。summary 寫「流暢度高、畫面優美」，
那是排出來的還是當天發揮的？ --&gt;
&lt;p&gt;
&lt;figure id="figure-紅光下的一個定格"&gt;
&lt;div class="flex justify-center "&gt;
&lt;div class="w-full" &gt;
&lt;img alt="紅光下的舞台畫面"
srcset="https://changshenghsun.com/post/kpop-dance/opening-scene_hu_5ad3aaac953d5f18.webp 320w, https://changshenghsun.com/post/kpop-dance/opening-scene_hu_f68b53b95f6dfa28.webp 480w, https://changshenghsun.com/post/kpop-dance/opening-scene_hu_dae3349f684b30aa.webp 760w"
sizes="(max-width: 480px) 100vw, (max-width: 768px) 90vw, (max-width: 1024px) 80vw, 760px"
src="https://changshenghsun.com/post/kpop-dance/opening-scene_hu_5ad3aaac953d5f18.webp"
width="760"
height="507"
loading="lazy" data-zoomable /&gt;&lt;/div&gt;
&lt;/div&gt;&lt;figcaption&gt;
紅光下的一個定格
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;figure id="figure-下台前的最後一個畫面"&gt;
&lt;div class="flex justify-center "&gt;
&lt;div class="w-full" &gt;
&lt;img alt="四個人在台上笑著比手勢"
srcset="https://changshenghsun.com/post/kpop-dance/curtain-call_hu_faaa25f45c95e067.webp 320w, https://changshenghsun.com/post/kpop-dance/curtain-call_hu_81986c4d9da598b6.webp 480w, https://changshenghsun.com/post/kpop-dance/curtain-call_hu_11f97c2ba7de1598.webp 760w"
sizes="(max-width: 480px) 100vw, (max-width: 768px) 90vw, (max-width: 1024px) 80vw, 760px"
src="https://changshenghsun.com/post/kpop-dance/curtain-call_hu_faaa25f45c95e067.webp"
width="760"
height="507"
loading="lazy" data-zoomable /&gt;&lt;/div&gt;
&lt;/div&gt;&lt;figcaption&gt;
下台前的最後一個畫面
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;謝謝今年你們把它變成一部很好很好的作品。明年這個時間我不知道我還有沒有足夠的心力投入到另一個舞上，但還是希望能夠跟你們一起哇！跟一群自己很喜歡的人一起做事就是很幸福。&lt;/p&gt;</description></item><item><title>中國舞演出</title><link>https://changshenghsun.com/post/chinese-dance/</link><pubDate>Mon, 23 Mar 2026 00:00:00 +0000</pubDate><guid>https://changshenghsun.com/post/chinese-dance/</guid><description>&lt;h2 id="緣起"&gt;緣起&lt;/h2&gt;
&lt;p&gt;先來說說中國舞吧，承載了我許許多多的心力與期盼。這個故事應該是從高中時在 B 站滑到了白小白老師的國風爵士吧！從此便被這種舞風深深吸引，打開了新世界的大門，只能說很想把我眼中的這股美分享給大家啊！每次裙擺轉動、每次扇子飄揚總令我醉心不已，我就是偏愛著這種優雅、含蓄、克制卻又迸發出強烈生命力與美感的視覺效果。&lt;/p&gt;
&lt;p&gt;
&lt;figure id="figure-每次裙擺轉動每次扇子飄揚總令我醉心不已就是這種畫面"&gt;
&lt;div class="flex justify-center "&gt;
&lt;div class="w-full" &gt;
&lt;img alt="水袖與扇子在台上同時揚起的畫面"
srcset="https://changshenghsun.com/post/chinese-dance/silk-sleeves_hu_fe33855be00d2c80.webp 320w, https://changshenghsun.com/post/chinese-dance/silk-sleeves_hu_40642c7f4580237d.webp 480w, https://changshenghsun.com/post/chinese-dance/silk-sleeves_hu_3929976ea4035c3b.webp 760w"
sizes="(max-width: 480px) 100vw, (max-width: 768px) 90vw, (max-width: 1024px) 80vw, 760px"
src="https://changshenghsun.com/post/chinese-dance/silk-sleeves_hu_fe33855be00d2c80.webp"
width="760"
height="507"
loading="lazy" data-zoomable /&gt;&lt;/div&gt;
&lt;/div&gt;&lt;figcaption&gt;
每次裙擺轉動、每次扇子飄揚總令我醉心不已，就是這種畫面
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;!-- TODO(Ivan): 這裡缺一段「從想跳到真的開成」。
電機之夜以前沒有人開過中國舞，你是怎麼決定要開的？
當時有沒有人覺得不可能、或是覺得沒人會想跳？
summary 寫「打破傳統框架、從零到一」，就是這一段在講的事。 --&gt;
&lt;h2 id="準備"&gt;準備&lt;/h2&gt;
&lt;p&gt;謝謝，真的謝謝鄭安妤學姊 @anyu_0526 當初跑來跟我講說想加中國舞，沒有你，這個中國舞就算開成也絕不是如今這般萬人稱頌的演出。你對於美的理解遠在我之上，服飾、裝造、編曲各個方面都是，我在只是維持住中國舞的下限，有你中國舞的美才算是真正被展現出來。跟你合作我很愉快，事到如今，我對你剩下的只有感激而已，再來一次，我依然會希望跟你一起開這支舞。&lt;/p&gt;
&lt;!-- TODO(Ivan): 這裡缺排練的過程，整篇最需要補的就是這段。
十個人、一種大家都沒跳過的舞風，最難的是什麼？
動作教不會？找不到合適的音樂？服裝和道具（扇子、裙）怎麼生出來的？
共同負責人實際上在管什麼？現在讀者看不出你做了什麼。 --&gt;
&lt;h2 id="表演當天"&gt;表演當天&lt;/h2&gt;
&lt;!-- TODO(Ivan): 當天完全還沒寫。
上台前在後台是什麼狀態？燈亮的那一刻？
summary 寫「贏得全場高度迴響」——那個迴響具體是什麼樣子？
哪一個動作、哪一個瞬間台下有反應？ --&gt;
&lt;p&gt;
&lt;figure id="figure-雙人段落"&gt;
&lt;div class="flex justify-center "&gt;
&lt;div class="w-full" &gt;
&lt;img alt="兩位舞者雙掌相對的雙人段落"
srcset="https://changshenghsun.com/post/chinese-dance/fan-duet_hu_5de4c96a399e7a72.webp 320w, https://changshenghsun.com/post/chinese-dance/fan-duet_hu_dec66e4c1bfe5616.webp 480w, https://changshenghsun.com/post/chinese-dance/fan-duet_hu_5ca6693b40081036.webp 760w"
sizes="(max-width: 480px) 100vw, (max-width: 768px) 90vw, (max-width: 1024px) 80vw, 760px"
src="https://changshenghsun.com/post/chinese-dance/fan-duet_hu_5de4c96a399e7a72.webp"
width="760"
height="507"
loading="lazy" data-zoomable /&gt;&lt;/div&gt;
&lt;/div&gt;&lt;figcaption&gt;
雙人段落
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;figure id="figure-團扇"&gt;
&lt;div class="flex justify-center "&gt;
&lt;div class="w-full" &gt;
&lt;img alt="獨舞者持團扇的側面"
srcset="https://changshenghsun.com/post/chinese-dance/solo-fan_hu_f186f001222bdc57.webp 320w, https://changshenghsun.com/post/chinese-dance/solo-fan_hu_98e86925d8a1f438.webp 480w, https://changshenghsun.com/post/chinese-dance/solo-fan_hu_2a8f000177312ee0.webp 760w"
sizes="(max-width: 480px) 100vw, (max-width: 768px) 90vw, (max-width: 1024px) 80vw, 760px"
src="https://changshenghsun.com/post/chinese-dance/solo-fan_hu_f186f001222bdc57.webp"
width="760"
height="507"
loading="lazy" data-zoomable /&gt;&lt;/div&gt;
&lt;/div&gt;&lt;figcaption&gt;
團扇
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;也想謝謝何文璦 @ambaa_.10 ，電夜總算有一支和你一起跳的舞了，支持我做的許多決定，聽到你說你很喜歡中國舞、明年還會想要跳的時候，我發自內心的有種被認同、被接納的感覺。張勝勛是個很奇怪很不正常的人，謝謝你接受了也支持了他的奇思妙想。&lt;/p&gt;
&lt;p&gt;明年沒意外的話還是會有跨屆中國舞，希望會有更多喜歡跳舞（maybe 擅長跳舞）的人加入，也希望這東西在我離開台大後也能被傳承改良下去。&lt;/p&gt;</description></item><item><title>串場劇</title><link>https://changshenghsun.com/post/interlude-drama/</link><pubDate>Mon, 23 Mar 2026 00:00:00 +0000</pubDate><guid>https://changshenghsun.com/post/interlude-drama/</guid><description>&lt;h2 id="準備"&gt;準備&lt;/h2&gt;
&lt;p&gt;串場劇，說實在的一開始本來只是想要進去混個配角當當而已，但默默地好像也幫了不少忙，跟同屆的很多人變得更要好，也認識了很多很有意思的學弟們！（赫然發現串場劇都只有男生！！！）&lt;/p&gt;
&lt;p&gt;
&lt;figure id="figure-證據如上真的全部都是男生"&gt;
&lt;div class="flex justify-center "&gt;
&lt;div class="w-full" &gt;
&lt;img alt="排練結束後在走廊的大合照，全部都是男生"
srcset="https://changshenghsun.com/post/interlude-drama/cast-selfie_hu_ee201b5dbca6483f.webp 320w, https://changshenghsun.com/post/interlude-drama/cast-selfie_hu_4ac5bd81a8800895.webp 480w, https://changshenghsun.com/post/interlude-drama/cast-selfie_hu_c3da636b05db9569.webp 760w"
sizes="(max-width: 480px) 100vw, (max-width: 768px) 90vw, (max-width: 1024px) 80vw, 760px"
src="https://changshenghsun.com/post/interlude-drama/cast-selfie_hu_ee201b5dbca6483f.webp"
width="760"
height="570"
loading="lazy" data-zoomable /&gt;&lt;/div&gt;
&lt;/div&gt;&lt;figcaption&gt;
證據如上，真的全部都是男生
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;!-- TODO(Ivan): 這裡缺你實際做了什麼。
summary 寫「編劇、場控、共同籌劃、六幕、五十分鐘」，但內文一句都沒提到。
劇本是怎麼生出來的？六幕在講什麼故事？
場控在一場五十分鐘的演出裡是在控什麼？
「本來只想混個配角」怎麼一路變成在寫劇本的？這個轉折是整篇最好看的地方。 --&gt;
&lt;h2 id="表演"&gt;表演&lt;/h2&gt;
&lt;!-- TODO(Ivan): 當天完全還沒寫。
哪一幕最好笑？有沒有出包、然後怎麼救回來的？ --&gt;
&lt;p&gt;最後串場劇的效果很好笑，為眾人帶來了許多歡樂真是太好了！&lt;/p&gt;
&lt;p&gt;但說回來串場劇最大的收穫就是跟謝濟遠 @ikandoit_1014 變得很熟吧！一個令人尊敬的學弟，活到 20 歲，總不時會有這種感覺：「這個人一定能比我更強更有成就！」，你也讓我有這種感覺呢！負責認真、聰明能幹，嘛&amp;hellip;&amp;hellip;老實說我應該幫你更多的，有太多時候我的心態有點閃躲飄，讓你焦慮煩惱了很多次我真的很抱歉。雖然你走得比我快很多，能幫上你的應該不多，但有什麼需要還是讓我知道吧！&lt;/p&gt;
&lt;p&gt;是說今年演完劇有點演上癮了，明年有點想把跨屆劇魔改成古裝劇（畢竟應該也很多人手上會有漢服了），可以問問電機系的大家會有人有興趣嗎？&lt;/p&gt;</description></item><item><title>台大杜鵑花節</title><link>https://changshenghsun.com/post/ntu-azalea-festival/</link><pubDate>Sat, 14 Mar 2026 00:00:00 +0000</pubDate><guid>https://changshenghsun.com/post/ntu-azalea-festival/</guid><description>&lt;p&gt;台大杜鵑花節闖關遊戲組。&lt;/p&gt;</description></item><item><title>泳渡日月潭</title><link>https://changshenghsun.com/post/sun-moon-lake-swim/</link><pubDate>Mon, 15 Sep 2025 00:00:00 +0000</pubDate><guid>https://changshenghsun.com/post/sun-moon-lake-swim/</guid><description>&lt;h2 id="緣起"&gt;緣起&lt;/h2&gt;
&lt;p&gt;「ㄟ要不要去游日月潭？」那時候還沒考分科，每天就是一直在刷題吃飯睡覺、刷題吃飯睡覺，吃飯滑手機的時候看到了賴泓安傳來的訊息，也沒想太多吧！3.3公里一定游得完，而且也是台灣人特有的成就之一（對啊是說我們什麼時候要來單車環島），所以我就回了「好啊！」，男人的對話框就是這樣，哪有那麼多彎彎繞繞。最後去的人就是我、賴泓安、王元粲、陳彥臻、李允中。&lt;/p&gt;
&lt;h2 id="前一天"&gt;前一天&lt;/h2&gt;
&lt;p&gt;必須說，整個泳渡日月潭我覺得最難的完全不是游泳，最難的是上山和下山。我們到台中車站出來，一大堆人都在排公車，就在我們絕望於到底要怎麼上山的時候，旁邊有兩個大哥問了我們要不要拼車一起上山。現在想想能遇到那兩位大哥還真是幸運，不然我們到飯店可能都凌晨了。一路上我們聊了很多東西，只能說台大的身分還是蠻好用的，大哥聽到之後講話都變得客氣不少。而且大哥很酷耶，一天到晚去各種不同的地方騎腳踏車、參加鐵人三項，哪天我四十幾歲也蠻想活成他那樣子的，四十幾歲的人了還那麼有精神，看著健康的人我就很喜歡。&lt;/p&gt;
&lt;p&gt;到了之後，因為飯店是陳彥臻訂的，我們當下又聯絡不上他，只能在大廳休息。飯店的人也蠻好的，還準備了一些紅燒肉、滷蛋、湯讓來這邊的人吃，那個時候好像沒吃晚餐吧，狼吞虎嚥了一波，說實在還蠻爽的。ㄟ不對，我記得那一次一個晚上一個人要四千，是前一天的兩倍！貴死了，我只能說準備這些是應該的。當天晚上&amp;hellip;&amp;hellip;好像也沒有特別幹嘛，休息完就早一點回去睡覺了。&lt;/p&gt;
&lt;h2 id="當天"&gt;當天&lt;/h2&gt;
&lt;p&gt;必須說很震撼耶，真的是萬人泳渡日月潭，前往下水點的一路上滿滿的都是人，一眼望過去都是主辦單位發的紅色泳帽。我們好像是八點下水，那一天天氣還蠻炎熱的，一開始下水的時候真的挺冰涼，水沒有說特別髒，我游完身體也沒有任何紅腫發癢，挺不賴的。而且這是我第一次在開放水域游泳，那種踩不到地的感覺說實話還真的有點可怕。反正就開始游啊，游一游就只剩我跟賴泓安在最前面。主辦單位還蠻讚的，每隔50公尺就會有人餵水，我們就像魚一樣蹲在旁邊把嘴張開。到現在唯一還有印象的，大概就是人很密集，所以一直踢到別人、還有被別人踢吧！超級可怕。&lt;/p&gt;
&lt;p&gt;
&lt;figure id="figure-一眼望過去都是主辦單位發的紅色泳帽"&gt;
&lt;div class="flex justify-center "&gt;
&lt;div class="w-full" &gt;
&lt;img alt="泳渡現場戴著紅色泳帽的人群"
srcset="https://changshenghsun.com/post/sun-moon-lake-swim/red-swim-caps_hu_b834a574bb4c339e.webp 320w, https://changshenghsun.com/post/sun-moon-lake-swim/red-swim-caps_hu_479b0eb1f6c847a3.webp 480w, https://changshenghsun.com/post/sun-moon-lake-swim/red-swim-caps_hu_25d5400f51098936.webp 570w"
sizes="(max-width: 480px) 100vw, (max-width: 768px) 90vw, (max-width: 1024px) 80vw, 760px"
src="https://changshenghsun.com/post/sun-moon-lake-swim/red-swim-caps_hu_b834a574bb4c339e.webp"
width="570"
height="760"
loading="lazy" data-zoomable /&gt;&lt;/div&gt;
&lt;/div&gt;&lt;figcaption&gt;
一眼望過去都是主辦單位發的紅色泳帽
&lt;/figcaption&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;游過去差不多是十一點，說實話上岸之後的事情我都忘了，好像身上扛了一個人的感覺，走起路來特別重。我只記得我們走了很久，真的是很久很久很久，最後是靠陳彥臻他爸 carry 我們，才有回台北的客運車票。必須說真的超遠，大概開了快六個小時吧，兩三點的車到台北都八九點了&amp;hellip;&amp;hellip;整體來說我覺得推薦嗎？也還好，就有一種解鎖人生成就的感覺吧，但也真的是找罪受就是了。每年都去的話，除非你像馬英九一樣有專車接送，不然都挺麻煩的。&lt;/p&gt;
&lt;p&gt;是說什麼時候要游澎湖灣啊&lt;/p&gt;</description></item><item><title>RecoveryDAgger</title><link>https://changshenghsun.com/projects/recoverydagger/</link><pubDate>Mon, 01 Sep 2025 00:00:00 +0000</pubDate><guid>https://changshenghsun.com/projects/recoverydagger/</guid><description>&lt;p&gt;&lt;strong&gt;Sep – Dec 2025&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="the-problem"&gt;The problem&lt;/h2&gt;
&lt;p&gt;Imitation learning lets an agent pick up complex behaviour from expert
demonstrations, but plain behaviour cloning drifts. Small errors push the agent
into states the expert never demonstrated, and from there the mistakes compound.&lt;/p&gt;
&lt;p&gt;DAgger fixes the drift by querying the expert on the states the learner actually
visits. That works, but it asks constantly — and expert supervision is the
expensive part of the whole setup.&lt;/p&gt;
&lt;h2 id="what-we-built"&gt;What we built&lt;/h2&gt;
&lt;p&gt;RecoveryDAgger keeps DAgger&amp;rsquo;s interactive loop but adds a cheaper first response
to trouble. In a risky state the agent does not call the expert straight away.
It first runs a &lt;strong&gt;recovery policy&lt;/strong&gt; that corrects itself locally by ascending the
gradient of a learned &lt;strong&gt;Success Q-function&lt;/strong&gt; — a network that estimates the
probability the task will still be completed from the current state. The expert
is queried only when recovery is unreliable, which is to say only when the state
is genuinely novel.&lt;/p&gt;
&lt;p&gt;The point is to spend expert supervision on new information, rather than on
situations the agent could have dug itself out of.&lt;/p&gt;
&lt;h2 id="my-role"&gt;My role&lt;/h2&gt;
&lt;p&gt;I led a four-person team and built the expert policy and the training pipeline
myself, in PyTorch and Stable-Baselines3. The expert is a rule-based controller
that steers toward the goal from the current state — deterministic, 100% success
on the task — and it generates the 100-trajectory offline dataset every method
in the paper starts from. Behaviour cloning on that dataset lands at roughly 26%
success, which is exactly the gap online training has to close.&lt;/p&gt;
&lt;p&gt;The design decision I care most about is how recovery actually produces an
action. PointMaze has a continuous action space (forces along x and y), so the
obvious version of recovery — enumerate candidate actions, take the arg max of
the Success Q-function — is not available. We instead start from the action the
imitation policy already proposed and run a few steps of gradient ascent on the
Success Q-function with respect to the action, projecting back into the valid
range after each step. Recovery is a local correction of the policy&amp;rsquo;s own
intent, not a second controller fighting it.&lt;/p&gt;
&lt;p&gt;The other decision was to stop trusting a single Q-network. One learned Success
Q is only an approximation, and recovery follows its gradient, so its errors get
amplified rather than averaged out. We trained an ensemble instead: the ensemble
mean defines risk, the ensemble variance defines novelty, and the recovery
objective subtracts a penalty λ·Var(Q) so recovery never climbs toward states
the ensemble disagrees about. One family of networks ends up serving all three
roles — risk detector, novelty detector, and recovery direction.&lt;/p&gt;
&lt;h2 id="results"&gt;Results&lt;/h2&gt;
&lt;p&gt;Evaluated on a four-room PointMaze navigation task against ThriftyDAgger, the
standard query-efficient baseline. Every method starts from the same
behaviour-cloned policy.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Expert queries&lt;/th&gt;
&lt;th&gt;Recovery queries&lt;/th&gt;
&lt;th&gt;Success rate&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Behaviour cloning&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;0.26&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ThriftyDAgger (baseline)&lt;/td&gt;
&lt;td&gt;20,048&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;0.81&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Single-Q recovery (ours)&lt;/td&gt;
&lt;td&gt;2,504&lt;/td&gt;
&lt;td&gt;9,232&lt;/td&gt;
&lt;td&gt;0.86&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ensemble-Q recovery (ours)&lt;/td&gt;
&lt;td&gt;2,693&lt;/td&gt;
&lt;td&gt;9,296&lt;/td&gt;
&lt;td&gt;0.88&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Ensemble-Q recovery ends up more accurate than the baseline while querying the
expert &lt;strong&gt;7.4× less often&lt;/strong&gt;. Partway through training the gap is even wider: both
recovery variants reach ~0.7 success after about 2k expert queries, where
ThriftyDAgger needs roughly 20k to get to the same place.&lt;/p&gt;
&lt;p&gt;The interesting part is &lt;em&gt;where&lt;/em&gt; the savings come from. Most of what a risk-gated
method spends its query budget on is not genuinely unfamiliar — it is
recoverable: local deviations near a doorway or a wall that the agent could fix
by itself. Separating &amp;ldquo;novel&amp;rdquo; from &amp;ldquo;merely risky&amp;rdquo; is what buys the 7.4×.&lt;/p&gt;
&lt;p&gt;The project placed 3rd among 30 teams, most of them graduate students, and the
work has been accepted to IEEE Potentials.&lt;/p&gt;</description></item><item><title>系學會 EE+</title><link>https://changshenghsun.com/post/ntuee-plus/</link><pubDate>Sun, 01 Sep 2024 00:00:00 +0000</pubDate><guid>https://changshenghsun.com/post/ntuee-plus/</guid><description>&lt;p&gt;&lt;strong&gt;Sep 2024 – Jun 2027&lt;/strong&gt;&lt;/p&gt;
&lt;!-- TODO: 寫下在 EE+ 的角色、做了什麼、學到什麼 --&gt;
&lt;p&gt;NTUEE 系學會 EE+。&lt;/p&gt;</description></item><item><title>Experience</title><link>https://changshenghsun.com/experience/</link><pubDate>Tue, 24 Oct 2023 00:00:00 +0000</pubDate><guid>https://changshenghsun.com/experience/</guid><description/></item></channel></rss>