Skip to content

feat: Joints implementation#150

Merged
alvarosabu merged 12 commits intomainfrom
feat/joints
Mar 18, 2025
Merged

feat: Joints implementation#150
alvarosabu merged 12 commits intomainfrom
feat/joints

Conversation

@Neosoulink
Copy link
Copy Markdown
Member

@Neosoulink Neosoulink commented Nov 20, 2024

Summary

This PR introduces the Joints feature.

Joints are one of the advanced features natively available in Rapier.
This PR provides an easy, basic but robust way to deal with it.

Logs

  • Support for Joint types:
    • "fixed" | "spring" | "rope" | "generic" | "spherical" | "prismatic" | "revolute"
  • New components based on the supported joint types (FixedJoint, SphericalJoint, ...)

How to use

Here's a basic implementation example:

<RigidBody
  v-for="(ref, i) in bodyRefs"
  :key="i"
  :ref="ref"
  :type="i === 0 ? 'kinematic' : 'dynamic'"
  :position="[i * 1.5, 0, 0]"
   collider="ball"
 >
  <TresMesh>
    <TresSphereGeometry />
    <TresMeshNormalMaterial />
  </TresMesh>
</RigidBody>

<SphericalJoint
  v-for="(ref, i) in bodyRefs"
  :key="i"
  :bodies="[ref.value?.[0]?.instance, bodyRefs[i - 1]?.value?.[0]?.instance]"
  :params="[
    [-1.1, 0, 0],
    [1.1, 0, 0],
  ]"
/>

Preview

Screen.Recording.2024-11-20.at.2.10.27.AM.mov

Will close #108

@Neosoulink Neosoulink self-assigned this Nov 20, 2024
@Neosoulink Neosoulink marked this pull request as draft November 20, 2024 00:19
@Neosoulink Neosoulink marked this pull request as ready for review December 9, 2024 14:05
@Neosoulink
Copy link
Copy Markdown
Member Author

Hi @alvarosabu, I just added a base documentation for Joint.
I'd appreciate having your review of it (the Joint implementation in general).

cc: @JaimeTorrealba

@Neosoulink Neosoulink added enhancement New feature or request feature p3-significant High-priority enhancement (priority) labels Dec 10, 2024
@Neosoulink
Copy link
Copy Markdown
Member Author

Any update on this one?

This PR is waiting for review

Copy link
Copy Markdown
Member

@JaimeTorrealba JaimeTorrealba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the implementation, But also I would add a composable WDYT? With the same logic

an useJoint() or similar so the people is not force to use it with Tres.js components only

Comment thread .vscode/settings.json Outdated
Comment thread docs/components/joint.md Outdated

Joints is an extension feature provided in [Rapier#Joint](https://rapier.rs/docs/user_guides/javascript/joints/). It lets us connect two or more bodies, restricting their movements according to each other.

In **Tres** we can achieve such motion restriction by using one of the available components designed to handle joints:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small one but maybe we need consistency here it all pages should be "Tres.js"

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noted

Comment thread docs/components/joint.md Outdated

<template>
<RigidBody
v-for="(ref, i) in bodyRefs"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got a problem, the mental load of this example is high. I would instead, in this page, come with a very basic example, just two rigid Bodies joined (just that). The idea here is that they learn how to use it.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example reflects the one in the playground (the JointsDemo example)...
Is it okay to simplify this one in this documentation but keep the demo as it is?

Array.from({ length: 10 }).map(() => shallowRef<ExposedRigidBody>(null)),
)

