Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,20 @@ write Movit for you.
The protocol and both libraries are **MIT-licensed** — the open core. See
[`spec/SPEC.md`](spec/SPEC.md) for the full language and
[`spec/llm-authoring.md`](spec/llm-authoring.md) for the authoring prompt.
For where Movit spreads fastest and the per-domain go-to-market plan, see
[`docs/market-research.md`](docs/market-research.md); for the engine roadmap,
[`ROADMAP.md`](ROADMAP.md).

## Scope (v0.1)

✅ Single-person fitness, stretching & posture · Mermaid-style DSL · ROM safety
clamping · forward kinematics · ground-lock IK · live playground.
✅ Single-person movement across fitness, physio, desk, dance, education & rehab ·
Mermaid-style DSL · ROM safety clamping · forward kinematics · ground-lock **and
reach-to-target IK** · hip-hinge · lying/seated poses · scene props (chair/wall/
bar) · a single-DOF hand rig · live playground.

⏳ Deferred: reach-IK, two-person / partner movements + collision detection,
FBX/GLB export, hosted SaaS editor and the expert-verified motion marketplace.
⏳ Deferred: two-person / partner movements + collision detection, deeper props
(load, bands, rings), multi-joint fingers, FBX/GLB export, hosted SaaS editor and
the expert-verified motion marketplace.

## Background

Expand Down
49 changes: 32 additions & 17 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,26 @@ domain needs — so contributions land where they unlock the most.

These are the unlocks, roughly in order of leverage:

1. **Hip / waist hinge primitive** — today deadlift / forward-fold are faked as a
spinal roll-down. A true hip hinge unlocks deadlift, row, good-morning, hinge-based
yoga, and bending to interact with props.
2. **Reach-IK (reach a world target)** — touch your toes, hand-to-opposite-knee,
grab a bar, place a hand on a wall. Unlocks a huge share of physio, yoga, and any
prop interaction.
3. **Scene props with contact anchors** — objects the figure can stand on, sit on,
hang from, or push against, plus ground-lock-style anchors to them.
4. **Lying & seated base poses** — supine / prone / quadruped / seated starting poses
(for floor yoga, mat Pilates, bed-based rehab, sit-to-stand on a real seat).
5. **Hand / finger articulation** — grip and gesture (sign language, grasping props).
1. ~~**Hip / waist hinge primitive**~~ — ✅ **shipped (v0.1).** `pelvis: hinge <deg>`
tips the torso forward over the hips while the legs stay planted (the renderer
counter-rotates the hips). Powers `deadlift`, `bent-over-row`, `good-morning`,
and `bow`. Next: hinge with a loaded-bar prop.
2. ~~**Reach-IK (reach a world target)**~~ — ✅ **shipped.** `reach: <effector>
<target>` drives a hand/foot to a body landmark, the `floor`, or a prop anchor
via CCD. Powers `touch-toes`, `cross-body-reach`, `seated-forward-fold`, and
prop grips. Next: ROM-constrained reach + dual-hand targets.
3. ~~**Scene props with contact anchors**~~ — ✅ **shipped (starter set).** `prop
chair|wall|bar` adds a scene object with named anchors (`seat`, `wall`, `bar`).
Powers `sit-to-stand`, `box-squat`, `wall-sit`, `dead-hang`, `hanging-knee-raise`.
Next: more props (bench, rings, bands), load cues, anchor-aware ground-lock.
4. ~~**Lying & seated base poses**~~ — ✅ **shipped.** `supine | prone | seated`
start poses (grounded by a bounding-box drop). Powers `glute-bridge`,
`dead-bug`, `cobra`, `seated-forward-fold`. Next: quadruped + chair-seated.
5. ~~**Hand / finger articulation**~~ — ✅ **shipped (single-DOF).** Per-finger
curl bones + `fingers` group. Powers `make-a-fist`, `pinch-grip`, `hand-wave`,
`finger-spell-demo`. Next: multi-joint fingers for accurate sign language.
6. **Two-person + collision** — partner stretches, assisted rehab, contact sports
(already noted as deferred in the spec).
(still deferred in the spec).

## Prop / equipment library (future)

Expand All @@ -60,10 +67,18 @@ Each prop is a small scene object + an anchor type; movements then reference it

## Current limitations (honest)

- One figure only; no props or external objects yet.
- Forward kinematics + ground-locked hands/feet; **no reach-to-target IK**.
- Hip/waist hinge is approximated by spinal flexion (so deadlift-class moves look
like a roll-down — curate around this until the hinge primitive lands).
- Rig ends at the wrist (no fingers) and the head (no facial articulation).
- One figure only; partner work and collision are still deferred.
- A **starter** prop set (chair / wall / bar) — no bench, rings, bands, or loaded
implements yet, and props sit at fixed default placements.
- Reach-IK is **unconstrained** (no ROM limits on the solved chain) and props are
visual + reach anchors (no physical sit/lean solve).
- Fingers are **single-DOF** curls — good for grip and rough gesture, not exact
sign language. The head has no facial articulation.

