编译需 Visual Studio 2022+、Clang 16+ 或 GCC 12+,并使用 C++17;库不使用 RTTI 和异常,集成时需注意编译选项;Platform Blue 需自备构建环境和 PlatformBlue.h。
JoltPhysics
jrouweMIT活跃维护多核友好的 C++ 刚体物理与碰撞检测库,专为游戏和 VR 场景设计,已被《地平线:西之绝境》等 3A 大作采用。
A multi core friendly rigid body physics and collision detection library. Written in C++. Suitable for games and VR applications. Used by Horizon Forbidden West and Death Stranding 2.
cmake -S . -B build && cmake --build buildREADME 未说明显存要求;CPU 方面 x86/x64 最低需 SSE2,可选用 SSE4.1/AVX/AVX2/AVX512,ARM64 使用 NEON 兼容 Armv8-A,ARM32 不使用特殊指令。
C++ 多核刚体物理与碰撞检测库,面向游戏和 VR 场景
多核友好的 C++ 刚体物理与碰撞检测库,专为游戏和 VR 场景设计,已被《地平线:西之绝境》等 3A 大作采用。
核心能力
- 支持球体、盒体、胶囊、凸包、网格、地形等多种形状的连续碰撞检测
- 提供固定、铰链、滑块、齿轮、6DOF 等约束与驱动电机
- 可在后台线程批量增删刚体,碰撞查询与主模拟并行
- 支持角色胶囊、轮式/履带车辆、软体、GPU 发丝模拟与浮力
- 模拟确定性可复现,仅复制输入即可在远端重放
容易踩的坑
- v5.6.05.6.0最新正式版2026-07-11 · 2026-07-11 18:55 UTC
New functionality
- Added interface to run compute shaders on the GPU with implementations for DX12, Vulkan and Metal. These interfaces can be disabled by setting
JPH_USE_DX12,JPH_USE_VK,JPH_USE_MTLandJPH_USE_CPU_COMPUTEtoOFF. To build on macOS, you'll need to have dxc and spirv-cross installed. The easiest way to install them is by installing the Vulkan SDK. - Added a strand based hair simulation running on GPU
- System is based on Cosserad rods.
- Can use long range attachment constraints to limit the stretch of hairs.
- Supports simulation (guide) and render (follow) hairs.
- Hair vs hair collision is handled by accumulating the average velocity in a grid and using those velocities to drive hairs.
- Supports collision with the environment, although it only supports ConvexHull and CompoundShapes at the moment.
- The roots of the hairs can be skinned to the scalp mesh.
- Note that this is still work in progress, some things that still need to be done are listed in Hair.h.
- Implemented a new friction model. This friction model is cheaper to execute (15 % faster, 40% less memory for Pyramid test) and doesn't favor the first contact manifold point. Instead of applying friction at every contact point, we now calculate the average contact point and apply friction there. Friction consists of 2 linear constraints and 1 angular constraint. The linear constraints use the
friction_coefficient * sum(contact_impulse)to determine the max linear friction impulse, the angular constraint usesfriction_coefficient * sum(distance_friction_point_to_contact_point * contact_impulse)to determine the max angular friction impulse. - Increased maximum value of
HeightFieldShape::mBitsPerSampleto 16 to be able to create height fields that more closely match the uncompressed height values. - Made tolerance that's used in the internal edge removal algorithm configurable in
CollideShapeSettings::mInternalEdgeRemovalVertexToleranceSqandPhysicsSettings::mInternalEdgeRemovalVertexToleranceSq. - Added support for RISC-V RVV, the SIMD extension for RISC-V.
- Added
JPH_BUILD_SHARED_LIBScmake variable to determine whether to build static or shared libraries (it defaults toBUILD_SHARED_LIBS). This allows embedding Jolt as a static library within a shared library. - Simulation stats: Added tracking of collision steps. This way we can know by how many steps we need to divide the numbers to get averages per step.
- Added support for glTF
KHR_physics_rigid_bodiesconstraint motors. This addsESpringMode::MassNormalizedStiffnessAndDampingto be able to specify the spring parameters mass-normalized / in acceleration-mode. It also addsEMotorState::PositionAndVelocitywhich creates a force proportional tostiffness * (position_target - position_current) + damping * (velocity_target - velocity_current). - Added
Ragdoll::DriveToPoseUsingMotorsvariant that drives to a pose using both position and velocity. - Added
Body::ApplyBodyCreationSettingsandBody::ApplySoftBodyCreationSettingsto be able to update a body with creation settings after creation. - Added
ShapeCastSettings::mExtraConvexRadiuswhich inflates the query shape by an extra convex radius. - Up to 40% performance improvement (scene dependent) and up to 70% memory reduction (scene dependent).
Bug Fixes
- Made it possible to make a class outside the
JPHnamespace serializable. VehicleConstraints are automatically disabled when the vehicle body is not in thePhysicsSystem.- Fixed an issue where a character could get stuck. If the character was teleported inside an area surrounded by slopes that are steeper than
mMaxSlopeAngle, the code to stop the constraint solver from ping ponging between two planes didn't work properly. - Fixed an issue where collide/cast shape against a triangle that was scaled inside out would return a hit result with
mShape2Facein incorrect winding order. This caused an incorrect n
- Added interface to run compute shaders on the GPU with implementations for DX12, Vulkan and Metal. These interfaces can be disabled by setting
- v5.5.05.5.02025-12-28 · 2025-12-28 13:18 UTC
查看更新说明
There are a few minor breaking changes, see this document.
New Functionality
- Added new define
JPH_TRACK_SIMULATION_STATSwhich tracks simulation statistics on a per body basis. This can be used to figure out bodies are the most expensive to simulate. - Added
RagdollSettings::CalculateConstraintPrioritieswhich calculates constraint priorities that boost the priority of joints towards the root of the ragdoll. BoxShape,CylinderShapeandTaperedCylinderShapewill now automatically reduce the convex radius if the specified value is too big for the shape (instead of erroring out).- Added ability to configure the thickness of triangles when colliding with soft bodies through
CollideSoftBodyVerticesVsTriangles::sTriangleThickness. - Added
JPH_DEFAULT_ALLOCATE_ALIGNMENTwhich allows defining the defaultAllocatealignment if your allocator's alignment is different from the alignment as defined by__STDCPP_DEFAULT_NEW_ALIGNMENT__. - Visual Studio 2026 support.
Bug Fixes
- A 6DOF constraint that constrains all rotation axis in combination with a body that has some of its rotation axis locked would not constrain the rotation in the unlocked axis.
- Added include
type_traitsforstd::is_trivialto avoid compile error on macOS with clang 21. - Fixed compilation error when using Jolt in conjunction with the
_CRTDBG_MAP_ALLOCdefine on Windows. - Fixed cast shape possibly not returning a hit when a shape cast starts touching (but not intersecting) another shape and requesting the deepest hit.
- Fixed division by zero when doing a really long (6 KM) sphere cast against a triangle. In this case the floating point accuracy became low enough so that the distance between the sphere center and the triangle (which should be 'radius') became zero instead.
- Fixed memory leak when providing invalid parameters to
TaperedCylinderShapeSettingsand creating the shape. - Fixed collision between soft body and
TriangleShape/MeshShape/HeightFieldShape. This would not find the closest collision point in case the shape was scaled. It would also make the triangles much thicker than intended causing collisions with back facing triangles that were very far away.
- Added new define
- v5.4.05.4.02025-09-27 · 2025-09-27 12:08 UTC
查看更新说明
There are a few minor breaking changes, see this document.
New Functionality
- Added Cosserat rods to soft bodies. This is a stick constraint with an orientation that can be used to attach geometry. Can be used e.g. to simulate vegetation in a cheap way. See the new
SoftBodyCosseratRodConstraintTestdemo. - Added ability to drive hinge constraints with
Ragdoll::DriveToPoseUsingMotors. This also addsHingeConstraint::SetTargetOrientationBSwhich sets the target angle in body space. - Added
JPH_USE_EXTERNAL_PROFILEcmake option that allows overriding the behavior of the profile macros. - Added
SoftBodyCreationSettings::mFacesDoubleSidedwhich treats the faces of the soft body as double sided. This can be used to make e.g. flags double sided. - Added functions to get the
CharacterSettingsfrom aCharacterandCharacterVirtualSettingsfrom aCharacterVirtual. - Added support for compound shapes as character shape in
CharacterVirtual. - Added
BodyInterface::SetIsSensor/IsSensorfunctions.
Bug Fixes
- Fixed bug in
ManifoldBetweenTwoFaceswhich would not find the correct manifold in case face 1 had 3 or more vertices and face 2 only 2. E.g. for a box resting the long edge of a cylinder this would mean that only a single contact point was found instead of 2 (the other way around would work fine). - Fixed bug in
ConvexHullShape::CollideSoftBodyVerticeswhere the wrong edge could be reported as the closest edge. - Fixed bug in
PhysicsSystem::OptimizeBroadPhase. When calling this function after removing all bodies from thePhysicsSystem, the internal nodes would not be freed until bodies are added again. This could lead to running out of internal nodes in rare cases. - Fixed bug in
MeshShapeactive edge calculation which could mark edges of non-manifold meshes as inactive instead of active. - Fixed passing underestimate of penetration depth in
ContactListener::OnContactPersistedwhen the contact comes from the contact cache. QuadTreewill now fall back to the heap when running out of stack space during collision queries. Previously this would trigger an assert and some collisions would not be detected.- Fixed
BodyInterface::MoveKinematic,SetLinearVelocity,SetAngularVelocity,SetLinearAndAngularVelocity,AddLinearVelocity,AddLinearAndAngularVelocity,SetPositionRotationAndVelocityandSetMotionTypewhen body not added to the physics system yet. - Fixed UBSAN false positive error that detected a dirty trick in
SimShapeFilter. - WheelSettingsTV and WheelSettingsWV were not serializing their base class members.
- The remap tables in
SoftBodySharedSettings::OptimizationResultsmapped from new to old index instead of from old to new as was documented. The maps now behave as documented. - Fixed an issue where soft body bend constraints could be created with identical vertices. This led to an assert triggering.
- Fixed infinite recursion when colliding a
TriangleShapevs aTriangleShape. - 32-bit MinGW g++ doesn't call the correct overload for the new operator when a type is 16 bytes aligned. This could cause unaligned read access violations.
- Fixed compiling in double precision and fixed issues with floating point contraction that caused unit test failures on LoongArch architecture.
- Added an epsilon to the
CastRay/CastShapeearly out condition to avoid dividing by a very small number and overflowing to INF. This can cause a float overflow exception. - Fixed Samples requiring Vulkan extension
VK_EXT_device_address_binding_reportwithout checking if it is available. - Fixed Vulkan warning in Samples: VkSemaphore is being signaled by VkQueue but it may still be in use by VkSwapchainKHR.
- Fixed incorrect RTTI definition of
MotorcycleControllerSettingswhich led to the members ofWheeledVehicleControllerSettingsnot being serialized. - Implemented missing `
- Added Cosserat rods to soft bodies. This is a stick constraint with an orientation that can be used to attach geometry. Can be used e.g. to simulate vegetation in a cheap way. See the new
- v5.3.05.3.02025-03-15 · 2025-03-15 21:26 UTC
查看更新说明
There are a few minor breaking changes, see this document.
New functionality
Samples
- The Samples and JoltViewer can run on Linux using Vulkan. Make sure to install the Vulkan SDK before compiling (see:
Build/ubuntu24_install_vulkan_sdk.sh). - The Samples and JoltViewer can run on macOS using Metal.
MeshShape
MeshShapes of up to 110M triangles are possible now, but the actual maximum is very dependent on how the triangles in the mesh are connected.- Optimized creation of
MeshShape. Improves build speed by about 25% and reduces number of allocations by a factor of 1000. Allocations caused contention when building meshes from multiple threads. - Added
MeshShapeSettings::mBuildQualitywhich allows selecting between faster mesh creation or faster run time performance.
Character
- Added
OnContactPersisted,OnContactRemoved,OnCharacterContactPersistedandOnCharacterContactRemovedfunctions onCharacterContactListenerto better match the interface ofContactListener. - Every
CharacterVirtualnow has aCharacterID. This ID can be used to identify the character after removal and is used to make the simulation deterministic in case a character collides with multiple other virtual characters. - Added support for
CharacterVirtualto override the inner rigid body ID. This can be used to make the simulation deterministic in e.g. client/server setups.
Collision Detection
- Added
PhysicsSystem::SetSimShapeFilter. This allows filtering out collisions between sub shapes within a body and can for example be used to have a single body that contains a low detail simulation shape an a high detail collision query shape. An example of a body that's both a sensor and a rigid body can be found inContactListenerTest. - Added
PhysicsSystem::SetSimCollideBodyVsBody. This allows overriding the collision detection between two bodies. It can be used to only store the 1st hit for sensor collisions. This makes sensors cheaper if you only need to know if there is an overlap or not. An example can be found inSimCollideBodyVsBodyTest. - Added
ClosestHitPerBodyCollisionCollectorwhich will report the closest / deepest hit per body that the collision query collides with. - Added overridable
CollisionCollector::OnBodyEndthat is called after all hits for a body have been processed when collecting hits throughNarrowPhaseQuery.
New Platforms
- Added support for RISC-V, LoongArch and PowerPC (Little Endian) CPUs.
- Added support for WASM64.
Various
- Removed the use of
std::unordered_mapandstd::unordered_setand replaced them with our own implementation:UnorderedMapandUnorderedSet. - Added
MotionProperties::ScaleToMass. This lets you easily change the mass and inertia tensor of a body after creation. - Split up
Body::ApplyBuoyancyImpulseintoBody::GetSubmergedVolumeandBody::ApplyBuoyancyImpulse. This allows you to use the calculated submerged volume for other purposes. - Added binary serialization to
SkeletalAnimation. - Added the ability to add a sub shape at a specified index in a
MutableCompoundShaperather than at the end. - Added
STLLocalAllocatorwhich is an allocator that can be used in e.g. theArrayclass. It keeps a fixed size buffer for N elements and only when it runs out of space falls back to the heap. - Added the following constants on PhysicsSystem:
cMaxBodiesLimit,cMaxBodyPairsLimitandcMaxContactConstraintsLimit. These constants are the max allowable values forPhysicsSystem::Init. Exceeding these will trigger an assert and the system will clamp the values. Note that on a 32 bit system, you'll run out of memory before you reach these values.
Bug fixes
- Fixed bodies gaining more energy than intended due to restitution. E.g. A restitution of 1 could lead to bodies bouncing ever higher.
- `BodyInterface::AddForc
- The Samples and JoltViewer can run on Linux using Vulkan. Make sure to install the Vulkan SDK before compiling (see:
- v5.2.05.2.02024-11-03 · 2024-11-03 20:53 UTC
查看更新说明
There are a few minor breaking changes, see this document.
New functionality
- Added PlaneShape. An infinite plane. Negative half space is considered solid.
- Added TaperedCylinderShape. A cylinder with different top and bottom radii.
- Added EmptyShape. A shape that collides with nothing and that can be used as a placeholder or for dummy bodies.
- Use MeshShapeSettings::mPerTriangleUserData at about 25% memory increase to get per triangle user data through MeshShape::GetTriangleUserData
- Added
Shape::GetLeafShapeto be able to get a leaf shape given a sub shape ID - Added
HeightFieldShape::GetSubShapeCoordinatesto get the triangle coordinates of a particular sub shape ID - Split back face mode between convex/triangles for ray casts. This allows you to e.g. have meshes that do give back face hits while convex shapes don't.
- SoftBodyManifold now returns sensor contacts separately. Before this change, there was a limit of a single colliding body per soft body vertex. If the closest body happened to be a sensor this effectively disabled the collision with the world and caused artifacts. We can now also detect multiple sensor contacts per soft body and they are returned through a new interface
SoftBodyManifold::GetSensorContactBodyID. - Added support for running Jolt with ThreadSanitizer.
- Added support for using ScaledShape inside CharacterVirtual.
- Added ability to save/restore a simulation in parts using
StateRecorder::SetIsLastPart. Also addedStateRecorderFilter::ShouldRestoreContactto allow selective restoring of contacts. - Added
JPH_DEBUG_SYMBOL_FORMATcmake option. This allows switching from the default dwarf symbol format to e.g. the source-map format for emscripten, which speeds up compilation.
Bug fixes
- Fixed an issue where enhanced internal edge removal would throw away valid contacts when a dynamic compound shape is colliding with another mesh / box shape.
- Fixed an issue where the bounding volume of a HeightFieldShape was not properly adjusted when calling SetHeights leading to missed collisions.
- Workaround for CMake error
CMake Error: No output files for WriteBuild!when using the 'Ninja Multi-Config' generator. - When a height field was created where SampleCount / BlockSize is not a power of 2 and a soft body touched the right or bottom border of the height field, the application would crash.
- Fixed a link error
ld: error: undefined symbol: pthread_createon FreeBSD. - Fixed missing files ConfigurationString.h and SoftBodyUpdateContext.h when running
cmake --install. - Fixed various missing header files when running
cmake --installwhenENABLE_OBJECT_STREAM=OFF. - When using
cmake --installto install a shared library on Windows, the dll is installed in the 'bin' folder now. - Fixed cmake warning:
Policy CMP0177 is not set: install() DESTINATION paths are normalized. - Fixed
unresolved symbol '__emutls_v._ZN3JPH11PhysicsLock6sLocksE'when compiling Jolt as a shared library with MinGW. - Added workaround for issue where Firefox has problems with the
_mm_blendv_psintrinsic when compiling to WASM.
用户点评
登录用户的真实使用记录,可按版本和硬件筛选还没有人点评。第一个说出真实体验的人最有价值。
Jolt Physics
A multi core friendly rigid body physics and collision detection library. Suitable for games and VR applications. Used by Horizon Forbidden West and Death Stranding 2: On the Beach.
![]() |
|---|
| A YouTube video showing a ragdoll pile simulated with Jolt Physics. |
For more demos and videos go to the Samples section.
Design considerations
Why create yet another physics engine? Firstly, it has been a personal learning project. Secondly, I wanted to address some issues that I had with existing physics engines:
- Games do more than simulating physics. These things happen across multiple threads. We emphasize on concurrently accessing physics data outside of the main simulation update:
- Sections of the simulation can be loaded / unloaded in the background. We prepare a batch of physics bodies on a background thread without locking or affecting the simulation. We insert the batch into the simulation with a minimal impact on performance.
- Collision queries can run parallel to adding / removing or updating a body. If a change to a body happened on the same thread, the change will be immediately visible. If the change happened on another thread, the query will see a consistent before or after state. An alternative would be to have a read and write version of the world. This prevents changes from being visible immediately, so we avoid this.
- Collision queries can run parallel to the main physics simulation. We do a coarse check (broad phase query) before the simulation step and do fine checks (narrow phase query) in the background. This way, long running processes (like navigation mesh generation) can be spread out across multiple frames.
- Accidental wake up of bodies cause performance problems when loading / unloading content. Therefore, bodies will not automatically wake up when created. Neighboring bodies will not be woken up when bodies are removed. This can be triggered manually if desired.
- The simulation runs deterministically. You can replicate a simulation to a remote client by merely replicating the inputs to the simulation. Read the Deterministic Simulation section to understand the limits.
- We try to simulate behavior of rigid bodies in the real world but make approximations. Therefore, this library should mainly be used for games or VR simulations.
Features
- Simulation of rigid bodies of various shapes using continuous collision detection:
- Sphere
- Box
- Capsule
- Tapered-capsule
- Cylinder
- Tapered-cylinder
- Convex hull
- Plane
- Compound
- Mesh (triangle)
- Terrain (height field)
- Simulation of constraints between bodies:
- Fixed
- Point
- Distance (including springs)
- Hinge
- Slider (also called prismatic)
- Cone
- Rack and pinion
- Gear
- Pulley
- Smooth spline paths
- Swing-twist (for humanoid shoulders)
- 6 DOF
- Motors to drive the constraints.
- Collision detection:
- Casting rays.
- Testing shapes vs shapes.
- Casting a shape vs another shape.
- Broadphase only tests to quickly determine which objects may intersect.
- Sensors (trigger volumes).
- Animated ragdolls:
- Hard keying (kinematic only rigid bodies).
- Soft keying (setting velocities on dynamic rigid bodies).
- Driving constraint motors to an animated pose.
- Mapping a high detail (animation) skeleton onto a low detail (ragdoll) skeleton and vice versa.
- Game character simulation (capsule)
- Rigid body character. Moves during the physics simulation. Cheapest option and most accurate collision response between character and dynamic bodies.
- Virtual character. Does not have a rigid body in the simulation but simulates one using collision checks. Updated outside of the physics update for more control. Less accurate interaction with dynamic bodies.
- Vehicles
- Wheeled vehicles.
- Tracked vehicles.
- Motorcycles.
- Soft body simulation (e.g. a soft ball or piece of cloth).
- Edge constraints.
- Dihedral bend constraints.
- Cosserat rod constraints (an edge with an orientation that can be used to orient geometry, e.g. a plant leaf).
- Tetrahedron volume constraints.
- Long range attachment constraints (also called tethers).
- Limiting the simulation to stay within a certain range of a skinned vertex.
- Internal pressure.
- Collision with simulated rigid bodies.
- Collision tests against soft bodies.
- A strand based hair simulation running on GPU
- System is based on Cosserad rods.
- Can use long range attachment constraints to limit the stretch of hairs.
- Supports simulation (guide) and render (follow) hairs.
- Hair vs hair collision is handled by accumulating the average velocity in a grid and using those velocities to drive hairs.
- Supports collision with the environment, although it only supports ConvexHull and CompoundShapes at the moment.
- The roots of the hairs can be skinned to the scalp mesh.
- Water buoyancy calculations.
- An optional double precision mode that allows large worlds.
Supported platforms
- Windows x86/x64/ARM64
- Linux (tested on Ubuntu) x86/x64/ARM32/ARM64/RISC-V64/LoongArch64/PowerPC64LE
- FreeBSD
- Android x86/x64/ARM32/ARM64
- Platform Blue (a popular game console) x64
- macOS x64/ARM64
- iOS x64/ARM64
- MSYS2 MinGW64
- WebAssembly, see this separate project.
Required CPU features
- On x86/x64 the minimal requirements are SSE2. The library can be compiled using SSE4.1, SSE4.2, AVX, AVX2, or AVX512.
- On ARM64 (AArch64) the library uses NEON and is compatible with Armv8-A. On ARM32 (AArch32) it doesn't use any special CPU instructions.
Documentation
To get started, look at the HelloWorld example. A HelloWorld example using CMake FetchContent is also available to show how you can integrate Jolt Physics in a CMake project.
Every feature in Jolt has its own sample. Running the Samples application and browsing through the code is a great way to learn about the library!
To learn more about Jolt go to the latest Architecture and API documentation. Documentation for a specific release is also available.
Some algorithms used by Jolt are described in detail in my GDC 2022 talk: Architecting Jolt Physics for 'Horizon Forbidden West' (slides, slides with speaker notes, video).
Compiling
- Compiles with Visual Studio 2022+, Clang 16+ or GCC 12+.
- Uses C++ 17.
- Depends only on the standard template library.
- Doesn't use RTTI.
- Doesn't use exceptions.
If you want to run on Platform Blue you'll need to provide your own build environment and PlatformBlue.h due to NDA requirements. This file is available on the Platform Blue developer forum.
For build instructions go to the Build section. When upgrading from an older version of the library go to the Release Notes or API Changes sections.
Performance
If you're interested in how Jolt scales with multiple CPUs and compares to other physics engines, take a look at this document.
Folder structure
- Assets - This folder contains assets used by the TestFramework, Samples and JoltViewer.
- Build - Contains everything needed to build the library, see the Build section.
- Docs - Contains documentation for the library.
- HelloWorld - A simple application demonstrating how to use the Jolt Physics library.
- Jolt - All source code for the library is in this folder.
- JoltViewer - It is possible to record the output of the physics engine using the DebugRendererRecorder class (a .jor file), this folder contains the source code to an application that can visualize a recording. This is useful for e.g. visualizing the output of the PerformanceTest from different platforms. Currently available on Windows, macOS and Linux.
- PerformanceTest - Contains a simple application that runs a performance test and collects timing information.
- Samples - This contains the sample application, see the Samples section. Currently available on Windows, macOS and Linux.
- TestFramework - A rendering framework to visualize the results of the physics engine. Used by Samples and JoltViewer. Currently available on Windows, macOS and Linux.
- UnitTests - A set of unit tests to validate the behavior of the physics engine.
Bindings for other languages
- C here, here, here and here
- C#
- Java or Kotlin here and here
- JavaScript
- Rust
- Python
- Zig
- Jai, based on this bindings generator
- Nim
Integrations in other engines
- Godot
- Source Engine
- Unreal Plugin here and here
See a list of projects that use Jolt Physics here.
License
The project is distributed under the MIT license.
Contributions
All contributions are welcome! If you intend to make larger changes, please discuss first in the GitHub Discussion section. For non-trivial changes, we require that you agree to a Contributor Agreement. When you create a PR, CLA assistant will prompt you to sign it.
Note that all PRs will be squashed before merging, so there's no need to force-push to git to keep the history clean.


