"
)
def _ex(question: str, files: list):
return [[str(EXAMPLES_DIR / f) for f in files], question]
EXAMPLES = [
_ex(
FLIP_QUESTION,
["image1.png", "image2.png", "image3.png", "image4.png", "image5.png"],
),
_ex(
Q1_QUESTION,
["q1_img1.jpg", "q1_img2.jpg", "q1_opt_a.jpg", "q1_opt_b.jpg",
"q1_opt_c.jpg", "q1_opt_d.jpg"],
),
_ex(
Q3_QUESTION,
["q3_struct1.jpg", "q3_struct2.jpg", "q3_opt_a.jpg", "q3_opt_b.jpg",
"q3_opt_c.jpg", "q3_opt_d.jpg"],
),
]
with gr.Blocks(title="SpatialBlock") as demo:
gr.HTML(
"""
🧱
SpatialBlock — Spatial Intelligence in LVLMs
SpatialBlock: Enhancing Spatial Intelligence in LVLMs via Synthetic
Block-Stacking Problem — vision-language models fine-tuned on
15,000 synthetic block-stacking problems to reason about the 3D
structure behind 2D images.
Paper ·
GitHub ·
Model ·
Dataset
"""
)
gr.Markdown(
"Upload the images for a spatial multiple-choice question — one image per "
"`` marker in the question — and ask. The model "
"(`SpatialBlock-7B-reason`) thinks step by step, then gives its final "
"answer between ` ` tags. "
"**Try the examples below** to see it in action."
)
with gr.Row():
with gr.Column():
images_in = gr.Gallery(
label="Images (one per marker, in order)",
file_types=["image"],
columns=3,
height=240,
type="filepath",
interactive=True,
)
question_in = gr.Textbox(
label="Question (use where each uploaded image goes)",
placeholder=(
"Question : Here are images of a 3D structure made of block \n"
"and the direction of views.\n..."
),
lines=9,
max_lines=14,
)
submit_btn = gr.Button("Answer", variant="primary")
with gr.Column():
answer_letter = gr.Textbox(
label="Answer",
interactive=False,
buttons=["copy"],
)
reasoning_out = gr.Textbox(
label="Step-by-step reasoning",
lines=14,
max_lines=24,
interactive=False,
buttons=["copy"],
)
timing_out = gr.Markdown()
submit_btn.click(
fn=answer,
inputs=[images_in, question_in],
outputs=[answer_letter, reasoning_out, timing_out],
)
gr.Examples(
examples=EXAMPLES,
inputs=[images_in, question_in],
fn=answer,
outputs=[answer_letter, reasoning_out, timing_out],
cache_examples=True,
cache_mode="lazy",
label="Examples from SpatialBlock-15k (and the repo's flip demo)",
)
gr.Markdown(
"""
How this works
The question text contains `` markers; each uploaded image is
substituted for one marker, in upload order. This is exactly the
interface of the authors' `src/demo.py` reference implementation.
- The question is wrapped in the authors' reasoning prompt, and the
model produces a numbered reasoning sequence ending with
`X`.
- The paper also trains a **direct** model that predicts the option
letter immediately
([SpatialBlock-7B-direct](https://huggingface.co/rsoohyun/SpatialBlock-7B-direct));
this demo runs the reasoning variant.
The checkpoint is a Qwen2.5-VL-7B-Instruct fine-tune on
[SpatialBlock-15k](https://huggingface.co/datasets/rsoohyun/SpatialBlock-15k),
a fully synthetic set of block-stacking problems covering 3D-to-2D
projection, viewpoint transformation, and structural combination.
Citation
```bibtex
@misc{ryu2026spatialblockenhancingspatialintelligence,
title={SpatialBlock: Enhancing Spatial Intelligence in LVLMs via Synthetic Block-Stacking Problem},
author={Soohyun Ryu and Sohee Kim and Eunho Yang},
year={2026},
eprint={2609.07064},
archivePrefix={arXiv},
primaryClass={cs.CV},
url={https://arxiv.org/abs/2609.07064},
}
```
"""
)
if __name__ == "__main__":
demo.launch(theme=gr.themes.Citrus())