From 57b121eb095c086554f97cf2bb90b20b3a368403 Mon Sep 17 00:00:00 2001 From: a-baran-orhan Date: Fri, 17 Jul 2026 23:37:40 +0300 Subject: [PATCH 1/2] Redesign landing page around LLM-written motion --- playground/index.html | 331 ++++----- playground/src/landing.css | 1321 +++++++++++++++++++++--------------- playground/src/landing.ts | 41 +- 3 files changed, 937 insertions(+), 756 deletions(-) diff --git a/playground/index.html b/playground/index.html index 0ab566d..d95b83e 100644 --- a/playground/index.html +++ b/playground/index.html @@ -126,7 +126,6 @@ - - -
-
-

Movement is programmable

-

- Write the move.
Watch it happen. -

-

- Turn readable instructions into structured, inspectable 3D motion. Build exercises, - stretches, dance phrases, and rehab routines, then edit every beat live in - the browser. -

-
- Open the playground → - +
+
+
+

A motion language for LLMs

+

Give your LLM
a body.

+

+ Posecode turns LLM-written text into structured, editable 3D human motion, live in your browser. +

+
+ Open the playground → + +
+
+ Open source + Runs on-device + LLM-ready +
-

- 48 launch-ready moves  ·  25 experimental previews  ·  validated text  ·  open source -

-
-
-
- -
+
+ + +
Drop into the landing
+
- -
-
-
-

Semantic, not matrices

-

- Models write phases and joint angles, like knees: flex 95, - instead of 3D transforms. The closed syntax makes the intended anatomy inspectable. -

-
-
-
-

Range-aware & testable

-

- Joint targets are constrained to configured reference ranges, while reach - residuals expose a fist, foot, or knee that remains short of its target. -

-
-
-
-

Cheap & client-side

-

- Generation is compact text. Rendering is forward kinematics and constrained IK - in Three.js on the user's device, with no server-side diffusion pipeline. -

-
-
+ + + - -
-
-

See it move

-

One language, many practices

-

- A taste of the library, from physiotherapy and posture to yoga, dance, and - martial arts. Every movement opens in the playground, editable and - shareable. -

-
-
-
+
+
+ 01 +
LLM-native

Readable movement, not matrices.

+
+
+ 02 +
Range-aware

Targets stay within configured ranges.

+
+
+ 03 +
Browser-native

Live 3D, no server-side diffusion.

+
+
- -
-
-

How it works

-

From a sentence to a moving figure

-
-
    -
  1. - 1 -

    A capable model writes .posecode

    -

    Give the Posecode authoring guide to a capable model and ask for a representable movement. For a supported request, its raw .posecode output remains editable and reviewable.

    -
  2. -
  3. - 2 -

    The parser validates & clamps

    -

    A TypeScript parser enforces the closed vocabulary, joint/action compatibility, contacts, and configured range limits.

    -
  4. -
  5. - 3 -

    Three.js renders it

    -

    Forward kinematics plus constrained contact IK animate a low-poly figure live in the browser.

    -
  6. -
-
+
+
+

How it works

+

One prompt. Three clear steps.

+
+
    +
  1. + 01 +

    Ask

    +

    Describe a representable movement.

    +
  2. +
  3. + 02 +

    Generate

    +

    A capable LLM writes a tiny .posecode file.

    +
  4. +
  5. + 03 +

    Move

    +

    The browser validates, constrains, and animates it.

    +
  6. +
+
- -
-
-

For developers

-

An open core you can build on

-
-
- -

Playground →

-

Live editor, 3D viewport, syntax highlighting, inline range-of-motion diagnostics.

-
-
-

MCP server

-

Let a model in an MCP client validate a movement and get back a render link.

- npx -y posecode-mcp -
-
-

VS Code extension

-

Highlighting, completion, hover docs, and ROM diagnostics for .posecode files.

-
- -

Apache 2.0 libraries

-

posecode-parser, posecode-render, and posecode-share are framework-agnostic and on GitHub.

-
-
-
+
+
+

Movement library

+

Ask for almost any move.

+

Explore launch-ready examples across fitness, rehab, dance, and more.

+
+
+
- -
-
-

FAQ

-

Common questions

-
-
-
-
What is Posecode?
-
- Posecode is an open-source text-to-motion language. You describe single-person - movement as phases, joint targets, timing, and contacts; the browser validates - the document and renders it as an animated 3D figure. -
-
-
-
How do I generate an exercise animation with an LLM?
-
- Copy the authoring guide into a capable chat model and ask for a representable - movement such as a hip hinge or hamstring stretch. For a representable request, - the model should return raw .posecode text. Paste it into the - playground: valid documents animate, while parse errors, range clamps, and - unresolved reach targets appear as diagnostics. -
-
-
-
Does Posecode guarantee a movement is safe?
-
- No. Posecode constrains authored and IK-generated joint targets to configured - reference ranges and reports unresolved reach targets. A simplified rig cannot - certify that a whole movement is safe, accurate, or appropriate for a person. - It is not medical advice. -
+
+
+

For developers

+

Open all the way down.

+

Use the language, parser, renderer, or agent tools. Everything is Apache 2.0 licensed.

+
+ -
-
Is Posecode free to use?
-
- Yes. Posecode is Apache-2.0-licensed and open source: the parser, 3D renderer, share - codec, MCP server, and VS Code extension are all free, and rendering runs - locally in a WebGL-capable browser without server-side motion generation. -
+
+ +
+

Your turn

+

What should a body do?

+

Ask your LLM. Paste the result. Watch it move.

