跪拜 Guibai
← Back to the summary

Pinned-Foot Dance Move Produces 15x Larger Center-of-Gravity Excursion, Two-Link IK Model Shows

Here's the conclusion first: putting "foot pinned, upper body sideways dodge" and "core-driven whole-body translation" into the same 2D model across 61 sample points, the former's center of gravity projection shift peaks at 18.00 cm, the latter only 1.19 cm, a difference of 15.13 times. The cost is also clear — this is a magnitude estimate from geometry and statics, not including ligament forces, muscle activation, or 3D torsion, and it cannot be used to diagnose anyone.

Table of contents: 1 Why dissect a dance move · 2 Verifying the 600M-playback thing · 3 Three technical routes evaluated · 4 Reducing 17 points to 3 points · 5 The actual 15x that came out · 6 Tumbler, tightrope, and a patented shoe · 7 Zero-dependency Canvas demo · 8 This inverse kinematics code runs in games every day · 9 Six pitfalls written into a checklist · 10 Boundaries and unsolved problems · 11 Summary and quick-reference table

1. Why dissect a dance move

The trigger for this piece is a phrase that keeps appearing in reports: "foot pinned to the ground, upper body forcibly twisted, knee joint in semi-flexed position bearing shear force." I wanted to figure out what this "shear" is determined by, read a few popular science pieces, and got only qualitative descriptions, none giving a magnitude.

The difference between a professional approach and an imitative approach is also consistent across the reports: the former uses core strength to drive the center of mass as a whole, with the center of mass always following the supporting foot; the latter fixes the foot, only lets the upper body dodge sideways, and the center of mass projection runs outside the support surface. This explanation makes sense, but it can't be verified or reused.

The flash step comes from Huagudeng — a folk song-and-dance from the Huai River basin in Anhui, listed as one of the first batch of national intangible cultural heritage items in 2006. Because it combines dance, lantern songs, and gong and drum, it's known as the "Oriental ballet," and its origins are often traced to the Song Dynasty. In the lantern troupe, the female role is called "orchid," the male role "drum frame"; the flash step is a basic step, emphasizing "slippery to start, sharp to stop," using core strength to drive the center of mass to shift. The viral take-off video this time was restaging the side flash.

I have no real person video material, nor force plate data. What I can do is abstract the movement into computable geometric quantities, run code to get magnitudes, and draw the process. Hence, a Python reproduction script and a zero-dependency browser demo.

Fair warning: I did no real human measurements. In the model, 65 kg, femur 0.45 m, tibia 0.43 m, hip height 0.72 m are all adjustable example parameters, taken from typical adult approximations; all numbers are computed by the script, changing parameters changes them. It cannot diagnose anyone, nor should it be taken as training advice.

2. Verifying the 600M-playback thing

Before writing code, I verified facts. I sorted the public reports I could find on a timeline and flagged places where the numbers don't align:

Time Fact Source
Intangible heritage origin Flash step is a basic step of Anhui Huagudeng, emphasizing "slippery to start, sharp to stop," using core strength to drive center of mass shift; divided into side flash, front flash, back flash Public encyclopedia "Flash Step" entry
1990s Zhao Tiechun and others recorded Huagudeng teaching videos; flash step is one of the teaching moves 2026-09-24 report and course recorder's response
September 2026 The teaching video was clipped and restaged by celebrities; related topic views "over 600M" 2026-09-24 media report
Late September 2026 Another report wrote "over 750M," without stating the statistics methodology or cutoff time 2026-09-28 media report
October 2026 Several people after imitation suffered knee joint pain, swelling, diagnosed with cruciate ligament sprain or partial tear 2026-10-08 / 10-09 reports
October 2026 From online meme to intangible heritage science, spread overseas Public encyclopedia entry "social impact"

These two numbers can't be merged into one definite value: 600M and 750M come from different media, different dates, and whether they count topics or individual videos, or deduplicate, the reports don't say. The title uses 600M, using the earlier, relatively clearer one.

What really matters to the code is the movement instruction line. "Core strength drives center of mass as a whole" can be translated directly into geometric constraints: the horizontal difference between hip and ankle is approximately 0; "foot pinned to the ground" translates to the ankle's horizontal coordinate being fixed, with the hip swinging independently. The whole calculation starts from this translation.

The public statement of the injury mechanism uses only the qualitative part: knee joint in semi-flexed position bears shear force, the anterior cruciate ligament stabilizes the tibia's sliding relative to the femur. This piece doesn't infer any clinical threshold from that; it mentions it only to explain why the center of mass projection is worth calculating.

