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
2 changes: 1 addition & 1 deletion packages/posecode-language/src/hover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export function getHover(
if (KINDS.includes(token)) return md(`Movement kind **${token}**.`);
if (POSES.includes(token)) return md(`Start pose **${token}**.`);
if ((MODES as readonly string[]).includes(token)) {
return md(`**${token}** ${KEYWORD_DOCS[token] ?? "timing mode"}`);
return md(`**${token}**: ${KEYWORD_DOCS[token] ?? "timing mode"}`);
}
return null;
}
6 changes: 3 additions & 3 deletions packages/posecode-language/src/vocab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ export const KEYWORD_DOCS: Record<string, string> = {
step: 'A movement phase: `step "<name>" <Ns> <mode>:` where mode is flow | settle | drive | snap | linear.',
flow: "Timing mode: pass through this pose with continuous velocity (flowing motion).",
settle: "Timing mode: decelerate to a genuine rest at this pose (a deliberate pause).",
drive: "Timing mode: accelerate from rest the concentric effort of a rep.",
snap: "Timing mode: fast, near-immediate arrival an accent.",
linear: "Timing mode: constant velocity intentionally mechanical.",
drive: "Timing mode: accelerate from rest, like the concentric effort of a rep.",
snap: "Timing mode: fast, near-immediate arrival with an accent.",
linear: "Timing mode: constant velocity; intentionally mechanical.",
repeat: "How many times the movement loops.",
"ground-lock": "Keeps grouped, per-side, or axial contacts on the floor: `feet`, `foot_left` (also `left foot`), `hands`, `forearms`, or `back` for supine work. Planted feet auto-level unless intentionally plantarflexed.",
reach:
Expand Down
2 changes: 1 addition & 1 deletion playground/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ <h1 class="headline">
</h1>
<p class="subhead">
Turn readable instructions into precise 3D movement. Build exercises,
stretches, dance phrases, and rehab routinesthen edit every beat live in
stretches, dance phrases, and rehab routines, then edit every beat live in
the browser.
</p>
<div class="hero-cta">
Expand Down
2 changes: 1 addition & 1 deletion playground/play.html
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@

<div id="intro" class="intro">
<span class="intro-text">
<b>Make something move.</b> Pick a movement or edit the instructionsthe
<b>Make something move.</b> Pick a movement or edit the instructions; the
figure updates as you type.
</span>
<button id="intro-open" class="link">Show me how →</button>
Expand Down
2 changes: 1 addition & 1 deletion playground/public/spec.html
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ <h2>5. Rendering model</h2>
<ol><li><strong>Reach-IK</strong>: a <code>reach:</code> line drives an effector (`hand_left|hand_right|</li></ol>
<p>foot_left|foot_right<code>, or the groups </code>hands<code>/</code>feet<code> for both sides) to a world <strong>target</strong> via Cyclic Coordinate Descent (CCD) over the arm/leg chain. A target is a body landmark bone (e.g. </code>ankle_left<code>), the keyword </code>floor<code>, or a prop anchor (</code>bar<code>, </code>seat<code>, </code>wall`). The solve is <strong>ROM-constrained</strong>: each iteration clamps every chain joint into its §4 Range-of-Motion limits (expressed as a per-axis box in the bone's local Euler frame), so a reach toward an unsafe or unreachable target settles on the closest *healthy* pose; solved angles obey the same hard limits as authored ones.</p>
<ol><li><strong>Props</strong>: <code>prop chair|wall|bar|box|dip-bars</code> adds a scene object at a</li></ol>
<p>fixed default placement (chair/wall behind, bar overhead, box in front, dip bars either side); its named anchors (<code>seat</code>, <code>wall</code>, <code>bar</code>, <code>box</code>, <code>bars</code>) become reach/pin targets. Props are <strong>solid</strong>: each prop declares blocking faces (the wall's surface, the chair's backrest and seat edge, the box's near face) and a contact pass removes any body overlap either by translating the whole figure out along the face normal (a wall-sit slides down the wall's *surface*, feet walking forward, instead of the torso hinging through the slab) or by bending the offending limb's hip clear, ROM-clamped like every other solve. Limbs pinned, gripped, or reached to a prop anchor are that phase's declared support and are exempt (a foot standing on the box top is not &quot;inside&quot; the box).</p>
<p>fixed default placement (chair/wall behind, bar overhead, box in front, dip bars either side); its named anchors (<code>seat</code>, <code>wall</code>, <code>bar</code>, <code>box</code>, <code>bars</code>) become reach/pin targets. Props are <strong>solid</strong>: each prop declares blocking faces (the wall's surface, the chair's backrest and seat edge, the box's near face) and a contact pass removes any body overlap: either by translating the whole figure out along the face normal (a wall-sit slides down the wall's *surface*, feet walking forward, instead of the torso hinging through the slab) or by bending the offending limb's hip clear, ROM-clamped like every other solve. Limbs pinned, gripped, or reached to a prop anchor are that phase's declared support and are exempt (a foot standing on the box top is not &quot;inside&quot; the box).</p>
<ol><li><strong>Pins</strong>: <code>pin: &lt;effector&gt; &lt;anchor&gt;</code> translates the whole figure so the</li></ol>
<p>effector sits on the anchor (effectors accept the same <code>hands</code>/<code>feet</code> groups as reach: <code>pin: hands bar</code> pins both). Where ground-lock keeps a foot on the floor and reach moves a limb to a target, a <strong>pin moves the body</strong> while the contact stays put, so the figure hangs from a bar, pulls up toward it, rises onto a box, or lowers into a dip as the joints work. Symmetric bar contacts resolve to side-specific anchors automatically (<code>bar.left</code> / <code>bar.right</code>, <code>bars.left</code> / <code>bars.right</code>). Contact post-processing also keeps floor-contacting soles level and gives bar-contacting wrists a stable overhand orientation; existing Posecode syntax remains unchanged.</p>
<ol><li><strong>Spatial choreography</strong>: <code>turn: &lt;deg&gt;</code> rotates the figure's facing (yaw</li></ol>
Expand Down
2 changes: 1 addition & 1 deletion spec/SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ research §5.1 normative tables. Selected ceilings (degrees):
dip bars either side); its named anchors (`seat`, `wall`, `bar`, `box`,
`bars`) become reach/pin targets. Props are **solid**: each prop declares
blocking faces (the wall's surface, the chair's backrest and seat edge,
the box's near face) and a contact pass removes any body overlap either
the box's near face) and a contact pass removes any body overlap: either
by translating the whole figure out along the face normal (a wall-sit
slides down the wall's *surface*, feet walking forward, instead of the
torso hinging through the slab) or by bending the offending limb's hip
Expand Down
6 changes: 3 additions & 3 deletions video/cut2/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ const Result = () => {
</div>
<div style={{position: 'absolute', left: 'calc(50% - 30px)', top: 290, width: 60, height: 60, borderRadius: 60, background: C.lime, color: C.ink, display: 'grid', placeItems: 'center', fontSize: 31, fontWeight: 900, boxShadow: '0 0 30px rgba(198,242,74,.5)', transform: `scale(${split})`}}>→</div>
</div>
<Caption keyword="renders">It renders — safe, 60fps.</Caption>
<Caption keyword="renders">It renders safely at 60fps.</Caption>
</AbsoluteFill>;
};

Expand All @@ -212,7 +212,7 @@ const Mcp = () => {
];
return <AbsoluteFill style={{opacity: fade(frame, BEAT)}}>
<div style={{position: 'absolute', top: 195, left: 135, right: 135, display: 'grid', gridTemplateColumns: '1.25fr .75fr', gap: 24, transform: `translateY(${rise(frame)}px)`}}>
<Window title="terminal posecode-mcp">
<Window title="terminal: posecode-mcp">
<div style={{height: 560, padding: '42px 42px', boxSizing: 'border-box', fontFamily: 'JetBrains Mono, monospace'}}>
{entries.map(([a,b], i) => <div key={a} style={{display: 'flex', justifyContent: 'space-between', fontSize: i === 0 ? 25 : 20, lineHeight: 2.35, opacity: interpolate(frame, [i * 14, i * 14 + 8], [0, 1], clamp), color: i === 0 ? C.white : i === 1 ? C.lime : '#d2dae6'}}><span>{a}</span><span style={{color: i > 1 ? C.lime : C.muted}}>{b}</span></div>)}
</div>
Expand Down Expand Up @@ -336,7 +336,7 @@ const VerticalCut2 = () => {
<div style={{position: 'absolute', right: 48, top: 330, background: C.lime, color: C.ink, fontFamily: 'JetBrains Mono, monospace', fontWeight: 800, borderRadius: 999, padding: '13px 18px'}}>60 FPS</div>
</div>}
{beat === 4 && <div style={sceneStyle}>
<div style={{position: 'absolute', top: 285, left: 48, right: 48}}><VCard title="terminal posecode-mcp"><div style={{height: 920, padding: '48px 38px', fontFamily: 'JetBrains Mono, monospace', fontSize: 25, lineHeight: 2.4}}><div style={{fontSize: 30, color: C.white}}>$ npx posecode-mcp</div><div style={{color: C.lime}}>● connected</div><div>→ authoring_guide <span style={{float: 'right', color: C.lime}}>✓</span></div><div>→ validate_posecode <span style={{float: 'right', color: C.lime}}>safe ✓</span></div><div>→ render_posecode <span style={{float: 'right', color: C.lime}}>ready ✓</span></div><div style={{height: 330, marginTop: 30, borderRadius: 22, border: `1px solid ${C.line}`}}><MoveVideo src="squat.mp4" style={{height: '100%', borderRadius: 22}} /></div></div></VCard></div>
<div style={{position: 'absolute', top: 285, left: 48, right: 48}}><VCard title="terminal: posecode-mcp"><div style={{height: 920, padding: '48px 38px', fontFamily: 'JetBrains Mono, monospace', fontSize: 25, lineHeight: 2.4}}><div style={{fontSize: 30, color: C.white}}>$ npx posecode-mcp</div><div style={{color: C.lime}}>● connected</div><div>→ authoring_guide <span style={{float: 'right', color: C.lime}}>✓</span></div><div>→ validate_posecode <span style={{float: 'right', color: C.lime}}>safe ✓</span></div><div>→ render_posecode <span style={{float: 'right', color: C.lime}}>ready ✓</span></div><div style={{height: 330, marginTop: 30, borderRadius: 22, border: `1px solid ${C.line}`}}><MoveVideo src="squat.mp4" style={{height: '100%', borderRadius: 22}} /></div></div></VCard></div>
</div>}
{beat === 5 && <div style={sceneStyle}>
<div style={{position: 'absolute', top: 255, left: 42, right: 42}}><VCard title="demo.html"><div style={{height: 1050, padding: '45px 35px', boxSizing: 'border-box', fontFamily: 'JetBrains Mono, monospace', fontSize: 23, lineHeight: 1.7}}><div style={{color: '#8fd7ff'}}>&lt;script</div><div style={{paddingLeft: 24}}><span style={{color: C.lime}}>src</span>=<span style={{color: '#ffd38f'}}>"https://unpkg.com/</span></div><div style={{paddingLeft: 24, color: '#ffd38f'}}>posecode-embed/dist/</div><div style={{paddingLeft: 24, color: '#ffd38f'}}>posecode-embed.js"</div><div style={{color: '#8fd7ff'}}>&gt;&lt;/script&gt;</div><div style={{height: 34}}/><div style={{color: '#8fd7ff'}}>&lt;posecode-player</div><div style={{paddingLeft: 24}}><span style={{color: C.lime}}>src</span>=<span style={{color: '#ffd38f'}}>"/movements/</span></div><div style={{paddingLeft: 24, color: '#ffd38f'}}>squat.posecode"</div><div style={{color: '#8fd7ff'}}>&gt;&lt;/posecode-player&gt;</div><div style={{height: 360, marginTop: 30, border: `1px solid ${C.line}`, borderRadius: 22}}><MoveVideo src="squat.mp4" style={{height: '100%', borderRadius: 22}} /></div></div></VCard></div>
Expand Down