Skip to content

fix: true rest-pose bounds, standing on the bottom centre - #5

Open
Aymericr wants to merge 10 commits into
mainfrom
ak-18/rest-pose-bounds
Open

Aymericr wants to merge 10 commits into
mainfrom
ak-18/rest-pose-bounds

Conversation

@Aymericr

Copy link
Copy Markdown
Contributor

Stacked on #4 (and #1–#3); until they merge this diff includes their commits.

What and why

A catalog record's dimensions drive the floor footprint, the drag box, the rotate handle, the 2D plan and the loading box. The catalog sync computed them from raw OBJ vertices only, so:

  • primitive-only records (most Articraft URDFs are boxes, cylinders and spheres) fell back to [1, 1, 1] (3,135 of 9,996 records);
  • the rest ignored primitives, link/joint/visual origins and mesh scale;
  • assets whose rest pose extends below their URDF origin sank into the floor, and footprints were off-centre.

This PR:

  • urdfRestBounds(urdf, meshExtent): the rest-pose bounds (every joint at 0) from every visual through link, joint and visual origins and mesh scale, in Pascal's Y-up frame. Same conventions as urdf-loader (fixed-axis rpy, Z-aligned cylinders, all root links at the origin). Exported, with objExtent and bottomCentreFrame, for hosts that sync a catalog.
  • bottomCentreFrame(bounds): dimensions plus an offset that stands the asset on its bottom centre at the node origin (rounded to 0.1 mm).
  • Catalog items and nodes carry an optional offset; placement copies it; the renderer moves the loaded asset by it. The asset now stands on the floor, centred on its footprint, like the placeholder box. Nodes without an offset render exactly as before (no silent move of placed assets).

Numbers (the audit's 200-record sample, seed 20260926, public index of 2026-08-11)

before (index) after (this code)
dimensions off by >10 % on an axis 188 / 200 0 / 200 (max 0.3 %)
sinks >1 cm into the floor 48 / 200 (24 %) 0 / 200
footprint centre off by >10 % 67 / 200 0 / 200

"After" is checked against an independent Python reference on the same files (floor and centre agree within 0.05 mm). 2 of the 200 are unit outliers (>30 m, OBJ in millimetres with no scale); they keep their true size.

Failing case first

Commit e1b34be: bounds.test.ts (box, cylinder under a rotated joint, a millimetre mesh with scale, comments and declarations in the XML) and the offset case in catalog-node.test.ts fail on main.

Proof

bun test: 40 pass, 0 fail. bun run check-types: clean. bun run build: ok.

The catalog index itself is rewritten by the host's sync (next step there); records synced before it keep [1,1,1] and no offset until then.

🤖 Generated with Claude Code

Aymericr and others added 10 commits September 26, 2026 20:58
…iling first

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The host ships @pascal-app/core 1.0.3 on three 0.186, which the <1.0.0 and
^0.185 ranges excluded, so strict installs refused the plugin. Dev
dependencies follow the host (core/editor/viewer 1.0.3, three 0.186.0,
@types/three 0.184.1 as in pascalorg/editor).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Every slider passed restoreOnCommit={false}: SliderControl pauses history for
the drag and, with the flag off, resumes without a tracked write, so a drag of
scale, position, rotation or a joint left no undo step. The default restores
the pre-drag value and writes the final one as a single tracked change.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Continuous joints (wheels, fans, knobs: 20.8 % of the catalog's movable joints)
followed the same sine sweep as limited ones, over a fallback range of ±π, so
they rocked back and forth. They now turn one full revolution per motion
period, live and in the exported loop clip, which stays seamless.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Placement wrote motionEnabled: true and the inspector toggled it through
updateNode, so every placed asset animated forever by default and Start/Stop
went into undo, autosave and collaboration. Playback now lives in a transient
per-asset store: assets start still, the scene keeps only the rest pose
(jointValues), and stopping returns every joint to it. The saved flag is
dropped from the schema; older scenes that saved it load still. The placement
preview shows the rest pose too.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Catalog dimensions came from raw OBJ vertices only, so primitive-only records
fell back to [1, 1, 1] and the rest ignored primitives, origins and mesh scale;
assets whose rest pose extends below their origin sank into the floor.

urdfRestBounds computes the rest-pose bounds from every visual (box, cylinder,
sphere, mesh) through link, joint and visual origins and mesh scale, in Pascal's
Y-up frame; bottomCentreFrame turns them into dimensions and an offset. Nodes
carry the catalog offset, and the renderer moves the loaded asset by it, so the
asset stands on the floor centred on its footprint, like the placeholder box.
Nodes without an offset render as before.

On the audit's 200-record sample (seed 20260926): dimensions off by more than
10 % 188 -> 0 (max 0.3 % against an independent reference), sinking into the
floor 48 -> 0, footprint centre off by more than 10 % 67 -> 0.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@pascal

pascal Bot commented Sep 27, 2026

Copy link
Copy Markdown

I hit an error while handling your request (Model unavailable on AI Gateway free tier: Free tier users do not have access to this model. Upgrade to paid credits at https://vercel.com/d?to=%2F%5Bteam%5D%2F%7E%2Fai%3Fmodal%3Dtop-up for unrestricted…).

Please try again, rephrase, or reach out if it keeps failing.

Error id: 239ad3a3-2592-4aa2-ad9c-aaaf1c9b3efc

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant