Core idea: treat the morphism between representations as a language β i.e., comprehension. A natural-language sentence goes in; the system returns a serial, ordered list of decision items; that serial form is discussable/refinable in conversation; and it ultimately resolves into a natural 3D configuration.
The comprehension gradient (why this matters): take "the cat sat and the sun shone."
Sentence β DECISION LEDGER (serial, ordered, dependency-aware, with unresolved choices surfaced)
β [discussion / refinement loop: interrogate the unresolved decisions]
β 3D CONFIGURATION (the UNDERSTANDING PROXY: relational scene β geometry + light +
support + orientation β not separate images)
β MATERIALIZATION (the LAST step: physical items for each word / the whole scene β
papercraft nets, origami crease patterns, printable parts,
electronic components + wiring, or a mix)
The serial order is not cosmetic β it is the narrative order the sentence itself imposes (and folding is inherently sequential too). The item list IS the intermediate representation (IR) of the language: a record of the decisions that reading hides. The 3D configuration must be derivable from the serial form alone β and it must encode relations between items, not just items.
Materialization is downstream of understanding, not part of it: origami/papercraft is a reality output β one fabrication channel chosen after the 3D proxy has done its job of making comprehension inspectable. The same ledger can materialize differently: pure papercraft (fold a net per item), an Arduino project with papercraft/origami props (electronic components for behavior + folded sheets for form), 3D-printed parts, or a mix. The ledger must therefore stay materialization-agnostic; materialization routes are chosen per item in the final stage.
| Item | Status |
|---|---|
| Space repo exists | hf://spaces/KwabsHug/VisualLearningIdea |
| README | sdk: gradio, sdk_version: 6.27.0, python_version: '3.12', app_file: app.py, pinned: false. Short description: "Visualisation and speed of input attempt" (may be updated). |
| app.py | Does not exist yet β repo contains only README + .gitattributes |
| Owner account | PRO account β ZeroGPU available (40 min/day quota), can host up to 10 ZeroGPU Spaces |
| Existing assets to reuse | Sibling Space KwabsHug/GameConfigIdea (Gradio, ZeroGPU, uses gradio_client + InferenceClient + local Kokoro) β reference for patterns that already work on this account |
The Space must launch with demo.launch(mcp_server=True) so each public function becomes an MCP tool callable from HuggingChat / Claude / Codex. Tool exposure is controlled by type hints + docstrings (they become the tool description the LLM reads). Set api_name=False on every helper function that should NOT become a tool.
def parse_sentence_to_items(sentence: str) -> str:
"""Decompose a natural-language sentence into a serial, ordered ledger
(the intermediate representation of the morphism). The output drives BOTH
views of the reference UI: a flat serial token reading and a 3D scene.
Structure (shaped by the cat-sun reference build β see section 9):
tokens: [{word, index, commits: [item_indices], opens: [question_ids]}]
β per-token attribution. Determiners commit nothing but open
unresolved "?" entries. One word may commit several items
(lexical compression: "sat" β surface + pose + support).
items: [{index, kind, description,
decision: {chosen, alternatives_considered},
params, depends_on, stage_direction}]
β stage_direction is the reveal payload the renderer plays:
{action: "spawn"|"move"|"orient"|"couple"|"mark",
target, from, to, couples: [item_indices], ...}.
Without it the player must be hand-coded per sentence.
unresolved:[{id, token_index, question, default_chosen, alternatives}]
β the discussion loop's agenda.
Args:
sentence: A plain-English sentence or scene description.
Returns:
JSON string with keys: tokens, items, unresolved.
"""
def items_to_fold(items_json: str) -> str:
"""Convert serial construction items into a crease pattern in FOLD format.
Args:
items_json: JSON string produced by parse_sentence_to_items.
Returns:
JSON string: {"fold": {...FOLD document...}, "warnings": [...]}
"""
def simulate_fold(fold_json: str) -> str:
"""Simulate folding a FOLD-format crease pattern and export the folded
3D state as OBJ/STL (plus a foldability report).
Args:
fold_json: FOLD-format JSON (from items_to_fold or user upload URL).
Returns:
File path/URL of the folded mesh + foldability diagnostics.
"""
def unfold_mesh_to_papercraft(mesh_url: str) -> str:
"""Reverse morphism: unfold a 3D mesh (STL/OBJ/PLY/OFF URL) into a
2D papercraft net (SVG files with fold direction markings).
Args:
mesh_url: Public http(s) URL to the mesh file.
Returns:
File paths/URLs of the generated SVG components.
"""
def materialize_scene(items_json: str, route: str = "papercraft") -> str:
"""Materialize a validated scene ledger into physical outputs β the LAST
step of the morphism: real items for each word / the whole scene.
Args:
items_json: JSON string produced by parse_sentence_to_items (or refined
via the discussion loop).
route: fabrication route β "papercraft" (unfold nets from the 3D
configuration and lay out sheets), "origami" (crease patterns),
"print3d" (STL per item), "electronics" (component list + wiring
notes for Arduino-type props), or "mixed".
Returns:
JSON string: {"parts": [{item_index, route, files: [urls], notes}],
"bom": [...bill of materials for electronic/physical components...]}
"""
FOLD format is the interchange hub (OrigamiSimulator reads/writes it; rtori converts it; Ori Studio imports/exports it). Every pipeline becomes "X β FOLD β Y".
kind: join item in the IR.pip install openmesh requires cmake + g++ + pybind11. If the Space build fails, pin prebuilt binaries (Inkscape MightyScape docs document per-OS workarounds).api_name=False on all internal helpers. Keep the public tool count β€ 6.@spaces.GPU(duration=N) values; quota is reserved per requested duration, not actual runtime. Reset is 24h from first GPU use.queue=True on long-running events (progress notifications), queue=False for fast ones (10Γ throughput).| Resource | URL |
|---|---|
| Gradio MCP server guide | gradio.app/guides/building-mcp-server-with-gradio |
| Spaces as MCP servers (HF docs) | huggingface.co/docs/hub/en/spaces-mcp-servers |
| paperfoldmodels | github.com/felixfeliz/paperfoldmodels |
| OrigamiSimulator (FOLD solver) | github.com/amandaghassaei/OrigamiSimulator |
| osresearch/papercraft (coplanar reference) | github.com/osresearch/papercraft |
| rtori (FOLD convert/simulate CLI) | github.com/origami-code/rtori |
| Ori Studio (UX reference) | oristudio.dev |
kwabshug-visuallearningidea.hf.space/gradio_api/mcp/schema lists exactly the 4 planned tools (no helper leakage)unfold_mesh_to_papercraft on a bunny OBJ returns valid SVG(s)parse_sentence_to_items("make a box with a lid") returns valid serial IR with β₯1 unresolved ambiguity noteitems_to_fold on that IR produces a FOLD doc that simulate_fold acceptsThe cat-sun demo (serial reading tab + scene tab, Three.js) was built end-to-end in the preview sandbox. These lessons are now folded into the contract above:
parse_sentence_to_items; the 3D scene is downstream. Both views render from the same ledger; each view has its own independent stepper. Default view: serial.stage_direction. The demo's choreography was hand-coded β possible only because the sentence was known in advance. A generic player requires each item to carry its reveal payload (spawn / move / orient / couple / mark). Now in the tool contract.buildForm / buildPose / buildSupport between the live scene and per-word snapshot images. The Space equivalent must be data-driven parameterization (item params β geometry). Otherwise every new sentence requires hand-modeling β the biggest current gap and the reason Phase 2's IR schema must be designed for buildability, not just describability.tokens is now a first-class output key.sdk: static. The player UI is proven in-browser (Three.js via CDN works in both the preview sandbox and static Spaces, which are free and run no compute). The Space's only job is to emit the items the browser cannot make. See companion doc: General Tool Space handover (artifact: toolhub-handover).