From 908e8a439521471f895affa9db03acf8033873b6 Mon Sep 17 00:00:00 2001
From: a-baran-orhan
Date: Thu, 16 Jul 2026 16:56:17 +0300
Subject: [PATCH 1/2] Add product integration page
---
playground/for-products.html | 162 +++++++++++
playground/index.html | 3 +-
playground/public/sitemap.xml | 6 +
playground/src/for-products.css | 387 +++++++++++++++++++++++++++
playground/src/for-products.ts | 21 ++
playground/test/for-products.test.ts | 38 +++
playground/vite.config.ts | 4 +-
vercel.json | 6 +-
vitest.config.ts | 2 +-
9 files changed, 624 insertions(+), 5 deletions(-)
create mode 100644 playground/for-products.html
create mode 100644 playground/src/for-products.css
create mode 100644 playground/src/for-products.ts
create mode 100644 playground/test/for-products.test.ts
diff --git a/playground/for-products.html b/playground/for-products.html
new file mode 100644
index 0000000..205cf03
--- /dev/null
+++ b/playground/for-products.html
@@ -0,0 +1,162 @@
+
+
+
+
+
+ Use Posecode in Your Product | Open-Source Motion Tools
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
For product owners & developers
+
Put movement inside your product.
+
Posecode turns a small, readable text document into an editable 3D movement. Use the open-source pieces now—or help shape the product infrastructure that should come next.
+
+
+
+ The honest version
+ Open-source toolkit today. No hosted commercial platform yet.
+ You can ship the web component and TypeScript packages in your own product now. Hosted APIs, cloud rendering, private libraries, and enterprise operations are ideas we would explore with design partners—not services you can buy today.
+
+
+
+
+
+
+
+ 01 / embed
+ Drop in a movement player
+ Use the framework-free <posecode-player> web component with inline Posecode, a .posecode URL, or a share token.
+ <script src="https://unpkg.com/posecode-embed@0.2.2/dist/posecode-embed.js"></script>
+<posecode-player src="/moves/squat.posecode"></posecode-player>
+
+
+ 02 / compose
+ Own the interface
+ Parse text into a typed, range-of-motion-clamped IR, then drive the Three.js renderer inside your own editor, lesson, or workflow.
+ npm install posecode-parser posecode-render three
+
+
+ 03 / agents
+ Run movement tools locally
+ The npm MCP server runs over stdio on your machine. It teaches an MCP client the language, validates documents, and creates playground links.
+ npx -y posecode-mcp@latest
+
+
+
+
+
+
+ Where it fits
+ Movement that stays inspectable.
+
+
+
Animation editors Generate a first pass from text, expose timing and joint values, and let a human revise the movement instead of accepting a black-box clip.
+
Fitness & rehab products Show an exercise beside a program or cue. Joint angles are clamped to general range-of-motion limits, but Posecode is not clinical advice or patient-specific validation.
+
Education tools Connect written instruction to a moving figure for anatomy, dance, physical education, or movement vocabulary.
+
Movement libraries Store small, diffable text files, validate them in CI, and open any movement in the browser without pre-rendering video.
+
Agent workflows Let an MCP-capable local agent write, validate, repair, and return a link to movement the user can inspect.
+
Other web products Use movement as editable content anywhere a video or static diagram is too rigid and a full animation pipeline is too heavy.
+
+
+
+
+
+ Available today
+ The current open-source surface.
+ These pieces are in the public repository and licensed Apache-2.0. You run them in your browser, build, or local environment.
+
+
+
posecode-embedA web component with lazy loading, controls, reduced-motion behavior, events, and inline, URL, or share-token inputs.
browser
+
posecode-parserA TypeScript parser and CLI that produce typed movement data, diagnostics, and range-of-motion clamps.
npm + CLI
+
posecode-renderA Three.js client-side renderer for a procedural figure or a compatible Mixamo-rigged GLB.
npm
+
posecode-shareA dependency-free codec for URL-safe documents and playground permalinks. The document lives in the URL; this is not private cloud storage.
npm
+
Share links The public playground opens encoded movements for viewing and editing in the browser.
posecode.org
+
posecode-mcpA local stdio MCP server for authoring guidance, validation, and render links. It does not render in the cloud.
local npm process
+
+ Operational boundary: there is currently no hosted product API, hosted MCP endpoint, account system, private content store, uptime commitment, or commercial support plan.
+
+
+
+
+
Exploring next
+
Useful infrastructure should be shaped by real products.
+
We are interested in working with a small number of design partners to learn which operational layer actually matters. Possibilities—not announced products—include:
+
+
+ Hosted generation or validation API
+ Hosted MCP access
+ Cloud rendering and asset exports
+ Custom characters and rigs
+ Private movement libraries
+ White-label embeds
+ Usage analytics
+ Support, security review, and SLAs
+
+ None of these capabilities is generally available today. There is no published commercial pricing. A design-partner conversation is for scoping the problem, constraints, and a possible collaboration—not selling a service that already exists.
+
+
+
+ Bring a concrete problem
+ What movement does your product need to explain?
+ Tell us what you are building, where the animation would appear, and whether the open-source pieces cover the first version. We will reply from there.
+ Email hello@posecode.org →
+
+
+
+
+
+
+
+
diff --git a/playground/index.html b/playground/index.html
index 81d6f00..6b8db42 100644
--- a/playground/index.html
+++ b/playground/index.html
@@ -137,7 +137,7 @@
Examples
Movement library
Developers
- Feedback
+ For products
GitHub
Open playground →
@@ -341,6 +341,7 @@ Common questions
Movement library ·
Language spec ·
LLM guide ·
+ For products ·
Feedback ·
Issues
diff --git a/playground/public/sitemap.xml b/playground/public/sitemap.xml
index db7d86b..e1e201e 100644
--- a/playground/public/sitemap.xml
+++ b/playground/public/sitemap.xml
@@ -12,6 +12,12 @@
weekly
0.9
+
+ https://www.posecode.org/for-products
+ 2026-07-16
+ monthly
+ 0.8
+
https://www.posecode.org/moves/
2026-07-16
diff --git a/playground/src/for-products.css b/playground/src/for-products.css
new file mode 100644
index 0000000..2b3ff25
--- /dev/null
+++ b/playground/src/for-products.css
@@ -0,0 +1,387 @@
+.product-page main {
+ overflow: hidden;
+}
+
+.product-page a:focus-visible {
+ outline: 3px solid var(--accent);
+ outline-offset: 4px;
+}
+
+.product-hero,
+.product-section,
+.product-cta {
+ max-width: var(--container);
+ margin: 0 auto;
+ padding-left: 28px;
+ padding-right: 28px;
+}
+
+.product-hero {
+ min-height: min(720px, calc(100vh - 69px));
+ display: grid;
+ grid-template-columns: minmax(0, 1.08fr) minmax(360px, .72fr);
+ align-items: center;
+ gap: clamp(48px, 8vw, 112px);
+ padding-top: clamp(70px, 10vh, 116px);
+ padding-bottom: clamp(80px, 12vh, 140px);
+}
+
+.product-hero h1 {
+ max-width: 11ch;
+ margin: 0 0 28px;
+ font-size: clamp(58px, 7.3vw, 102px);
+ font-weight: 900;
+ line-height: .88;
+ letter-spacing: -.065em;
+}
+
+.product-lede {
+ max-width: 58ch;
+ margin: 0 0 32px;
+ color: var(--text-2);
+ font-size: clamp(18px, 1.7vw, 22px);
+ line-height: 1.5;
+}
+
+.reality-card {
+ border-top: 2px solid var(--accent);
+ border-bottom: 1px solid var(--border);
+ padding: 28px 0 32px;
+}
+
+.status-label {
+ display: flex;
+ align-items: center;
+ gap: 9px;
+ margin: 0 0 30px;
+ color: var(--accent);
+ font-family: var(--mono);
+ font-size: 11px;
+ font-weight: 600;
+ letter-spacing: .12em;
+ text-transform: uppercase;
+}
+
+.status-label span {
+ width: 7px;
+ height: 7px;
+ background: var(--accent);
+ border-radius: 50%;
+}
+
+.reality-card h2 {
+ margin: 0 0 18px;
+ font-size: clamp(25px, 3vw, 35px);
+ line-height: 1.08;
+ letter-spacing: -.035em;
+}
+
+.reality-card > p:last-child,
+.product-section-head > p:last-child,
+.exploring-copy > p:last-child {
+ color: var(--text-2);
+}
+
+.product-section {
+ padding-top: clamp(80px, 10vw, 140px);
+ padding-bottom: clamp(80px, 10vw, 140px);
+}
+
+.product-section-head {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) minmax(280px, .7fr);
+ column-gap: 60px;
+ align-items: end;
+ margin-bottom: 52px;
+}
+
+.product-section-head .eyebrow {
+ grid-column: 1 / -1;
+}
+
+.product-section-head h2,
+.exploring-copy h2,
+.product-cta h2 {
+ margin: 0;
+ max-width: 13ch;
+ font-size: clamp(40px, 5.4vw, 68px);
+ line-height: .98;
+ letter-spacing: -.05em;
+}
+
+.product-section-head > p:last-child {
+ margin: 0;
+ font-size: 17px;
+}
+
+.integration-grid {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ border-top: 1px solid var(--border);
+ border-left: 1px solid var(--border);
+}
+
+.integration-card {
+ min-width: 0;
+ display: flex;
+ flex-direction: column;
+ min-height: 400px;
+ padding: 30px;
+ border-right: 1px solid var(--border);
+ border-bottom: 1px solid var(--border);
+}
+
+.card-index,
+.capability-row > span {
+ font-family: var(--mono);
+ color: var(--accent);
+ font-size: 11px;
+ letter-spacing: .11em;
+ text-transform: uppercase;
+}
+
+.integration-card h3,
+.use-case h3 {
+ margin: 48px 0 12px;
+ font-size: 23px;
+ line-height: 1.1;
+ letter-spacing: -.025em;
+}
+
+.integration-card p,
+.use-case p {
+ margin: 0;
+ color: var(--text-2);
+}
+
+.integration-card pre {
+ max-width: 100%;
+ overflow-x: auto;
+ margin: auto 0 0;
+ padding: 17px;
+ border: 1px solid var(--border);
+ background: #080a0b;
+ color: var(--text);
+ font: 11px/1.7 var(--mono);
+ white-space: pre-wrap;
+ overflow-wrap: anywhere;
+}
+
+.integration-card pre code {
+ padding: 0;
+ border: 0;
+ background: none;
+ font: inherit;
+}
+
+.use-cases {
+ border-top: 1px solid var(--border);
+}
+
+.use-case-grid {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ border-top: 1px solid var(--border);
+}
+
+.use-case {
+ min-height: 230px;
+ padding: 28px 26px 32px 0;
+ border-bottom: 1px solid var(--border);
+}
+
+.use-case:not(:nth-child(3n + 1)) {
+ padding-left: 26px;
+ border-left: 1px solid var(--border);
+}
+
+.use-case h3 {
+ margin-top: 0;
+ font-size: 20px;
+}
+
+.today-section {
+ border-top: 1px solid var(--border);
+}
+
+.capability-list {
+ border-top: 1px solid var(--border);
+}
+
+.capability-row {
+ display: grid;
+ grid-template-columns: minmax(190px, .75fr) minmax(0, 1.7fr) 150px;
+ gap: 30px;
+ align-items: baseline;
+ padding: 24px 0;
+ border-bottom: 1px solid var(--border);
+}
+
+.capability-row h3,
+.capability-row p {
+ margin: 0;
+}
+
+.capability-row h3 code {
+ background: transparent;
+ border: 0;
+ padding: 0;
+ font-size: 14px;
+ color: var(--text);
+}
+
+.capability-row p {
+ color: var(--text-2);
+}
+
+.capability-row > span {
+ color: var(--muted);
+ text-align: right;
+}
+
+.availability-note,
+.future-qualifier {
+ margin: 30px 0 0;
+ padding: 20px 22px;
+ border-left: 2px solid var(--accent);
+ background: #0e1011;
+ color: var(--text-2);
+}
+
+.availability-note strong {
+ color: var(--text);
+}
+
+.exploring-section {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) minmax(340px, .8fr);
+ gap: clamp(50px, 8vw, 110px);
+ border-top: 1px solid var(--border);
+}
+
+.exploring-copy h2 {
+ margin-bottom: 24px;
+}
+
+.future-list {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ border-top: 1px solid var(--border);
+}
+
+.future-list li {
+ position: relative;
+ padding: 14px 0 14px 25px;
+ border-bottom: 1px solid var(--border);
+ font-weight: 650;
+}
+
+.future-list li::before {
+ content: "+";
+ position: absolute;
+ left: 0;
+ color: var(--accent);
+ font-family: var(--mono);
+}
+
+.future-qualifier {
+ grid-column: 1 / -1;
+ margin-top: 0;
+}
+
+.product-cta {
+ margin-bottom: clamp(80px, 10vw, 140px);
+ padding-top: clamp(70px, 9vw, 110px);
+ padding-bottom: clamp(70px, 9vw, 110px);
+ text-align: center;
+ border-top: 1px solid var(--border);
+ border-bottom: 1px solid var(--border);
+ background: linear-gradient(180deg, #0e1011, transparent);
+}
+
+.product-cta h2,
+.product-cta > p {
+ max-width: 760px;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+.product-cta > p:not(.eyebrow) {
+ color: var(--text-2);
+ font-size: 18px;
+ margin-top: 22px;
+ margin-bottom: 30px;
+}
+
+@media (max-width: 920px) {
+ .product-hero,
+ .exploring-section {
+ grid-template-columns: 1fr;
+ }
+ .product-hero {
+ min-height: auto;
+ }
+ .product-hero h1 {
+ max-width: 12ch;
+ }
+ .product-section-head {
+ grid-template-columns: 1fr;
+ gap: 22px;
+ }
+ .integration-grid,
+ .use-case-grid {
+ grid-template-columns: 1fr 1fr;
+ }
+ .use-case:not(:nth-child(3n + 1)) {
+ padding-left: 0;
+ border-left: 0;
+ }
+ .use-case:nth-child(even) {
+ padding-left: 26px;
+ border-left: 1px solid var(--border);
+ }
+}
+
+@media (max-width: 620px) {
+ .product-hero,
+ .product-section,
+ .product-cta {
+ padding-left: 18px;
+ padding-right: 18px;
+ }
+ .product-hero {
+ gap: 64px;
+ padding-top: 64px;
+ padding-bottom: 84px;
+ }
+ .product-hero h1 {
+ font-size: clamp(51px, 16vw, 72px);
+ }
+ .integration-grid,
+ .use-case-grid {
+ grid-template-columns: 1fr;
+ border-left: 0;
+ }
+ .integration-card {
+ min-height: 340px;
+ padding: 26px 0;
+ border-right: 0;
+ }
+ .use-case,
+ .use-case:nth-child(even) {
+ min-height: 0;
+ padding: 25px 0;
+ border-left: 0;
+ }
+ .capability-row {
+ grid-template-columns: 1fr;
+ gap: 9px;
+ }
+ .capability-row > span {
+ text-align: left;
+ }
+ .exploring-section {
+ gap: 50px;
+ }
+}
diff --git a/playground/src/for-products.ts b/playground/src/for-products.ts
new file mode 100644
index 0000000..fcba4ec
--- /dev/null
+++ b/playground/src/for-products.ts
@@ -0,0 +1,21 @@
+import { inject } from "@vercel/analytics";
+
+inject();
+
+const prefersReducedMotion = matchMedia("(prefers-reduced-motion: reduce)").matches;
+
+if (!prefersReducedMotion && "IntersectionObserver" in window) {
+ const observer = new IntersectionObserver(
+ (entries) => {
+ for (const entry of entries) {
+ if (!entry.isIntersecting) continue;
+ entry.target.classList.add("in");
+ observer.unobserve(entry.target);
+ }
+ },
+ { threshold: 0.08, rootMargin: "0px 0px -6% 0px" },
+ );
+ for (const element of document.querySelectorAll(".reveal")) observer.observe(element);
+} else {
+ for (const element of document.querySelectorAll(".reveal")) element.classList.add("in");
+}
diff --git a/playground/test/for-products.test.ts b/playground/test/for-products.test.ts
new file mode 100644
index 0000000..5205c2e
--- /dev/null
+++ b/playground/test/for-products.test.ts
@@ -0,0 +1,38 @@
+import { readFileSync } from "node:fs";
+import { resolve } from "node:path";
+import { describe, expect, it } from "vitest";
+
+const root = resolve(import.meta.dirname, "../..");
+const page = readFileSync(resolve(root, "playground/for-products.html"), "utf8");
+const home = readFileSync(resolve(root, "playground/index.html"), "utf8");
+const vercel = JSON.parse(readFileSync(resolve(root, "vercel.json"), "utf8")) as {
+ redirects: Array<{ source: string; destination: string }>;
+ rewrites: Array<{ source: string; destination: string }>;
+};
+
+describe("product integration page", () => {
+ it("publishes the clean route and makes it discoverable", () => {
+ expect(vercel.rewrites).toContainEqual({ source: "/for-products", destination: "/for-products.html" });
+ expect(vercel.redirects).toContainEqual({ source: "/for-products.html", destination: "/for-products", permanent: true });
+ expect(home).toContain('href="/for-products"');
+ });
+
+ it("includes canonical and social metadata", () => {
+ expect(page).toContain("Use Posecode in Your Product");
+ expect(page).toContain('rel="canonical" href="https://www.posecode.org/for-products"');
+ expect(page).toContain('property="og:title"');
+ expect(page).toContain('name="twitter:card"');
+ });
+
+ it("keeps current and potential capabilities explicitly separate", () => {
+ expect(page).toContain('id="today"');
+ expect(page).toContain('id="exploring"');
+ expect(page).toContain("No hosted commercial platform yet");
+ expect(page).toContain("None of these capabilities is generally available today");
+ expect(page).toContain("There is no published commercial pricing");
+ });
+
+ it("provides an integration-specific contact action", () => {
+ expect(page).toContain("mailto:hello@posecode.org?subject=Posecode%20product%20integration");
+ });
+});
diff --git a/playground/vite.config.ts b/playground/vite.config.ts
index 076bb7c..5064dfd 100644
--- a/playground/vite.config.ts
+++ b/playground/vite.config.ts
@@ -18,9 +18,11 @@ export default defineConfig({
build: {
rollupOptions: {
input: {
- // Build files behind the public `/` and `/play[/movement]` routes.
+ // Build files behind the public `/`, `/play[/movement]`, and
+ // `/for-products` routes.
main: resolve(here, "index.html"),
play: resolve(here, "play.html"),
+ forProducts: resolve(here, "for-products.html"),
},
},
},
diff --git a/vercel.json b/vercel.json
index 62b7d5d..ba111b2 100644
--- a/vercel.json
+++ b/vercel.json
@@ -6,10 +6,12 @@
"outputDirectory": "playground/dist",
"redirects": [
{ "source": "/index.html", "destination": "/", "permanent": true },
- { "source": "/play.html", "destination": "/play", "permanent": true }
+ { "source": "/play.html", "destination": "/play", "permanent": true },
+ { "source": "/for-products.html", "destination": "/for-products", "permanent": true }
],
"rewrites": [
{ "source": "/play", "destination": "/play.html" },
- { "source": "/play/:movement", "destination": "/play.html" }
+ { "source": "/play/:movement", "destination": "/play.html" },
+ { "source": "/for-products", "destination": "/for-products.html" }
]
}
diff --git a/vitest.config.ts b/vitest.config.ts
index ad9d188..af05dbd 100644
--- a/vitest.config.ts
+++ b/vitest.config.ts
@@ -2,7 +2,7 @@ import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
- include: ["packages/**/test/**/*.test.ts"],
+ include: ["packages/**/test/**/*.test.ts", "playground/test/**/*.test.ts"],
coverage: {
provider: "v8",
include: ["packages/posecode-parser/src/**/*.ts"],
From 96300c557a3c9472c3982c9a5faf2a2e1de3469c Mon Sep 17 00:00:00 2001
From: a-baran-orhan
Date: Thu, 16 Jul 2026 17:10:04 +0300
Subject: [PATCH 2/2] Add empty changeset for website update
---
.changeset/wise-deer-do.md | 2 ++
1 file changed, 2 insertions(+)
create mode 100644 .changeset/wise-deer-do.md
diff --git a/.changeset/wise-deer-do.md b/.changeset/wise-deer-do.md
new file mode 100644
index 0000000..a845151
--- /dev/null
+++ b/.changeset/wise-deer-do.md
@@ -0,0 +1,2 @@
+---
+---