Origami RL

environment

OpenEnv RL environment for origami folding. Add one crease at a time, get per-step geometry rewards, build up to the target shape.

Multi-step episodes: each crease is scored immediately for progress, flat-foldability (Kawasaki, Maekawa, BLB), and economy. Complete within max_folds to unlock a 10× bonus.

How It Works

1
Reset
Pick a task → get empty paper + anchor points
2
Add Crease
Submit {"from":[x,y], "to":[x,y], "assignment":"M"|"V"}
3
Per-step Reward
Progress + geometry theorems scored after every crease
4
Complete
Finish within max_folds to unlock 10× completion bonus

Action

from [x, y] Start point — must be a listed anchor pointrequired
to [x, y] End point — must be a listed anchor pointrequired
assignment "M" | "V" Mountain or valley foldrequired

Reward Breakdown

progress 0–1 Fraction of target creases geometrically covered
delta 0–1 Coverage improvement from this step alone
kawasaki 0–1 Flat-foldability: alternating sector angles sum to 180°
maekawa 0–1 Flat-foldability: |M−V| = 2 at interior vertices
blb 0–1 Big-Little-Big lemma compliance
economy 0–1 Penalty for excess creases
completion 0 | 10 Bonus when progress > 0.9 and geometry valid

API Reference

WebSocket

WS /ws Persistent connection
Send: Reset
{"type": "reset", "data": {"task_name": "triangle"}}
Send: Step
{"type": "step", "data": {"fold_data": {...}}}
Receive: Observation
{"type": "observation", "data": {"reward": 20.0, "done": true, ...}}

REST

POST /sessions Create session
POST /sessions/{id}/reset Reset with task_name
POST /sessions/{id}/step Submit fold action
GET /tasks List all tasks
GET /tasks/{name} Task detail + target fold

Quick Start

python — multi-step episode
import requests

SERVER = "http://localhost:8000"

# Create session + reset
sid = requests.post(f"{SERVER}/sessions").json()["session_id"]
obs = requests.post(f"{SERVER}/sessions/{sid}/reset",
    json={"task_name": "triangle"}).json()["observation"]
print("anchor points:", obs["anchor_points"])

# Add creases one at a time
creases = [
    {"from": [0, 0], "to": [1, 1], "assignment": "V"},
]
for crease in creases:
    result = requests.post(f"{SERVER}/sessions/{sid}/step",
        json={"crease": crease}).json()["observation"]
    print(f"step {result['step_count']}: reward={result['reward']:.3f}")
    print(f"  breakdown: {result['reward_breakdown']}")
    if result["done"]:
        print("Episode complete!")
        break
step 0 / —
2D Paper
Mountain
Valley
Boundary
Reward
Start an episode to see reward breakdown
No steps yet
from to