References (no links, search by title):

3. Three technical routes evaluated

Initially I wanted to go straight for pose estimation: feed a video, get keypoints, calculate angles, looks the most proper. After putting the three routes side by side, I changed my mind.

Route What it gives me Why I didn't choose it
TensorFlow.js + MoveNet Browser-side outputs 17 keypoints, with x, y, confidence, and names; Lightning uses 192×192 input, Thunder 256×256, official claimed 30+ FPS on most devices Requires tfjs-core, tfjs-converter, and a WebGL/WASM backend; lacks publicly usable real-person video material, can't produce credible results
MediaPipe / BlazePose series pose estimation Denser keypoints, with depth-related info Also depends on real material and model files, and the more outputs, the harder to explain which part causes the excursion
2D two-link geometric model (chosen) Needs only 3 points: ankle, knee, hip; pure standard library / pure Canvas, offline runnable, every number traces back to a single formula Loses 3D torsion and muscle activation; can give only magnitudes, not real-person conclusions

The trade-off favored explainability: I want to answer "how much does the center of mass deviate geometrically when it follows the foot vs when the foot doesn't move," not "is this person doing it right." The former needs video and annotation; the latter needs only 3 points and the cosine rule.

MoveNet's parameters were checked against official TensorFlow documentation: the May 2021 official intro gives 17 keypoints, Lightning / Thunder variants, 192×192 and 256×256 inputs, runs in the browser via TensorFlow.js, no server-side calls after first load. These are official claims, used only for comparison; this piece did no local performance benchmarks.

4. Reducing 17 points to 3 points

The model keeps only one leg in the sagittal plane: ankle A, knee K, hip H. Thigh length L₁, shank length L₂ are fixed. Given A and H's positions, use two-link inverse kinematics to solve for K.

Let d = |H − A|, unit vector u along A→H, normal p = (−u_y, u_x). The projection of knee-to-ankle on u is a = (L₂² − L₁² + d²) / (2d), perpendicular distance h = √(L₂² − a²), giving two candidate solutions K = A + a·u ± h·p. The one with the larger x is "knee in front," the other is the reverse-joint solution.

def solve_knee(ankle, hip, pick="front"):
    ax, ay = ankle
    hx, hy = hip
    dx, dy = hx - ax, hy - ay
    d = math.hypot(dx, dy)
    if d == 0 or d > L_SHANK + L_THIGH or d < abs(L_THIGH - L_SHANK):
        return None

    a = (L_SHANK ** 2 - L_THIGH ** 2 + d ** 2) / (2 * d)
    h = math.sqrt(max(0.0, L_SHANK ** 2 - a ** 2))
    ux, uy = dx / d, dy / d
    px, py = -uy, ux

    k_plus = (ax + a * ux + h * px, ay + a * uy + h * py)
    k_minus = (ax + a * ux - h * px, ay + a * uy - h * py)
    front = k_plus if k_plus[0] >= k_minus[0] else k_minus
    back = k_minus if k_plus[0] >= k_minus[0] else k_plus
    return front if pick == "front" else back

The only output that really matters is the center of mass projection excursion |H.x − A.x|. Weight above the hip W = body mass × g × 0.62, multiplied by this excursion, gives the approximate bending moment at the knee W × |H.x − A.x|. It's a statics magnitude of "how far the gravity line is from the support point," not ligament force.

Two movement modes sample 61 points in the same sine period:

Hip height is uniformly set to 0.72 − 0.04·|sin(2πt)| m. This 0.72 isn't random: I ran 0.62 / 0.72 / 0.82 / 0.86 m each, with knee flexion ranges 90.4–93.1°, 70.2–74.0°, 42.6–49.1°, 24.5–34.9° respectively. The report said "knee in semi-flexed position," and at 0.86 m the leg is almost straight; only 0.72 m lands in the semi-flexed range, so I set it to 0.72.

5. The actual 15x that came out

Python 3.13.12, standard library, command is a single line python kinematics.py. 61 sample points, one full side-flash period, output verbatim:

Mode Peak center of mass excursion Average excursion Peak bending moment Knee flexion range Frames with knee behind ankle
clean 1.19 cm 0.75 cm 4.72 N·m 70.2–78.8° 0.0%
pinned 18.00 cm 11.26 cm 71.16 N·m 70.2–74.0° 0.0%

18.00 / 1.19 = 15.13 times, 71.16 / 4.72 = 15.08 times, average excursion is also 15.01 times. The "15x" in the title refers to these three consistent ratios. Excursion and bending moment are linearly related: with W fixed at 395.34 N, each additional 1 cm of excursion adds about 3.95 N·m of moment.