> Range-of-motion values are general literature data, not medical advice.

---

See [`docs/market-research.md`](docs/market-research.md) for where Movit spreads
fastest, the per-domain go-to-market briefs, and which engine unlock opens which
locked domain.
161 changes: 161 additions & 0 deletions docs/market-research.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# Movit — market research & go-to-market

> Where Movit spreads fastest, who pulls hardest, and which engine unlock opens
> which locked domain. Companion to [`../ROADMAP.md`](../ROADMAP.md) (engine
> capabilities) and [`../spec/llm-authoring.md`](../spec/llm-authoring.md)
> (how an LLM authors a movement).

## 1. The thesis

Movit is **"Mermaid for human movement."** A person describes a movement in
words; an LLM writes a short `.movit` document; the browser parses it, clamps it
to a safe range of motion, and renders an animated 3D mannequin — producing a
**shareable URL**. The loop is:

> **ask an LLM for a movement → it renders → share the link.**

This is structurally different from video. A `.movit` doc is **editable text**:
an LLM can generate it, a human can tweak one angle, a clinician can fork it, and
it diffs in version control. Diffusion/video models hallucinate anatomy and can't
be safely constrained; Movit's ROM clamp is a *correctness* feature, not a filter.
Text is also how LLMs natively "think" about structure — so authoring is reliable
and improves as models improve.

### Why it can spread

- **LLM-native.** The unit of creation is a code block any chat model emits. No
studio, no mocap, no rigging.
- **Shareable by construction.** Every movement is a URL ([`movit-share`](../packages/movit-share)).
A link is the most viral object on the internet.
- **Agent-native.** The [`movit-mcp`](../packages/movit-mcp) server lets Claude/
ChatGPT author, validate, and return a render link *inside the chat* — the
movement appears where the user already is.
- **Safe to trust.** Clinical ROM limits mean shared links can't depict unsafe
joint angles — important for the health-adjacent buyers below.

## 2. How we scored the domains

Each domain is rated on four axes:

| Axis | Question |
| --- | --- |
| **Engine-fit today** | Does it render cleanly on the v0.1 rig (1 figure, FK, ground-locked feet/hands, no props, no reach-IK)? |
| **Customer pull** | Is there an acute, recurring need a free shareable demo satisfies? |
| **Virality** | How naturally does output get shared, embedded, or re-prompted? |
| **LLM-authorability** | Can a model reliably write correct docs with little context? |

The four domains below score highest on **engine-fit × authorability** — they
work *today*, so the catalog and the viral loop compound now rather than waiting
on the roadmap.

## 3. Target domains (ship now)

### 3a. Anatomy & movement education — *top of funnel*

- **Customer:** anatomy/kinesiology students & instructors, PT/OT/med students,
personal-trainer certifications, biology teachers, curious people.
- **Aha use case:** "What is shoulder abduction?" → an isolated joint sweeps
through its plane, labeled. The answer is a *moving figure*, not a static
diagram.
- **Viral loop:** an LLM answering an anatomy question embeds a Movit link;
teachers paste links into slides/LMS; students re-prompt for the next joint.
- **Ships:** `shoulder-abduction-demo`, `hip-flexion-demo`, `knee-flexion-demo`,
`spine-rotation-demo`, `elbow-flexion-pronation`.
- **Engine-fit:** ★★★★★ — single-joint ROM demos are *exactly* what the rig does.

### 3b. Physiotherapy & rehab

- **Customer:** physios, chiros, athletic trainers, and their patients running
home-exercise programs; post-op ROM protocols.
- **Aha use case:** a clinician types a prescription and hands the patient a link
that *shows* the exercise, with a built-in safe-range guarantee.
- **Viral loop:** clinician → patient link sharing is high-frequency and trusted;
patients forward to family; clinics build reusable libraries.
- **Ships:** `heel-raises`, `standing-hamstring-curl`, `hip-abduction`,
`good-morning` (back-health hinge), plus existing `neck-rotation`,
`shoulder-stretch`.
- **Engine-fit:** ★★★★☆ — the ROM clamp is a clinical feature; bands/balls and
lying poses are future (see roadmap).

### 3c. Desk & workplace wellness

- **Customer:** remote workers, HR/wellness programs, ergonomics consultants,
"stretch break" apps.
- **Aha use case:** a recurring "do this every hour" prompt returns a fresh
60-second posture-reset animation.
- **Viral loop:** Slack/Teams wellness bots posting a daily link; an LLM "stretch
break" habit; embeds on internal wikis.
- **Ships:** `shoulder-rolls`, `neck-side-stretch`, `chest-opener`,
`overhead-reach-reset`, plus existing `posture-reset`, `spinal-twist`.
- **Engine-fit:** ★★★★☆ — standing variants render today; true *seated* needs a
chair prop.