+
+ Start with the playground → +
-
-
+ + - diff --git a/playground/src/landing.css b/playground/src/landing.css index 8e85eec..b126503 100644 --- a/playground/src/landing.css +++ b/playground/src/landing.css @@ -1,8 +1,6 @@ -/* ============================================================================ - Posecode — landing page. Extends the "Kinetic Lab" identity (studio-dark + a - single lime accent, Hanken Grotesk + JetBrains Mono) into a demo-forward - product page. Palette mirrors style.css so the landing and playground match. - ========================================================================== */ +/* Posecode landing page — the playground's Kinetic Lab system, simplified + into a short LLM-first story. The palette and logo treatment deliberately + mirror style.css so the marketing surface and tool feel like one product. */ :root { --bg: #0a0d12; @@ -17,6 +15,7 @@ --muted: #616d7c; --accent: #c6f24a; --accent-2: #a9e02f; + --brand-accent: #d4ff3f; --accent-ink: #0a0d12; --accent-glow: rgba(198, 242, 74, 0.45); --accent-veil: rgba(198, 242, 74, 0.16); @@ -24,13 +23,14 @@ --mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace; --sans: "Hanken Grotesk", system-ui, -apple-system, "Segoe UI", sans-serif; - --radius: 14px; - --radius-sm: 9px; - --shadow-2: 0 24px 60px -28px rgba(0, 0, 0, 0.8); - --ease: cubic-bezier(0.22, 1, 0.36, 1); + --radius: 10px; + --radius-sm: 8px; --container: 1180px; + --ease-out: cubic-bezier(0.23, 1, 0.32, 1); + --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1); + --shadow-float: 0 2px 4px rgba(0, 0, 0, 0.3), 0 24px 64px -24px rgba(0, 0, 0, 0.88); + --edge: inset 0 1px 0 rgba(255, 255, 255, 0.05); - /* Syntax colors (match the editor) */ --t-kw: var(--accent); --t-kind: #79c0ff; --t-act: #ffcc66; @@ -44,19 +44,21 @@ * { box-sizing: border-box; } + html { scroll-behavior: smooth; } + body { margin: 0; + overflow-x: hidden; background: var(--bg); color: var(--text); font-family: var(--sans); font-size: 16px; - line-height: 1.6; + line-height: 1.55; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; - overflow-x: hidden; } .bg-fx { @@ -64,15 +66,16 @@ body { inset: 0; z-index: -2; background: - radial-gradient(70vw 60vh at 85% -5%, rgba(198, 242, 74, 0.08), transparent 60%), - radial-gradient(60vw 50vh at 5% 105%, rgba(70, 110, 160, 0.08), transparent 55%), + radial-gradient(68vw 56vh at 82% -8%, rgba(198, 242, 74, 0.075), transparent 64%), + radial-gradient(54vw 52vh at 4% 108%, rgba(70, 110, 160, 0.08), transparent 58%), var(--bg); } + .bg-fx::after { content: ""; position: absolute; inset: 0; - opacity: 0.035; + opacity: 0.028; mix-blend-mode: overlay; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); } @@ -81,61 +84,86 @@ a { color: inherit; text-decoration: none; } + +button, +a { + -webkit-tap-highlight-color: transparent; +} + code { - font-family: var(--mono); - font-size: 0.88em; - color: var(--text); - background: var(--panel-2); + padding: 1px 6px; border: 1px solid var(--border); border-radius: 5px; - padding: 1px 6px; + background: var(--panel-2); + color: var(--text); + font-family: var(--mono); + font-size: 0.88em; +} + +.hero, +.proof, +.how, +.examples, +.developers, +.final-cta, +.footer { + width: min(100%, var(--container)); + margin-inline: auto; + padding-inline: 28px; } -/* --- Buttons --------------------------------------------------------------- */ +/* Buttons use the same material and lime hierarchy as the playground. */ .btn { - font-family: var(--sans); - font-weight: 700; - font-size: 14px; - letter-spacing: 0.1px; - color: var(--text); - background: var(--panel-2); - border: 1px solid var(--border-2); - border-radius: var(--radius-sm); - padding: 10px 18px; - cursor: pointer; display: inline-flex; align-items: center; justify-content: center; gap: 8px; + padding: 10px 18px; + border: 1px solid var(--border-2); + border-radius: var(--radius-sm); + background: var(--panel-2); + color: var(--text); + font-family: var(--sans); + font-size: 14px; + font-weight: 700; + letter-spacing: 0.1px; + line-height: 1.2; white-space: nowrap; - transition: transform 0.12s var(--ease), border-color 0.16s var(--ease), - background 0.16s var(--ease), box-shadow 0.16s var(--ease), color 0.16s var(--ease); -} -.btn:hover { - border-color: var(--accent); - color: #fff; - box-shadow: 0 0 0 1px var(--accent-veil), 0 8px 22px -12px var(--accent-glow); + cursor: pointer; + box-shadow: var(--edge); + transition: + transform 140ms var(--ease-out), + border-color 180ms var(--ease-out), + background 180ms var(--ease-out), + box-shadow 180ms var(--ease-out), + color 180ms var(--ease-out); } + .btn:active { - transform: translateY(1px); + transform: scale(0.97); } + +.btn:focus-visible, +.nav-links a:focus-visible, +.footer-links a:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 3px; +} + .btn.primary { - color: var(--accent-ink); - background: linear-gradient(180deg, var(--accent), var(--accent-2)); border-color: transparent; - box-shadow: 0 1px 0 rgba(255, 255, 255, 0.25) inset, 0 8px 22px -10px var(--accent-glow); -} -.btn.primary:hover { + background: linear-gradient(180deg, var(--accent), var(--accent-2)); color: var(--accent-ink); - filter: brightness(1.06); - box-shadow: 0 1px 0 rgba(255, 255, 255, 0.3) inset, 0 12px 30px -10px var(--accent-glow); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.27), 0 8px 22px -10px var(--accent-glow); } + .btn.lg { - padding: 13px 24px; + min-height: 48px; + padding: 13px 22px; font-size: 15px; } -/* --- Nav ------------------------------------------------------------------- */ +/* Floating translucent navigation matches the playground top bar. */ .nav { position: sticky; top: 0; @@ -143,177 +171,220 @@ code { display: flex; align-items: center; gap: 22px; - max-width: var(--container); - margin: 0 auto; - padding: 16px 28px; - background: linear-gradient(180deg, rgba(10, 13, 18, 0.85), rgba(10, 13, 18, 0.4)); - backdrop-filter: blur(10px); - -webkit-backdrop-filter: blur(10px); + width: 100%; + min-height: 68px; + padding: 12px max(24px, calc((100vw - var(--container)) / 2 + 28px)); + border-bottom: 1px solid rgba(42, 50, 63, 0.72); + background: rgba(10, 13, 18, 0.78); + box-shadow: var(--edge); + backdrop-filter: blur(18px) saturate(140%); + -webkit-backdrop-filter: blur(18px) saturate(140%); } + .brand { display: inline-flex; - align-items: baseline; + align-items: center; gap: 9px; font-weight: 800; font-size: 19px; letter-spacing: -0.4px; } -.brand .logo { - color: var(--accent); - align-self: center; + +.brand .logo, +.footer-brand .logo { + flex: 0 0 auto; + color: var(--brand-accent); filter: drop-shadow(0 0 8px var(--accent-glow)); } + .nav-links { display: flex; - gap: 24px; + align-items: center; + gap: 25px; margin-left: auto; + color: var(--text-2); font-size: 14px; font-weight: 600; - color: var(--text-2); } -.nav-links a:hover { - color: var(--text); + +.nav-links a, +.footer-links a { + transition: color 150ms var(--ease-out); } + .nav-cta { + padding: 9px 15px; font-size: 13px; - padding: 9px 16px; } -/* --- Layout helpers -------------------------------------------------------- */ -.hero, -.props, -.examples, -.how, -.developers, -.faq, -.footer { - max-width: var(--container); - margin: 0 auto; - padding-left: 28px; - padding-right: 28px; +/* Hero: one sentence plus one visual chain (prompt → code → body). */ +.hero { + display: grid; + grid-template-columns: minmax(0, 0.88fr) minmax(500px, 1.12fr); + align-items: center; + gap: clamp(48px, 7vw, 92px); + min-height: min(800px, calc(100svh - 68px)); + padding-top: clamp(72px, 9vh, 110px); + padding-bottom: clamp(88px, 11vh, 132px); } -.section-head { - text-align: center; - max-width: 640px; - margin: 0 auto 48px; + +.hero-copy { + position: relative; + z-index: 2; } + .eyebrow { + margin: 0 0 16px; + color: var(--accent); font-family: var(--mono); - font-size: 12px; - font-weight: 600; + font-size: 11px; + font-weight: 700; letter-spacing: 2px; + line-height: 1.4; text-transform: uppercase; - color: var(--accent); - margin: 0 0 14px; -} -.section-head h2 { - font-size: clamp(28px, 4vw, 40px); - font-weight: 800; - letter-spacing: -1px; - margin: 0; - line-height: 1.1; -} -.section-sub { - color: var(--text-2); - margin: 14px 0 0; } -/* --- Hero ------------------------------------------------------------------ */ -.hero { - display: grid; - grid-template-columns: 1.05fr 0.95fr; - gap: 56px; - align-items: center; - padding-top: clamp(48px, 7vw, 96px); - padding-bottom: clamp(56px, 8vw, 110px); -} .headline { - font-size: clamp(40px, 6vw, 68px); + max-width: 10ch; + margin: 0 0 24px; + font-size: clamp(52px, 6vw, 84px); font-weight: 900; - line-height: 1.02; - letter-spacing: -2px; - margin: 0 0 22px; + letter-spacing: -0.058em; + line-height: 0.94; } + .headline .hl { - color: var(--accent); - position: relative; - white-space: nowrap; -} -.headline .hl::after { - content: ""; - position: absolute; - left: 0; - right: 0; - bottom: 0.06em; - height: 0.13em; - background: var(--accent); - opacity: 0.22; - border-radius: 2px; + color: var(--text); } + .subhead { - font-size: 18px; + max-width: 42ch; + margin: 0 0 31px; color: var(--text-2); - max-width: 50ch; - margin: 0 0 30px; + font-size: clamp(17px, 1.55vw, 20px); + line-height: 1.55; } + .hero-cta { display: flex; flex-wrap: wrap; - gap: 12px; + gap: 11px; } + .hero-meta { - margin: 26px 0 0; - font-family: var(--mono); - font-size: 12.5px; + display: flex; + flex-wrap: wrap; + gap: 10px 18px; + margin-top: 24px; color: var(--muted); + font-family: var(--mono); + font-size: 11px; letter-spacing: 0.3px; + text-transform: uppercase; +} + +.hero-meta span { + display: inline-flex; + align-items: center; + gap: 8px; +} + +.hero-meta span::before { + content: ""; + width: 4px; + height: 4px; + border-radius: 50%; + background: var(--accent); + box-shadow: 0 0 6px var(--accent-glow); } -/* Live studio card */ .hero-stage { position: relative; min-width: 0; + padding-top: 34px; +} + +.prompt-card { + position: absolute; + top: 0; + left: -38px; + z-index: 3; + width: min(360px, 74%); + padding: 14px 17px; + border: 1px solid var(--border-2); + border-radius: var(--radius); + background: rgba(20, 26, 35, 0.94); + box-shadow: var(--edge), 0 16px 34px -22px rgba(0, 0, 0, 0.9); + backdrop-filter: blur(14px); + -webkit-backdrop-filter: blur(14px); +} + +.prompt-label, +.code-label, +.studio-kicker { + color: var(--muted); + font-family: var(--mono); + font-size: 9px; + font-weight: 700; + letter-spacing: 1.35px; + text-transform: uppercase; +} + +.prompt-card p { + margin: 4px 0 0; + color: var(--text); + font-size: 14px; + font-weight: 600; + line-height: 1.4; } + .studio { position: relative; + overflow: hidden; border: 1px solid var(--border-2); border-radius: var(--radius); - overflow: hidden; background: var(--bg-viewer); - box-shadow: var(--shadow-2); + box-shadow: var(--edge), var(--shadow-float); } + .studio-bar { display: flex; align-items: center; gap: 10px; - padding: 11px 14px; + min-height: 43px; + padding: 10px 14px; border-bottom: 1px solid var(--border); - background: var(--panel); + background: rgba(15, 20, 27, 0.94); } -.studio-bar .dots { - width: 9px; - height: 9px; - border-radius: 50%; - background: var(--border-2); - box-shadow: 15px 0 0 var(--border-2), 30px 0 0 var(--border-2); - margin-right: 26px; + +.studio-kicker { + padding-right: 10px; + border-right: 1px solid var(--border-2); } + .studio-title { - font-family: var(--mono); - font-size: 12px; + overflow: hidden; color: var(--text-2); + font-family: var(--mono); + font-size: 11px; + text-overflow: ellipsis; + white-space: nowrap; } + .studio-live { - margin-left: auto; display: inline-flex; align-items: center; gap: 6px; + margin-left: auto; + color: var(--accent); font-family: var(--mono); - font-size: 10px; + font-size: 9px; + font-weight: 700; letter-spacing: 1px; text-transform: uppercase; - color: var(--accent); + white-space: nowrap; } + .studio-live i { width: 6px; height: 6px; @@ -322,22 +393,27 @@ code { box-shadow: 0 0 8px var(--accent-glow); animation: pulse 1.8s ease-in-out infinite; } + #hero-canvas { display: block; width: 100%; - aspect-ratio: 4 / 3.2; + aspect-ratio: 4 / 3.15; } + .studio-hud { position: absolute; - left: 16px; bottom: 14px; + left: 16px; pointer-events: none; } + .studio-hud span { + color: var(--text); + font-size: 14px; font-weight: 800; - font-size: 15px; - text-shadow: 0 1px 12px rgba(0, 0, 0, 0.7); + text-shadow: 0 1px 12px rgba(0, 0, 0, 0.75); } + .studio-hud span::before { content: ""; display: inline-block; @@ -352,22 +428,29 @@ code { .code-chip { position: absolute; - right: -18px; - bottom: -22px; + right: -24px; + bottom: -34px; + z-index: 2; margin: 0; - padding: 14px 16px; - font-family: var(--mono); - font-size: 11.5px; - line-height: 1.7; - color: var(--text-2); - background: rgba(15, 20, 27, 0.92); + padding: 13px 16px 15px; border: 1px solid var(--border-2); - border-radius: 10px; - box-shadow: var(--shadow-2); - backdrop-filter: blur(8px); - -webkit-backdrop-filter: blur(8px); + border-radius: var(--radius-sm); + background: rgba(15, 20, 27, 0.95); + color: var(--text-2); + font-family: var(--mono); + font-size: 10.5px; + line-height: 1.65; + box-shadow: var(--edge), var(--shadow-float); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); +} + +.code-label { + display: block; + margin-bottom: 6px; } -.t-kw { color: var(--t-kw); font-weight: 600; } + +.t-kw { color: var(--t-kw); font-weight: 700; } .t-kind { color: var(--t-kind); } .t-act { color: var(--t-act); } .t-joint { color: var(--t-joint); } @@ -376,511 +459,625 @@ code { .t-str { color: var(--t-str); } .t-punct { color: var(--t-punct); } -/* --- Value props ----------------------------------------------------------- */ -.props { +/* Three terse proof points replace long feature cards. */ +.proof { display: grid; grid-template-columns: repeat(3, 1fr); - gap: 20px; - padding-top: clamp(40px, 6vw, 72px); - padding-bottom: clamp(40px, 6vw, 72px); + padding-top: 0; + padding-bottom: 0; + border-top: 1px solid var(--border); + border-bottom: 1px solid var(--border); } -.prop { - border: 1px solid var(--border); - border-radius: var(--radius); - padding: 26px 24px; - background: linear-gradient(180deg, var(--panel), rgba(15, 20, 27, 0.4)); - transition: border-color 0.2s var(--ease), transform 0.2s var(--ease); + +.proof-item { + display: flex; + align-items: flex-start; + gap: 16px; + min-width: 0; + padding: 25px 28px; + border-right: 1px solid var(--border); } -.prop:hover { - border-color: var(--border-2); - transform: translateY(-3px); + +.proof-item:last-child { + border-right: 0; } -.prop-mark { - font-size: 22px; + +.proof-n, +.how-n { color: var(--accent); - width: 44px; - height: 44px; - display: grid; - place-items: center; - border-radius: 11px; - background: var(--accent-faint); - border: 1px solid var(--accent-veil); - margin-bottom: 16px; -} -.prop h3 { - font-size: 18px; + font-family: var(--mono); + font-size: 10px; font-weight: 700; - margin: 0 0 8px; - letter-spacing: -0.3px; + letter-spacing: 1px; } -.prop p { - font-size: 14.5px; + +.proof-item strong { + display: block; + margin-bottom: 2px; + font-size: 15px; + letter-spacing: -0.1px; +} + +.proof-item p { + margin: 0; color: var(--text-2); + font-size: 13.5px; +} + +.how, +.examples, +.developers { + padding-top: clamp(92px, 11vw, 144px); +} + +.section-head { + max-width: 680px; + margin: 0 0 42px; +} + +.section-head h2, +.final-cta h2 { margin: 0; + font-size: clamp(36px, 4.8vw, 60px); + font-weight: 850; + letter-spacing: -0.045em; + line-height: 1.02; } -/* --- Examples -------------------------------------------------------------- */ -.examples { - padding-top: clamp(48px, 7vw, 88px); - padding-bottom: clamp(48px, 7vw, 88px); +.section-sub { + max-width: 54ch; + margin: 15px 0 0; + color: var(--text-2); + font-size: 16px; } -.examples-grid { + +/* A single connected workflow is faster to scan than three explanation cards. */ +.how-steps { + position: relative; display: grid; grid-template-columns: repeat(3, 1fr); - gap: 16px; -} -.example-card { - display: flex; - flex-direction: column; - gap: 6px; - padding: 22px 22px 20px; + margin: 0; + padding: 0; + list-style: none; border: 1px solid var(--border); border-radius: var(--radius); - background: var(--panel); - cursor: pointer; - transition: border-color 0.18s var(--ease), transform 0.18s var(--ease), - box-shadow 0.18s var(--ease), background 0.18s var(--ease); + background: linear-gradient(180deg, rgba(20, 26, 35, 0.72), rgba(15, 20, 27, 0.42)); + box-shadow: var(--edge); } -.example-card:hover { - border-color: var(--accent); - transform: translateY(-3px); - background: var(--panel-2); - box-shadow: 0 14px 30px -18px var(--accent-glow); + +.how-steps li { + position: relative; + min-height: 168px; + padding: 27px 28px 30px; + border-right: 1px solid var(--border); } -.example-kind { - font-family: var(--mono); - font-size: 11px; - letter-spacing: 1px; - text-transform: uppercase; - color: var(--muted); -} -.example-name { - font-size: 19px; - font-weight: 700; - letter-spacing: -0.3px; -} -.example-go { - margin-top: 10px; - font-size: 13px; - font-weight: 700; - color: var(--accent); + +.how-steps li:last-child { + border-right: 0; } -.example-more { - border-style: dashed; - border-color: var(--border-2); - background: transparent; - justify-content: center; + +.how-steps h3 { + margin: 23px 0 7px; + font-size: 20px; + letter-spacing: -0.35px; } -.example-more .example-name { - color: var(--accent); + +.how-steps p { + max-width: 28ch; + margin: 0; + color: var(--text-2); + font-size: 14.5px; } -.example-more:hover { - border-style: solid; + +.how-steps li:not(:last-child)::after { + content: "→"; + position: absolute; + top: 30px; + right: -11px; + z-index: 2; + display: grid; + width: 20px; + height: 20px; + place-items: center; + border: 1px solid var(--border-2); + border-radius: 50%; background: var(--panel); + color: var(--muted); + font-family: var(--mono); + font-size: 10px; } -/* --- How it works ---------------------------------------------------------- */ -.how { - padding-top: clamp(48px, 7vw, 88px); - padding-bottom: clamp(48px, 7vw, 88px); -} -.how-steps { - list-style: none; - margin: 0; - padding: 0; +.examples-grid { display: grid; grid-template-columns: repeat(3, 1fr); - gap: 22px; - counter-reset: step; + gap: 12px; } -.how-steps li { + +.example-card { position: relative; - padding: 28px 24px; + display: flex; + min-height: 154px; + flex-direction: column; + gap: 6px; + padding: 21px 21px 19px; + overflow: hidden; border: 1px solid var(--border); border-radius: var(--radius); - background: linear-gradient(180deg, var(--panel), transparent); + background: rgba(15, 20, 27, 0.72); + box-shadow: var(--edge); + transition: + transform 180ms var(--ease-out), + border-color 180ms var(--ease-out), + background 180ms var(--ease-out), + box-shadow 180ms var(--ease-out); } -.how-n { - display: grid; - place-items: center; - width: 32px; - height: 32px; - border-radius: 9px; + +.example-card::after { + content: ""; + position: absolute; + top: 0; + right: 0; + width: 58px; + height: 58px; + background: radial-gradient(circle at 100% 0%, var(--accent-faint), transparent 68%); + pointer-events: none; +} + +.example-kind, +.dev-kind { + color: var(--muted); font-family: var(--mono); + font-size: 9.5px; font-weight: 700; - color: var(--accent-ink); - background: linear-gradient(180deg, var(--accent), var(--accent-2)); - margin-bottom: 16px; + letter-spacing: 1.15px; + text-transform: uppercase; } -.how-steps h3 { - font-size: 17px; - font-weight: 700; - margin: 0 0 8px; + +.example-name { + font-size: 18px; + font-weight: 750; letter-spacing: -0.3px; } -.how-steps p { - font-size: 14.5px; - color: var(--text-2); - margin: 0; + +.example-go { + margin-top: auto; + color: var(--accent); + font-size: 12px; + font-weight: 700; } -/* --- Developers ------------------------------------------------------------ */ -.developers { - padding-top: clamp(48px, 7vw, 88px); - padding-bottom: clamp(48px, 7vw, 88px); +.example-more { + border-style: dashed; + background: transparent; } + +.example-more .example-name { + color: var(--accent); +} + .dev-grid { display: grid; grid-template-columns: repeat(4, 1fr); - gap: 16px; + border-top: 1px solid var(--border); + border-left: 1px solid var(--border); } + .dev-card { display: block; - padding: 22px 20px; - border: 1px solid var(--border); - border-radius: var(--radius); - background: var(--panel); - transition: border-color 0.18s var(--ease), transform 0.18s var(--ease); -} -.dev-card:hover { - border-color: var(--border-2); - transform: translateY(-3px); -} -a.dev-card:hover { - border-color: var(--accent); + min-height: 156px; + padding: 22px 21px; + border-right: 1px solid var(--border); + border-bottom: 1px solid var(--border); + background: rgba(15, 20, 27, 0.28); + transition: + background 180ms var(--ease-out), + color 180ms var(--ease-out); } + .dev-card h3 { - font-size: 16px; - font-weight: 700; - margin: 0 0 8px; - letter-spacing: -0.2px; -} -.dev-card p { - font-size: 13.5px; - color: var(--text-2); - margin: 0; + margin: 24px 0 5px; + font-size: 17px; + letter-spacing: -0.25px; } -.dev-code { - display: inline-block; - margin-top: 12px; - font-size: 12px; + +.dev-card h3 span { color: var(--accent); - background: var(--accent-faint); - border-color: var(--accent-veil); } -/* --- FAQ -------------------------------------------------------------------- */ -.faq { - padding-top: clamp(48px, 7vw, 88px); - padding-bottom: clamp(48px, 7vw, 88px); -} -.faq-list { - max-width: 760px; - margin: 0 auto; - display: flex; - flex-direction: column; - gap: 14px; +.dev-card p { + margin: 0; + color: var(--text-2); + font-size: 13.5px; } -.faq-item { - padding: 22px 24px; - border: 1px solid var(--border); + +.final-cta { + margin-top: clamp(100px, 13vw, 168px); + padding-top: clamp(54px, 7vw, 80px); + padding-bottom: clamp(58px, 7vw, 84px); + border: 1px solid var(--border-2); border-radius: var(--radius); - background: linear-gradient(180deg, var(--panel), transparent); + background: + radial-gradient(70% 170% at 95% 10%, rgba(198, 242, 74, 0.1), transparent 66%), + linear-gradient(180deg, rgba(20, 26, 35, 0.92), rgba(15, 20, 27, 0.72)); + box-shadow: var(--edge), var(--shadow-float); } -.faq-item dt { - font-size: 16px; - font-weight: 700; - letter-spacing: -0.2px; - margin: 0 0 8px; + +.final-cta h2 { + max-width: 12ch; } -.faq-item dd { - margin: 0; - font-size: 14.5px; - line-height: 1.6; + +.final-cta > p:not(.eyebrow) { + margin: 15px 0 26px; color: var(--text-2); -} -.faq-item em { - color: var(--accent); - font-style: normal; - font-weight: 600; + font-size: 17px; } -/* --- Footer ---------------------------------------------------------------- */ .footer { + margin-top: 74px; + padding-top: 34px; + padding-bottom: 42px; border-top: 1px solid var(--border); - margin-top: 40px; - padding-top: 40px; - padding-bottom: 56px; +} + +.footer-top { display: flex; - flex-direction: column; - gap: 12px; + align-items: center; + justify-content: space-between; + gap: 28px; } + .footer-brand { + display: flex; + align-items: center; + gap: 8px; + font-size: 16px; font-weight: 800; - font-size: 17px; } -.footer-brand .logo { - color: var(--accent); -} -.footer-tag { - font-family: var(--mono); - font-size: 11px; + +.footer-brand small { + margin-left: 4px; color: var(--muted); - letter-spacing: 0.5px; - margin-left: 8px; + font-family: var(--mono); + font-size: 10px; + font-weight: 500; + letter-spacing: 0.3px; } -.footer-note { + +.footer-links { + display: flex; + flex-wrap: wrap; + justify-content: flex-end; + gap: 18px; + color: var(--text-2); font-size: 13px; - color: var(--muted); - max-width: 70ch; - margin: 0; -} -.footer-legal { - font-family: var(--mono); - font-size: 12px; - color: var(--muted); - margin: 0; + font-weight: 600; } -.footer-legal a { + +.footer-note { + margin: 16px 0 0; color: var(--muted); - text-decoration: underline; - text-decoration-color: var(--border-2); - text-underline-offset: 2px; -} -.footer-legal a:hover { - color: var(--accent); - text-decoration-color: var(--accent); + font-family: var(--mono); + font-size: 10.5px; } -/* --- Motion ---------------------------------------------------------------- */ @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } } + +/* Marketing entrances explain hierarchy once; frequently used tool actions + remain unanimated in the playground. */ .reveal { opacity: 0; - transform: translateY(18px); - transition: opacity 0.6s var(--ease), transform 0.6s var(--ease); + transform: translateY(14px); + transition: + opacity 520ms var(--ease-out), + transform 520ms var(--ease-out); } + .reveal.in { opacity: 1; transform: none; } -.hero-copy.reveal { transition-delay: 0.05s; } -.hero-stage.reveal { transition-delay: 0.16s; } -.props .prop:nth-child(2) { transition-delay: 0.08s; } -.props .prop:nth-child(3) { transition-delay: 0.16s; } -@media (prefers-reduced-motion: reduce) { - html { scroll-behavior: auto; } - .reveal { opacity: 1; transform: none; transition: none; } +.hero-stage.reveal { + transition-delay: 80ms; +} + +.proof-item:nth-child(2), +.how-steps li:nth-child(2), +.dev-card:nth-child(2) { + transition-delay: 45ms; +} + +.proof-item:nth-child(3), +.how-steps li:nth-child(3), +.dev-card:nth-child(3) { + transition-delay: 90ms; +} + +.dev-card:nth-child(4) { + transition-delay: 135ms; +} + +@media (hover: hover) and (pointer: fine) { + .btn:hover { + border-color: var(--accent); + background: var(--panel-3); + color: #fff; + box-shadow: var(--edge), 0 8px 22px -14px var(--accent-glow); + transform: translateY(-1px); + } + + .btn.primary:hover { + border-color: transparent; + background: linear-gradient(180deg, #d0fa58, var(--accent)); + color: var(--accent-ink); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3), 0 12px 28px -11px var(--accent-glow); + } + + .nav-links a:hover, + .footer-links a:hover { + color: var(--text); + } + + .example-card:hover { + transform: translateY(-3px); + border-color: var(--accent); + background: var(--panel-2); + box-shadow: var(--edge), 0 16px 32px -22px var(--accent-glow); + } + + .dev-card:hover { + background: var(--panel-2); + } } -/* --- Responsive ------------------------------------------------------------ */ -@media (max-width: 920px) { +@media (max-width: 980px) { .hero { grid-template-columns: 1fr; - gap: 40px; + gap: 58px; + min-height: auto; } - .props, - .examples-grid, - .how-steps { - grid-template-columns: 1fr 1fr; + + .hero-copy { + max-width: 650px; } - .dev-grid { - grid-template-columns: 1fr 1fr; + + .headline { + max-width: 11ch; } - .code-chip { - right: 8px; - bottom: -16px; - font-size: 10.5px; + + .hero-stage { + width: min(100%, 680px); + margin-inline: auto; + } + + .proof { + padding-inline: 28px; + } + + .proof-item { + padding-inline: 20px; + } + + .dev-grid { + grid-template-columns: repeat(2, 1fr); } } -@media (max-width: 620px) { + +@media (max-width: 760px) { .nav-links { display: none; } - .props, - .examples-grid, + + .nav-cta { + margin-left: auto; + } + + .proof, .how-steps, - .dev-grid { + .examples-grid { grid-template-columns: 1fr; } - .code-chip { - display: none; + + .proof { + border-right: 1px solid var(--border); + border-left: 1px solid var(--border); } - .hero { - padding-top: 40px; + + .proof-item, + .proof-item:last-child { + border-right: 0; + border-bottom: 1px solid var(--border); } -} -/* 2026 editorial refresh: let the motion carry the spectacle. Flat surfaces, - strong rules, and restrained color replace generic glowing SaaS cards. */ -:root { - --bg: #0b0c0d; - --bg-viewer: #101214; - --panel: #111315; - --panel-2: #171a1d; - --panel-3: #1c2023; - --border: #292d30; - --border-2: #3a3f43; - --text: #f2f1eb; - --text-2: #aaa9a2; - --muted: #74746f; - --accent: #d4ff3f; - --accent-2: #d4ff3f; - --radius: 4px; - --radius-sm: 3px; - --shadow-2: 0 18px 50px rgba(0, 0, 0, 0.34); -} -.bg-fx { background: var(--bg); } -.bg-fx::after { opacity: .018; } -.nav { - max-width: none; - padding: 18px max(24px, calc((100vw - var(--container)) / 2 + 28px)); - border-bottom: 1px solid var(--border); - background: rgba(11, 12, 13, .94); - backdrop-filter: blur(18px); -} -.brand .logo { filter: none; } -.nav-links { margin-left: auto; } -.nav-links a { color: var(--text-2); } -.btn { box-shadow: none; border-radius: 3px; } -.btn:hover { box-shadow: none; transform: translateY(-1px); } -.btn.primary, -.btn.primary:hover { - background: var(--accent); - box-shadow: none; - filter: none; -} -.hero { - grid-template-columns: minmax(0, .9fr) minmax(480px, 1.1fr); - min-height: min(780px, calc(100vh - 68px)); - gap: clamp(42px, 6vw, 92px); - padding-top: clamp(54px, 8vh, 100px); - padding-bottom: clamp(70px, 10vh, 120px); -} -.eyebrow { color: var(--text-2); letter-spacing: 2.4px; } -.headline { - max-width: 11ch; - font-size: clamp(52px, 5.8vw, 82px); - line-height: .92; - letter-spacing: -.055em; -} -.headline .hl { color: var(--text); white-space: normal; } -.headline .hl::after { display: none; } -.subhead { font-size: clamp(17px, 1.5vw, 20px); line-height: 1.55; } -.hero-meta { border-top: 1px solid var(--border); padding-top: 18px; } -.studio { border-radius: 3px; box-shadow: var(--shadow-2); } -.studio-bar { background: #0d0f10; } -.studio-bar .dots { display: none; } -.code-chip { - position: absolute; - z-index: 2; - top: 44px; - right: -28px; - bottom: auto; - width: max-content; - max-width: calc(100% - 48px); - box-sizing: border-box; - margin: 0; - overflow: hidden; - pointer-events: none; - padding: 12px 14px; - font-size: 10.5px; - line-height: 1.6; - border-radius: 2px; - background: #0b0d0e; - backdrop-filter: none; -} -.props { - gap: 0; - border-top: 1px solid var(--border); - border-bottom: 1px solid var(--border); - padding-top: 0; - padding-bottom: 0; -} -.prop { - border: 0; - border-right: 1px solid var(--border); - border-radius: 0; - padding: 38px 30px 42px; - background: transparent; + .proof-item:last-child { + border-bottom: 0; + } + + .how-steps li, + .how-steps li:last-child { + min-height: auto; + border-right: 0; + border-bottom: 1px solid var(--border); + } + + .how-steps li:last-child { + border-bottom: 0; + } + + .how-steps li:not(:last-child)::after { + top: auto; + right: 28px; + bottom: -11px; + content: "↓"; + } + + .footer-top { + align-items: flex-start; + flex-direction: column; + } + + .footer-links { + justify-content: flex-start; + } } -.prop:first-child { border-left: 1px solid var(--border); } -.prop:hover { border-color: var(--border); transform: none; background: #0e1011; } -.prop-mark { - width: auto; - height: auto; - display: block; - border: 0; - border-radius: 0; - background: transparent; - font-family: var(--mono); - font-size: 14px; + +@media (max-width: 560px) { + .hero, + .proof, + .how, + .examples, + .developers, + .footer { + padding-inline: 18px; + } + + .nav { + min-height: 62px; + padding: 10px 16px; + } + + .brand { + font-size: 17px; + } + + .nav-cta { + padding: 9px 12px; + } + + .hero { + gap: 44px; + padding-top: 54px; + padding-bottom: 76px; + } + + .headline { + font-size: clamp(47px, 14vw, 66px); + } + + .subhead { + font-size: 17px; + } + + .hero-cta { + display: grid; + width: 100%; + } + + .hero-cta .btn { + width: 100%; + } + + .hero-stage { + padding-top: 0; + } + + .prompt-card { + position: relative; + top: auto; + left: auto; + width: calc(100% - 24px); + margin: 0 auto -8px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; + } + + .studio { + margin-inline: -18px; + border-right: 0; + border-left: 0; + border-radius: 0; + } + + .studio-kicker { + display: none; + } + + .code-chip { + right: -4px; + bottom: -26px; + font-size: 9.5px; + } + + .proof { + padding-inline: 0; + } + + .how, + .examples, + .developers { + padding-top: 92px; + } + + .section-head { + margin-bottom: 32px; + } + + .section-head h2, + .final-cta h2 { + font-size: clamp(36px, 11vw, 48px); + } + + .dev-grid { + grid-template-columns: 1fr; + } + + .dev-card { + min-height: 132px; + } + + .final-cta { + width: calc(100% - 36px); + margin-top: 110px; + padding: 44px 22px 48px; + } + + .footer-brand { + flex-wrap: wrap; + } + + .footer-brand small { + width: 100%; + margin-left: 27px; + } } -.section-head { text-align: left; margin-left: 0; } -.section-head h2 { font-size: clamp(34px, 4.5vw, 56px); letter-spacing: -.04em; } -.examples-grid { gap: 0; border-top: 1px solid var(--border); } -.example-card { - min-height: 154px; - border: 0; - border-right: 1px solid var(--border); - border-bottom: 1px solid var(--border); - border-radius: 0; - background: transparent; - justify-content: space-between; + +@media (prefers-reduced-motion: reduce) { + html { + scroll-behavior: auto; + } + + .reveal { + opacity: 1; + transform: none; + transition: opacity 180ms var(--ease-out); + } + + .studio-live i { + animation: none; + } } -.example-card:nth-child(3n + 1) { border-left: 1px solid var(--border); } -.example-card:hover { transform: none; background: var(--text); color: var(--bg); box-shadow: none; border-color: var(--border); } -.example-card:hover .example-kind { color: #555; } -.example-card:hover .example-go { color: #1e2410; } -.how-steps { gap: 0; border-top: 1px solid var(--border); } -.how-steps li { - border: 0; - border-right: 1px solid var(--border); - border-bottom: 1px solid var(--border); - border-radius: 0; - background: transparent; - padding: 32px; -} -.how-steps li:first-child { border-left: 1px solid var(--border); } -.how-n { background: transparent; color: var(--accent); place-items: start; } -.dev-grid { gap: 0; border-top: 1px solid var(--border); border-left: 1px solid var(--border); } -.dev-card { border: 0; border-right: 1px solid var(--border); border-bottom: 1px solid var(--border); border-radius: 0; background: transparent; } -.dev-card:hover, a.dev-card:hover { transform: none; background: #0e1011; border-color: var(--border); } -.faq-list { border-top: 1px solid var(--border); } -.faq-item { border: 0; border-bottom: 1px solid var(--border); border-radius: 0; background: transparent; padding: 24px 0; } - -@media (max-width: 920px) { - .hero { grid-template-columns: 1fr; min-height: auto; } - .headline { max-width: 12ch; } + +@media (prefers-reduced-transparency: reduce) { + .nav, + .prompt-card, .code-chip { - position: static; - width: max-content; - max-width: 100%; - margin: 14px 0 0 auto; - overflow-x: auto; - pointer-events: auto; - } - .prop:nth-child(2) { border-left: 1px solid var(--border); } - .example-card:nth-child(3n + 1) { border-left: 0; } - .example-card:nth-child(2n + 1) { border-left: 1px solid var(--border); } -} -@media (max-width: 620px) { - .nav { padding: 14px 18px; } - .nav-cta { padding: 9px 12px; } - .hero, .props, .examples, .how, .developers, .faq, .footer { padding-left: 18px; padding-right: 18px; } - .hero { gap: 34px; padding-top: 48px; padding-bottom: 64px; } - .headline { font-size: clamp(46px, 14vw, 62px); } - .headline .hl { white-space: normal; } - .subhead { font-size: 17px; } - .hero-cta { display: grid; } - .hero-cta .btn { width: 100%; } - .studio { margin-left: -18px; margin-right: -18px; border-left: 0; border-right: 0; } - .hero-stage { min-width: 0; } - .studio-bar { padding-left: 18px; } - .props { border: 0; } - .prop, .prop:first-child, .prop:nth-child(2) { border-left: 0; border-right: 0; border-top: 1px solid var(--border); padding-left: 0; padding-right: 0; } - .example-card, .example-card:nth-child(2n + 1), .how-steps li, .how-steps li:first-child { border-left: 0; border-right: 0; } + background: var(--panel); + backdrop-filter: none; + -webkit-backdrop-filter: none; + } +} + +@media (prefers-contrast: more) { + .nav, + .prompt-card, + .studio, + .code-chip, + .how-steps, + .example-card, + .final-cta { + border-color: var(--text-2); + } } diff --git a/playground/src/landing.ts b/playground/src/landing.ts index 549628a..9cfe560 100644 --- a/playground/src/landing.ts +++ b/playground/src/landing.ts @@ -104,18 +104,51 @@ if (grid) { } // --- Copy the LLM authoring prompt ------------------------------------------ -const copyBtn = document.getElementById("copy-prompt") as HTMLButtonElement | null; -if (copyBtn) { +async function writeClipboard(text: string): Promise { + if (navigator.clipboard?.writeText) { + try { + // Clipboard permissions can remain pending in embedded browsers. Keep + // the button responsive and fall back to the classic selection path. + await Promise.race([ + navigator.clipboard.writeText(text), + new Promise((_, reject) => + window.setTimeout(() => reject(new Error("clipboard timeout")), 800), + ), + ]); + return; + } catch { + // Continue to the local fallback below. + } + } + + const textarea = document.createElement("textarea"); + textarea.value = text; + textarea.setAttribute("readonly", ""); + textarea.style.position = "fixed"; + textarea.style.opacity = "0"; + document.body.append(textarea); + textarea.select(); + const copied = document.execCommand("copy"); + textarea.remove(); + if (!copied) throw new Error("clipboard unavailable"); +} + +for (const copyBtn of document.querySelectorAll("[data-copy-prompt]")) { const lbl = copyBtn.querySelector(".lbl") ?? copyBtn; copyBtn.addEventListener("click", async () => { const prev = lbl.textContent; + copyBtn.disabled = true; + lbl.textContent = "Copying…"; try { - await navigator.clipboard.writeText(llmPrompt); + await writeClipboard(llmPrompt); lbl.textContent = "Copied ✓"; } catch { lbl.textContent = "Copy failed"; } - window.setTimeout(() => (lbl.textContent = prev), 1500); + window.setTimeout(() => { + lbl.textContent = prev; + copyBtn.disabled = false; + }, 1500); }); } From 89e45530d6eca4cc8fdd6ebc96612dc87179539c Mon Sep 17 00:00:00 2001 From: a-baran-orhan Date: Fri, 17 Jul 2026 23:52:43 +0300 Subject: [PATCH 2/2] Improve mobile hero clarity --- playground/index.html | 9 +++++---- playground/src/landing.css | 4 +--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/playground/index.html b/playground/index.html index d95b83e..2275fa0 100644 --- a/playground/index.html +++ b/playground/index.html @@ -147,7 +147,8 @@

A motion language for LLMs

Give your LLM
a body.

- Posecode turns LLM-written text into structured, editable 3D human motion, live in your browser. + Give your LLM the Posecode prompt. Posecode turns its response into structured, editable 3D human + motion in your browser.

Open the playground → @@ -158,14 +159,14 @@

Give your LLM
a body.

Open source Runs on-device - LLM-ready + Prompt included
- Prompt to a capable LLM -

“Write a controlled superhero landing.”

+ After pasting the Posecode prompt +

Then ask: “Write a controlled superhero landing.”

diff --git a/playground/src/landing.css b/playground/src/landing.css index b126503..a38c386 100644 --- a/playground/src/landing.css +++ b/playground/src/landing.css @@ -996,9 +996,7 @@ code { } .code-chip { - right: -4px; - bottom: -26px; - font-size: 9.5px; + display: none; } .proof {