Plotting the same 61 sample points as curves: pinned has two big humps, clean hugs the zero line the whole time.

clean vs pinned center of mass projection excursion vs time (61 sample points), peaks 1.19 cm and 18.00 cm

I also swept the side-flash amplitude from 0.06 m to 0.24 m to see if the linearity breaks at the boundaries:

Side-flash amplitude Peak center of mass excursion Peak bending moment
0.06 m 6.00 cm 23.72 N·m
0.12 m 12.00 cm 47.44 N·m
0.18 m 18.00 cm 71.16 N·m
0.24 m 24.00 cm 94.88 N·m

All four points are strictly proportional, showing no other variable is messing around in this model. The model being too clean is also a problem: a real human body isn't so obedient, muscles compensate, feet leave the ground, the torso twists in the horizontal plane, none of which is in the formula.

Failure log: solve_knee has two solutions. I ran the posterior solution alone, and in the animation the knee goes entirely behind the body; statistically, the anterior solution gives a 0.0% frame ratio of knee behind ankle, the posterior 100.0%. It's not "looks odd," it's every frame being hyperextended. The fix is to always take the anterior solution and write this into the script's failure log, so I don't revert it later.

The clean column isn't 0 either: I gave 0.012·sin(4πt) a small perturbation to represent that a real person can't be perfectly synchronized. This perturbation is an assumption, not measured data; if set to 0, the ratio becomes infinity and loses reference value.

6. Tumbler, tightrope, and a patented shoe

pinned's peak of 18.00 cm — just a little narrower than a sheet of A4 paper's width (21 cm) — is how far the center of mass projection runs outside the supporting foot. Simply put, this quantity measures how close you are to falling. Body weight must transfer to the ground through the support surface; once the center of mass projection goes out, gravity has only a "topple you over" moment about the ankle, unless something pulls it back.

Ways to pull the center of mass back are common in life:

When |H.x − A.x| gets to 18 cm, everyday balance instincts can no longer compensate; it takes specialized technique or external structure. Huagudeng artists use decades of skill to compensate; this article uses the 1.19 and 18.00 ratio to quantify it.

7. Zero-dependency Canvas demo

The tables and curves are there, but you still can't see how the movement gradually goes off. I put the same formulas into the browser as a side-by-side animation — clean on the left, pinned on the right, driven by the same t, sharing one set of constants.

demo comparison gif: left clean right pinned, same cycle driven, color bar under feet is center of mass projection excursion

The environment is any modern browser supporting Canvas 2D, ES2020, no dependency on npm, build, or network. Save flash-step-demo.html locally and double-click to run; CSS, HTML, JS together are a bit over 100 lines.

The core is porting the inverse solution to JS, with ** exponentiation and Math.hypot natively available:

function solveKnee(A, H) {
  const dx = H.x - A.x, dy = H.y - A.y;
  const d = Math.hypot(dx, dy);
  if (!d || d > L_THIGH + L_SHANK || d < Math.abs(L_THIGH - L_SHANK)) return null;
  const a = (L_SHANK ** 2 - L_THIGH ** 2 + d ** 2) / (2 * d);
  const h = Math.sqrt(Math.max(0, L_SHANK ** 2 - a ** 2));

  const ux = dx / d, uy = dy / d, px = -uy, py = ux;
  const k1 = { x: A.x + a * ux + h * px, y: A.y + a * uy + h * py };
  const k2 = { x: A.x + a * ux - h * px, y: A.y + a * uy - h * py };
  return k1.x >= k2.x ? k1 : k2;
}

Two pitfalls in rendering. One is coordinate handedness: physics coordinates have y pointing up, Canvas y points down, toPx must be written y: ORIGIN.y - p.y * SCALE; adding directly would draw the person below the ground. The other is animation timing: requestAnimationFrame gives timestamps in milliseconds, and I use (ts / 1600) % 1 to normalize into the period, instead of incrementing t += 0.01 per frame, otherwise on a 144 Hz screen the movement would be more than twice as fast.

Below each panel, the current excursion and approximate bending moment display in real time, and a short color bar under the feet draws the length of |H.x − A.x|, cyan for clean, red for pinned. When the right side hits its peak, the numbers land at 18.00 cm / 71.16 N·m, matching the Python table. That's also how I verified the two implementations: with the same set of constants and the same t, the outputs of both environments must match digit-for-digit.

demo full-page screenshot, frozen at t = 7/60: clean at its sample peak 1.19 cm / 4.72 N·m, pinned at 12.04 cm