### 3d. Sports, martial arts & **dance** — *flagship*

- **Customer:** coaches, dancers/choreographers, martial-arts instructors,
general athletes warming up.
- **Aha use case (sports/MA):** stances, strikes, and warm-up drills as
short, snappy, shareable clips — `front-kick`, `jab-cross`, `horse-stance`,
`bow`, `arm-circles`, `high-knee-march`.

#### Dance / choreography — the flagship bet

Dance is where the *editable-text* thesis is most magical: **you describe the
movement in your head and watch it appear** — then nudge a beat, swap an arm
position, extend the phrase, and re-share. It is inherently sequential,
expressive, and social — exactly the content people share.

- **Customer:** choreographers drafting and notating phrases, dance teachers,
students learning vocabulary, social dancers.
- **Aha use case:** "give me an 8-count: plié, port de bras, relevé" →
`dance-phrase` renders a real phrase you can scrub, loop, and link.
- **Viral loop:** dancers share phrase links; teachers assign them; students
re-prompt variations; the gallery becomes a browsable vocabulary.
- **Ships:** `demi-plie`, `releve`, `tendu`, `port-de-bras`, and the combined
`dance-phrase` centerpiece.
- **Engine-fit:** ★★★☆☆ today (turnout, plié, relevé, port de bras all render);
precise foot placement, traveling steps, and partner work are future.
- **Long game:** a **shareable, LLM-authorable choreography notation** — Labanotation
was never going to be typed into a chat box; a `.movit` phrase is. If Movit
becomes the way people sketch and pass around movement, dance is the wedge.

## 4. Spread mechanics

- **MCP inside the assistant.** [`movit-mcp`](../packages/movit-mcp) puts authoring +
a render link directly in Claude/ChatGPT — distribution rides on assistants we
don't have to build an audience for.
- **Links as the unit.** [`movit-share`](../packages/movit-share) makes every
movement a URL; links are forwarded, bookmarked, and embedded.
- **Gallery grouped by domain.** The playground presets carry a `domain` and the
gallery auto-groups them (Education, Physiotherapy, Desk & posture, Martial
arts, Warm-up, Dance, Fitness, Yoga, Mobility) so breadth is visible on the
landing page and each domain has an obvious entry point.
- **Education as top-of-funnel.** Anatomy demos answer questions millions already
ask LLMs daily; each answer can carry a link.
- **Workplace cadence.** "Every hour" stretch prompts create recurring,
habit-driven link generation.
- **Embeds.** A link that renders in an iframe drops Movit into LMSs, clinic
portals, and blog posts.

## 5. Which engine unlock opens which domain

From [`../ROADMAP.md`](../ROADMAP.md), in rough order of leverage:

| Unlock | Domains it opens / deepens | Status |
| --- | --- | --- |
| **Hip-hinge** | Fitness (deadlift, row, good-morning), back-health physio, martial-arts bow | ✅ shipped |
| **Reach-to-target IK** | Big share of physio (touch toes, cross-body), yoga, prop interaction | ✅ shipped |
| **Scene props + anchors** | Sit-to-stand, box squat, wall sit, dead hang / hanging knee raise | ✅ shipped (chair / wall / bar) |
| **Lying / seated base poses** | Floor yoga, mat Pilates, bed-based rehab (glute bridge, dead bug, cobra) | ✅ shipped |
| **Hand / finger rig** | Grip rehab, expressive gesture, rough finger-spelling | ✅ shipped (single-DOF) |
| **Two-person + collision** | Partner stretches, assisted rehab, contact sports | ⏳ deferred |

The strategic read: **education + physio + desk + dance** monetize the rig and
build the catalog/virality flywheel. With reach-IK, props, lying/seated poses, and
a hand rig now shipped, the roadmap's 🟡 domains (functional/elderly care, floor
yoga, loaded strength, gesture) are reachable today; the remaining frontier is
deeper props (load, bands, rings), ROM-constrained reach, and two-person work.

> ⚠️ Movit's range-of-motion values are general literature data, not medical
> advice. Consult a qualified professional for physiotherapy or exercise
> prescription.
14 changes: 10 additions & 4 deletions packages/movit-language/src/vocab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,32 @@ export { JOINT_NAMES, ACTION_NAMES, EASINGS };
export const KINDS = ["exercise", "stretch", "posture"];

/** Recognised start poses (`pose start = ...`). */
export const POSES = ["neutral", "standing", "plank"];
export const POSES = ["neutral", "standing", "plank", "supine", "prone", "seated"];