setInterval(() => {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why setInterval?

And if you decided to use setInterval, please remember to clear the interval in the onUnmouted

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah, you're right,

setInterval was used to update the rotation of the first and have that whip effect

Comment thread src/components/joints/BaseJoint.vue Outdated
}

if (hasParamsError) {
throw new Error(`Invalid "${type}" joint parameters`)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe too difficult, but could be said what parameters have problems?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, maybe a string containing the requirement or why it the error occurs

@Neosoulink
Copy link
Copy Markdown
Member Author

I like the implementation, But also I would add a composable WDYT? With the same logic

an useJoint() or similar so the people is not force to use it with Tres.js components only

I think it possible even to have both features

@JaimeTorrealba
Copy link
Copy Markdown
Member

I like the implementation, But also I would add a composable WDYT? With the same logic
an useJoint() or similar so the people is not force to use it with Tres.js components only

I think it possible even to have both features

Completely, maybe another PR to be more organized.

### Description

- Make the Joint component listen to updates
- Provide more precise `Joint` error messages
- Simplify the Joint example and the Joint documentation
- Remove `cSpell.words` VsCode setting
@Neosoulink
Copy link
Copy Markdown
Member Author

Completely, maybe another PR to be more organized.

I pushed the changes requested, and yes, this will be part of a separate PR ✅

Here what has changed:

  • c1a6ffd1769b6a872c48a42bcd54bf02333658e1
    • Make the Joint component listen to updates
    • Provide more precise Joint error messages
    • Simplify the Joint example and the Joint documentation
    • Remove cSpell.words VsCode setting

Comment thread docs/components/joint.md Outdated

```vue
<script setup lang="ts">
<script setup>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @Neosoulink examples should be in Typescript as much as possible:

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it

Comment thread docs/components/joint.md
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Neosoulink you need to add the entry on docs/.vitepress/config so it's available on the side navigation

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noted

Comment thread docs/components/joint.md

> Preview
<img width="843" alt="Screenshot 2024-12-09 at 4 01 58PM" src="https://github.com/user-attachments/assets/9baaea58-f996-45d5-b4f4-34dae30d44cb">
<img width="1141" alt="JointsDemo" src="https://github.com/user-attachments/assets/d3cacac3-8764-4906-886a-d0b7a764b7c0" />
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Neosoulink Why not using the normal markdown image notation for this?

![JointsDemo](https://github.com/user-attachments/assets/d3cacac3-8764-4906-886a-d0b7a764b7c0)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was automatically added from github, but let make it clean. I'm going to update it

Comment thread docs/components/joint.md Outdated
### Explanation

In the above example, we created a list of 10 `RigidBody` references and mapped them using the `v-for` directive. Then, we implemented the `SphericalJoint` component, creating a Joint between each mapped `RigidBody`.
In the above example, we created 2 `RigidBody` references, then, we implemented the `SphericalJoint` component, by placing our 2 `RigidBody` references in the `:bodies` property and specifying parameters, we created a `spherical-joint` between them.
Copy link
Copy Markdown
Member

@alvarosabu alvarosabu Jan 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we created two RigidBody references

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @Neosoulink if I understand correctly the scope of this file is to generate several components using BaseJoint.vue as a base, but why? Why not just directly create the SFC components per kind of joint? They are only 7

This is an unusual pattern for vue that we don't use anywhere else in the ecosystem, I will strongly suggest we just separate this into different Joint components.

You could even just have one Join component and pass a prop defining the type and having <component :is="AnyJointComponent" /> under the hood.

Let me know if I can support you with this one.

Copy link
Copy Markdown
Member Author

@Neosoulink Neosoulink Jan 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This approach prioritizes re-usability based on the same component.
In other words, it's just a shortcut for the Joints

It's exactly the same as doing:

<Joint type="joint-type" />

What makes it efficient (in my point of view) is that there is only one source of truth, one part dealing with the main feature and other parts extending from it.
Plus, the child components can have props type precisions and be aware of what the parent needs for the props

I often used to implement a few years ago, back in 2019 (old goods days 🥲)
It's a pattern I discovered while learning how Vue was working under the hood

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey!
While updating it, I realized I did the same for the Colliders, Why not make the change on a separate PR, to update the pattern? (for Joints & Colliders)

@alvarosabu alvarosabu self-requested a review March 18, 2025 09:47
@alvarosabu alvarosabu merged commit 7a11432 into main Mar 18, 2025
2 checks passed
@Neosoulink Neosoulink deleted the feat/joints branch May 20, 2025 09:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request feature p3-significant High-priority enhancement (priority)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Joints

3 participants