To change parameters and reproduce: kinematics.py supports --mass, --swing, --frames; after changing body mass or side-flash amplitude, update the constants in the browser, then compare the two again.

8. This inverse kinematics code runs in games every day

The solveKnee above isn't an obscure formula. In the game industry this problem is called two-segment inverse kinematics (IK): two links, thigh and shank, given the foot placement and hip position, solve which way the knee bends — the same formula, the same "front solution vs back solution" choice.

Every stable step in a game is this inverse solution running per frame — the same math as section 7.

9. Six pitfalls written into a checklist

# Phenomenon Root cause Fix / reusable check
1 Skeleton knee goes behind the body, looks hyperextended Two-link inverse solution has two symmetric solutions; picked the back one Always pick the larger x; add a "knee behind ankle frame ratio" assertion, should be 0%
2 Hip height 0.86 m makes knee nearly straight, doesn't match "semi-flexed" Hip-ankle distance approaches L₁ + L₂, knee angle pushed to near 180° Sweep hip height first to see knee flexion range, then set the value; here 0.72 m gives 70.2–74.0°
3 Person drawn below ground Canvas y axis points down, physics y up Flip with subtraction in toPx; print the pixel coordinates of a known point to verify
# Phenomenon Root cause Fix / check
4 Movement visibly accelerates on high-refresh screens Using fixed-step t accumulation, frame rate becomes part of the period duration Use timestamp normalization (ts / 1600) % 1, decoupling period from refresh rate
5 Left and right appear swapped Front-facing camera or mirrored video flips x Unify coordinate handedness; do a mirror normalization before feeding real video
6 Reading N·m as "ligament force" Bending moment is weight × horizontal arm, units aren't force Write "approximate bending moment" in tables, notes in figure captions that ligament force and muscle activation are excluded

Items 3 and 5 won't actually appear in this pure-geometry demo; they are checks I record before porting the formula to real video. Item 6 is most important: one unit misreading can turn an engineering visualization into a medical claim, and that kind of error is harder to withdraw than a code bug.

10. Boundaries and unsolved problems

The model can answer a very narrow question: in a 2D sagittal plane, single-leg support, fixed link lengths, and the assumption that the center of mass approximates the hip, how much difference does moving the foot vs not moving the foot make to "how far the gravity line deviates from the support point." Beyond that, the numbers are meaningless.

At least four categories of things the model doesn't compute:

  1. Horizontal-plane torsion. The "flash" of the flash step includes trunk rotation relative to the pelvis, which a 2D side view can't see; the shear force mentioned in public reports is strongly correlated with this rotation, and this model doesn't compute it at all.
  2. Muscles and ligaments. No muscle activation, no anterior cruciate ligament force, no joint contact force, and no clinical thresholds. 4.72 and 71.16 N·m can only be compared to each other, not to any safety value.
  3. Real human parameters. 65 kg, 0.45 / 0.43 m, 0.62 upper-body mass fraction are all example values; different height and body fat people will change results; except for the sensitivity sweep, I did no individual validation.
  4. Real movement data. No video, no keypoint annotations, no force plate, no comparison with medical imaging. This article gives no "who does it right" judgment.

One more thing is unsolved: the 0.012 m synchronization perturbation in clean mode is manually set to avoid an infinite ratio and has no data source. It only affects the denominator, not the directional conclusion that "pinning the foot amplifies the excursion"; to use a specific multiple as a claim, you'd need real motion-capture data. I don't have such data, so I list it explicitly as an assumption; readers can change it and see how the ratio changes.

The most worthwhile next step: a licensed real-person video plus a time series of 17 keypoints, replacing the sine assumption, then see whether the clean / pinned curves still separate.

11. Summary and quick-reference table

The pitfalls hit along the way, compressed into a quick-reference table to go through before the next movement visualization:

Check Pass criteria
Knee solution Always take the front solution; knee behind ankle frame ratio = 0%
Posture Sweep hip height first, set value only when knee flexion range is in target range
Coordinates Physics y up, Canvas y down; use subtraction for conversion
Time Use timestamp normalization, not fixed step
Units Write "approximate bending moment N·m," not "ligament force"
Cross-end consistency JS and Python with same constants, same t, output digit-aligned

This piece is original, first released. The complete reproduction script kinematics.py and the zero-dependency browser demo flash-step-demo.html are attached; save and run locally. Public report references are in section 2, official MoveNet parameters in section 3.

I want to hear your approach: for movement visualization, do you go straight for keypoint detection models to preserve real data, or do you first use a geometric model to explain causality, then decide whether to introduce real material?