/** Effectors that can be ground-locked. */
export const EFFECTORS = ["hands", "feet"];

/** Reach effectors (friendly aliases) and the scene props that supply anchors. */
export const REACH_EFFECTORS = ["hand_left", "hand_right", "foot_left", "foot_right"];
export const PROPS = ["chair", "wall", "bar"];

/** Top-level directives (excluding the `movit` header keyword). */
export const TOP_KEYWORDS = ["rig", "pose", "step", "repeat"];
export const TOP_KEYWORDS = ["rig", "prop", "pose", "step", "repeat"];

/** Keywords valid as step children. */
export const CHILD_KEYWORDS = ["ground-lock", "cue"];
export const CHILD_KEYWORDS = ["ground-lock", "reach", "cue"];

/** Short docs surfaced on hover and as completion detail. */
export const KEYWORD_DOCS: Record<string, string> = {
movit: 'Document header — `movit <kind> "<name>"`.',
rig: "Selects the rig (currently `humanoid`).",
pose: "Sets the starting pose — `pose start = standing | neutral | plank`.",
prop: "Adds a scene object — `prop chair | wall | bar`. Supplies reach anchors.",
pose: "Sets the starting pose — `pose start = standing | neutral | plank | supine | prone | seated`.",
start: "Used in `pose start = <pose>`.",
step: 'A movement phase — `step "<name>" <Ns> <easing>:`.',
repeat: "How many times the movement loops.",
"ground-lock": "Pins effectors (hands / feet) to the floor for this phase.",
reach: "Drives an effector to a target via IK — `reach: hand_left ankle_left`.",
cue: "A short coaching cue shown while this phase plays.",
hold: "Keep the joint at its neutral / rest angle.",
};
2 changes: 2 additions & 0 deletions packages/movit-parser/src/clamp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export function resolve(ast: AstDoc): ResolveResult {
name: ast.name,
rig: ast.rig,
...(ast.startPose ? { startPose: ast.startPose } : {}),
props: ast.props,
repeat: ast.repeat,
phases,
};
Expand Down Expand Up @@ -119,6 +120,7 @@ function resolveStep(
easing: step.easing as Phase["easing"],
targets,
groundLock: step.groundLock,
reaches: step.reaches,
...(step.cue ? { cue: step.cue } : {}),
};
}
Expand Down
1 change: 1 addition & 0 deletions packages/movit-parser/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export type {
Easing,
EulerDeg,
JointTarget,
ReachTarget,
Phase,
MovitIR,
Warning,
Expand Down
36 changes: 36 additions & 0 deletions packages/movit-parser/src/joints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,51 @@ export const BONES = [
"knee_right",
"ankle_left",
"ankle_right",

// Hand rig: one curl bone per finger (single DOF), off each wrist.
"thumb_left",
"index_left",
"middle_left",
"ring_left",
"pinky_left",
"thumb_right",
"index_right",
"middle_right",
"ring_right",
"pinky_right",
] as const;

export type BoneId = (typeof BONES)[number];

const BONE_SET = new Set<string>(BONES);

/** Symmetric DSL group names → the bones they expand to. */
const FINGERS_LEFT: BoneId[] = [
"thumb_left",
"index_left",
"middle_left",
"ring_left",
"pinky_left",
];
const FINGERS_RIGHT: BoneId[] = [
"thumb_right",
"index_right",
"middle_right",
"ring_right",
"pinky_right",
];

const GROUPS: Record<string, BoneId[]> = {
shoulders: ["shoulder_left", "shoulder_right"],
elbows: ["elbow_left", "elbow_right"],
wrists: ["wrist_left", "wrist_right"],
hips: ["hip_left", "hip_right"],
knees: ["knee_left", "knee_right"],
ankles: ["ankle_left", "ankle_right"],
// Finger groups: curl one hand, or both with `fingers`.
fingers_left: FINGERS_LEFT,
fingers_right: FINGERS_RIGHT,
fingers: [...FINGERS_LEFT, ...FINGERS_RIGHT],
};

/** Symmetric group names usable as joints in the DSL (e.g. "shoulders"). */
Expand Down Expand Up @@ -81,6 +112,11 @@ const ACTIONS: Record<string, ActionAxis> = {
pronate: { axis: "y", sign: -1 },
dorsiflex: { axis: "x", sign: 1 },
plantarflex: { axis: "x", sign: -1 },
// Hip hinge: tip the torso forward over the hip line (deadlift, row, bow,
// good-morning). Applied to the `pelvis`; sign -1 tips the figure forward
// (same sagittal direction as spine flex). The renderer counter-rotates the
// hips so the legs stay planted — see movit-render/src/timeline.ts.
hinge: { axis: "x", sign: -1 },
};

/** Every semantic action name the DSL accepts (e.g. "flex", "abduct"). */
Expand Down
Loading