English | 日本語
Touchless sensory evaluation of materials, with a webcam and your bare hands.
GPU soft-matter physics you can pinch, press and lift with bare hands in front of an ordinary webcam; a pseudo-haptic hand that is held back by hard materials; and a built-in psychophysics lab that runs blind A/B tests on simulated materials and tells you, with confidence intervals, what people can feel.
One sheet, one grip. The dial moves from gossamer to sheet metal while the hand is still holding it -- the fold, the swing and the drape all change, because the dial is Young's modulus, not a colour.
A materials company that wants to know can customers tell these two foams apart? or which of these three do they prefer? normally makes the foams and recruits a panel. This runs the panel on simulated samples instead -- at a trade-show booth, on visitors, with nothing to touch but air:
| Usual practice | FCTX MATTER STUDIO | |
|---|---|---|
| Samples | Physical prototypes | Simulated, specified by Young's modulus (or your own catalogue) |
| Conveying hardness | Touch the real thing | Pseudo-haptics: the drawn hand is resisted by hard samples |
| Answering | Paper or tablet | Raise a hand over your choice -- no touch, no mouse |
| Design | Hand-assigned | 2AFC + adaptive staircase, sides and conditions randomised |
| Results | Tabulated later | JND, modulus Weber fraction, Bradley–Terry ranking, automatically |
| Does the illusion work? | -- | Measured in the same run: on/off interleaved, effect with a bootstrap CI |
- XPBD solver written from scratch in NVIDIA Warp -- not
warp.sim. Cloth (stretch, shear, dihedral bending), soft bodies (stable Neo-Hookean tetrahedra, Macklin & Müller 2021) and 24,000-grain granular matter are one solver with different constraint sets, so a single scalar rewrites every compliance in the scene mid-grab without rebuilding anything. - Parallel Gauss–Seidel by graph colouring, the substep loop captured as a CUDA graph (dynamic values live in device arrays so the graph stays valid), Jacobi-averaged particle contacts with count-faded SOR, a hash grid.
- Embedded render skin: the drawn surface is a smooth fitted mesh bound to eight incident tetrahedra per vertex by barycentric blending, so a coarse lattice renders as a sphere, not a staircase.
- Bare-hand interaction: MediaPipe landmarks → One-Euro filtering → image-to-world projection → 21 capsule colliders per hand, swept across substeps, speed-limited, faded in so a hand never materialises inside matter; wrist-anchored grabs with palm-frame rotation so opening the fingers never flings what they held.
- Pseudo-haptics with a per-(hand, body) contact kernel read back through double-buffered pinned memory and CUDA events -- zero measured frame cost.
- Custom ModernGL renderer: HDR, MSAA, shadow maps with per-receiver bias, SSAO, progressive bloom, ACES, a single-draw-call HUD with a CJK label cache, CUDA–GL interop for zero-copy particle upload.
- Deterministic lockstep: headless runs are bit-reproducible, which is what the test suite and the video renderer stand on.
- Built for unattended operation: camera hot-plug recovery, attract mode, a resilient frame loop, scheduled restarts only when nobody is there, a soak-test tool, visitor analytics.
Every number below is produced by tools/make_figures.py
and stored in docs/figures/measurements.json.
Windows with an NVIDIA GPU (CUDA 12 driver) and any webcam:
setup.bator by hand, on Windows or Linux:
uv sync
uv run python tools/download_models.py # MediaPipe hand model, sha256-checked
uv run fctx --check # GPU, OpenGL, model, camera
uv run fctx # free play: cloth (1-5 switch presets)
uv run fctx --demo # the choreographed demonstration
uv run fctx --source synthetic # no camera: mouse-driven handRun a study and analyse it:
uv run fctx --study studies/hardness_jnd.toml --kiosk
uv run fctx-analyze studies/results/hardness_jnd.csv --plot jnd.pngDISCRIMINATION (threshold = hardness-dial difference at 75% correct)
pseudo-haptics on: 120 trials, 14 people, 78% correct
threshold 0.071 [0.058, 0.090] staircase 0.066 -> modulus Weber fraction 72%
pseudo-haptics off: 120 trials, 14 people, 71% correct
threshold 0.118 [0.091, 0.160] staircase 0.109 -> modulus Weber fraction 145%
pseudo-haptics effect: threshold off/on = 1.66 [1.18, 2.35] -> helps
Output format only -- illustrative numbers, not a result.
- Pre-screening materials before making prototypes: which differences are
noticeable at all, which of a shortlist people prefer. Bring your own
catalogue (
--catalog materials.toml, Young's modulus per entry). - HCI and perception research: pseudo-haptics, visual stiffness perception,
bare-hand interaction -- with a validated staircase, reproducible CSV logs and
deterministic replay of recorded hand motion (
--record/--source replay). - Exhibitions and teaching:
--kioskruns unattended for days; the demo, attract mode, visitor prompts (any language) and a daily report are built in.
flowchart LR
cam[webcam] --> mp[MediaPipe<br/>landmarks]
mp --> trk[HandTracker<br/>One-Euro, projection,<br/>track ids]
trk -->|real hands| hap[PseudoHaptics<br/>C/D ratio by hardness]
hap -->|displayed hands| sol
subgraph GPU [GPU · NVIDIA Warp]
sol[XPBD solver<br/>colored Gauss-Seidel<br/>CUDA graph] --> con[contact kernel<br/>per hand × body]
end
con -.->|async pinned readback| hap
con -.-> st[Study<br/>staircase, blinding,<br/>dwell answers]
st -->|per-sample hardness| sol
st --> csv[(CSV)] --> an[fctx-analyze<br/>fit, bootstrap,<br/>Bradley-Terry]
sol -->|CUDA-GL interop| ren[ModernGL renderer<br/>HDR, shadows, SSAO]
The design, the maths, every stability rule and the known limits (with measurements) are in docs/ARCHITECTURE.md. Running an installation or a study: docs/OPERATIONS.md (Japanese).
- Not yet validated on people. Whether pseudo-haptics helps with a webcam hand, and whether judgements on simulated samples match judgements on real ones, are exactly what this tool measures -- they are not claims. Tying results to products needs one panel with physical samples of known modulus.
- Stiffness ceiling. Above ~0.4 on the soft dial the tetrahedra reach their resolvable stiffness; ordering holds, the modulus ratio becomes nominal (the analysis warns).
- Granular friction is weak (position-based friction vanishes at rest), so piles spread; the grain preset ships with a basin. Measured in ARCHITECTURE §10.
- NVIDIA GPU required for physics and rendering; the tracking, study and analysis code runs anywhere (that is what CI runs).
uv run python tools/run_tests.py # 18 files, ~380 checks (GPU, ~4 min)
uv run python tools/run_tests.py --cpu # what CI runs on every pushTests are named as the property they defend -- a_hard_surface_holds_the_drawn_hand_back_and_a_soft_one_lets_it_sink,
the_study_recovers_a_known_threshold, lockstep_makes_a_headless_run_reproducible,
opening_the_fingers_does_not_fling_what_they_were_holding.
- NVIDIA Warp (Apache-2.0), MediaPipe Hands (Apache-2.0; the model is downloaded and hash-checked, not redistributed), ModernGL (MIT), OpenCV (Apache-2.0)
- Macklin, Müller & Chentanez, XPBD (2016); Macklin et al., Small Steps in Physics Simulation (2019); Macklin & Müller, Stable Neo-Hookean (2021)
- Casiez, Roussel & Vogel, 1€ Filter (2012); Lécuyer et al., pseudo-haptic feedback (2000); Levitt, transformed up-down methods (1971); Hunter, MM algorithms for Bradley–Terry (2004)
MIT licensed. If you use it in research, see CITATION.cff.





