Commit Graph

5315 Commits

Author SHA1 Message Date
Matija Kecman b3ef7a8c2f Simplify MuJoCo Studio viewer selection and unify model flags.
This change removes the ViewerMode enum and instead infers whether to launch the Web Viewer or Native Viewer based on the graphics mode (gfx) setting. Specifically, setting gfx to "web" or "webgl" will now launch the Web Viewer (in future "webgpu" would also launch the Web Viewer).

Additionally, this unifies command-line flags across studio scripts and samples by replacing the --mjcf flag with --model (with positional argument fallback) and standardizing absl flags usage. --model is a better name since formats like .mjz and .mjb are also supported by this argument.

PiperOrigin-RevId: 959058940
Change-Id: If4e0ace664ddc6e45cb681d168679148e8c4901d
2026-08-04 09:14:07 -07:00
Haroon Qureshi 0a10860257 Classic rendering mode works with wayland now.
PiperOrigin-RevId: 959036941
Change-Id: I31231c644e8a535918e4ace5d44f84b9b7da78bc
2026-08-04 08:29:04 -07:00
Yuval Tassa 9553926158 Save flex node coordinates in the new nodecoord attribute.
Interpolated flexes with pinned nodes could not be reloaded after saving:
pinned nodes share their parent body, and their positions within it lived
only in mjsFlex.node, which had no MJCF attribute. On reload the pinned
nodes collapsed onto the parent body origin, degenerating the trilinear
interpolation grid ("flex grid rotation R0 is not orthonormal"). This
made model/flex/strain.xml and gripper_trilinear.xml fail to round-trip.

Add flex/nodecoord, real(3*nnode), the node analog of flex/vertex: local
node coordinates within the corresponding body frames. The reader picks
it up from the regenerated schema tables; the writer emits it with the
precision-aware WriteVector, since VectorToString ignores the XML
precision setting and truncating node coordinates to 6 digits while body
positions carry 17 fails the R0 orthonormality check at full precision.

Add a WritesPinnedFlexNodes round-trip regression test, and remove the
two write-read sweep exclusions documenting this bug. The removed
substring filter "strain" was also matching core_constraint, silently
excluding that entire testdata directory from the sweep; its ~40 models
are now covered and pass.

PiperOrigin-RevId: 959025281
Change-Id: I2fed28c01491c5a8431e813102a423d12b659911
2026-08-04 08:04:27 -07:00
Yuval Tassa 574b6bd6bf More schema-related cleanup.
- Declare every nonzero default; make the defaults cross-check total.
- Skip default-valued attributes in the hand-written writer paths.
- Fix type facts on hand-read elements, found by the dm_control diff.

PiperOrigin-RevId: 958999733
Change-Id: I3064ccc6ae1f049c20f273abc234cd02990a8b7e
2026-08-04 07:05:41 -07:00
Copybara-Service 10793e539e Merge pull request #3451 from smallquail:flex-geometric-stiffness
PiperOrigin-RevId: 958995742
Change-Id: Ibb60c3112b6dbc2373a5cd98df0477d639a5a001
2026-08-04 06:56:37 -07:00
Yuval Tassa 3d1d133a48 In the compile sample, copy the error message before deleting the spec that owns it.
PiperOrigin-RevId: 958970071
Change-Id: I1e8e367f26fde4778747020ab61f26105d70d690
2026-08-04 05:44:59 -07:00
Yuval Tassa 1e3c8f3f91 Add XSD schema.
Fixes #6, #3237, #3410

PiperOrigin-RevId: 958922477
Change-Id: Ia68e10be06d7c880b6a095edcc79572ee8b6f50e
2026-08-04 03:32:24 -07:00
Yuval Tassa 2544c34997 Clean up new schema code.
- Declare the full child lists of the body-alias elements.
- Verify read-table coverage: every generated row array must be consumed.
- Fix stale attribute facts on hand-read elements.

PiperOrigin-RevId: 958685667
Change-Id: I4a914f3136a5078eb8ca24aa4e162d55afafd923
2026-08-03 18:15:39 -07:00
Taylor Howell f848b185d3 update mjx make_data and put_data docstrings for njmax
PiperOrigin-RevId: 958526560
Change-Id: Iaeff307e4d09c9193134fc29689aeedfdcaa9d53
2026-08-03 12:49:29 -07:00
Kyle Bayes 0bfa4e984c Fix latent bug in multiccd so that we can never write more contacts than what the buffer space allows.
PiperOrigin-RevId: 958505449
Change-Id: I77cb1142405df5107be46ca0dbef6effc690028d
2026-08-03 12:07:00 -07:00
Taylor Howell 382af63dc3 update mjx for naccdmax
PiperOrigin-RevId: 958479874
Change-Id: If0f48f2f372955f2948cb286966f5fce52c3f0ba
2026-08-03 11:20:34 -07:00
Saran Tunyasuvunakool b0c3486249 Tweak URL printout in terminal when launching the web viewer.
PiperOrigin-RevId: 958422471
Change-Id: I2d637c615015915eb01b65bb0bad22749886a372
2026-08-03 09:41:25 -07:00
Yuval Tassa d33f297b56 Zero out stale lambda coordinate in S3D in GJK.
PiperOrigin-RevId: 958414972
Change-Id: Ia21f8959a990c18b9d67959be5b2adeb1d3fa1dd
2026-08-03 09:25:46 -07:00
Copybara-Service eb049fb287 Merge pull request #3450 from teerthsharma:topo/hullgraph-inverse-map
PiperOrigin-RevId: 958414730
Change-Id: I4a7f8fdde77513a3267e07e46a13144592e73ff0
2026-08-03 09:24:33 -07:00
Yuval Tassa 8a643f4e2b Format some more files in user/
PiperOrigin-RevId: 958383817
Change-Id: I17fcdbf32967ec5a5c4d2552823ef5100faaea3b
2026-08-03 08:17:01 -07:00
Alessio 5497994763 Add the geometric term to the flex stretch stiffness
K_stretch was the Gauss-Newton Hessian of the stretch force, not its Jacobian.
With elongation e_a = L_a^2 - L0_a^2 and force f = -sum_ab M_ab e_a grad(e_b)/2,

  K = 2 sum_ab M_ab (s_a d_a)(s_b d_b)^T + sum_a Me_a (Laplacian_a (x) I3)

and only the first term was there. The second is proportional to the edge
tension Me_a = sum_b M_ab e_b, so it vanishes at rest and grows with strain:
the operator was first-order correct and no more. Finite-differencing it
against -d(qfrc_passive)/dq on a mesh dilated by 5% gives 7.8% of the force
scale; with the term it is exact to roundoff.

Add only the tensile part. The geometric block is Me_a*[[I,-I],[-I,I]] over the
edge's two vertices, which is positive semi-definite exactly when Me_a >= 0; a
compressed edge would make K indefinite, and both consumers -- the CG
constraint solver and the PCG in mjd_effSolve -- require SPD. The clamp is
structural, so no eigendecomposition is needed, and it is confined to the
operator: mj_flexPassiveStretch keeps the full Me_a, so no force changes.

Both the matrix-free operator and the CSR assembly the effective metric builds
from are updated, since they must agree.

This changes how flexes with elastic2d="stretch" integrate under the implicit
integrators and the effective metric -- bag.xml moves, poncho.xml is
bit-identical because bending energy is quadratic and has no geometric term.
The interpolated-flex path still uses its Gauss-Newton approximation, which
FlexInterpDerivativesDeformed asserts.
2026-08-03 16:16:23 +01:00
Alessio Quaglino 7927e908a3 Fix flex bending frame transformation when parent body is rotated.
PiperOrigin-RevId: 958362895
Change-Id: I0f6ba12a441bd7daa54292bfe2c70f0d836b008d
2026-08-03 07:28:52 -07:00
Copybara-Service 2c8d7b565d Merge pull request #3252 from devshahofficial:devshahofficial/studio-filament-source-build
PiperOrigin-RevId: 958356099
Change-Id: If4e68babdc6c68d7dd05ced7197a1869db4a0625
2026-08-03 07:12:38 -07:00
teerthsharma 747d36da91 Remap convex hull graph ids with an inverse table
Signed-off-by: Teerth Sharma <teerths57@gmail.com>
2026-08-03 18:08:09 +05:30
Yuval Tassa b475bb6f36 Move schema related generated files into their own directory
PiperOrigin-RevId: 958296165
Change-Id: I48cacc72c7df5994f5f816489ba069a5813845a1
2026-08-03 04:23:56 -07:00
Yuval Tassa 5e99ca6cb8 Table-driven attribute writing: rebase the writer on the shared rows.
The writer consumes the same generated rows as the reader.
mjXWriter::WriteAttrTable drives the mechanical attributes of an
element from its mjXAttr rows: each bound field is compared against
the class default at the same offset -- the default object is the same
struct type, so the rows carry no comparison values -- and attributes
equal to their default are skipped. A null default object means the
element has no defaults, and every defined value is written.
Ranged-arity rows write with trailing-default trimming, which the
reader makes round-trip exact by refilling from the same default.
Call sites upcast to the private mjs base (the friend declarations
permit it; mjCMesh gains the friendship its siblings had); the
comparison object is def->X().spec, a freshly-defaulted struct for
the sections, or zero-initialized for size, whose spec defaults (-1,
auto) are resolved by compilation.

Converted: pair, geom, site, joint, camera, light, material, the
equality family, both tendon types (the fixed rows are the spatial
rows without appearance attributes -- exactly the tag difference), the
actuator, flex with its three sub-elements, mesh, skin, option, the
six visual sub-sections, statistic and size. The remnants keep names,
files, resolved reference strings (the mjC classes null their private
base's string pointers; resolved names live behind accessors), and the
writing=custom policies the schema declares: compile directives never
saved (fromto, springdamper, fitscale), type-dependent lengths and
attributes (sizes, joint pos/axis/limited, shellinertia), and
alternatives (mass/density, fovy-versus-intrinsics, the plugin-gated
gain/bias family). Compiler keeps its write-if-nonzero policy;
keyframe keeps its model-sized vectors.

Saved files are canonical: attributes follow schema declaration order
with remnants trailing, and sections follow the schema's dependency
order (statistic before visual, deformable before the contact and
equality sections that name flexes, tendon before the equality
constraints that name tendons, custom demoted to the data tail).
Uniform behavior fixes fall out: default-equal positionals are
dropped, dynprm is trimmed like every other ranged vector, and mesh
material -- read into the spec but never written -- now survives
save/load round trips. Changelog entries ride along.

Verified: full suite, doc_test, and the two-tier A/B harness --
saved XML reorders attributes, and every corpus model reloads to a
byte-identical binary.
PiperOrigin-RevId: 958255003
Change-Id: I5fe7346014450db88b2f3f8680a8f616f7d31266
2026-08-03 02:27:22 -07:00
Yuval Tassa 760477f406 Add .clang-format to user/, format user_composite
PiperOrigin-RevId: 958225464
Change-Id: Iad7eb52dbecf7585f98375c90863ca707c494590
2026-08-03 01:22:00 -07:00
Yuval Tassa 4278c7b0cd Table-driven attribute reading: rebase the reader on generated rows.
Every mechanical attribute read in MJCF now derives from mjcf.schema.
generate_read_table.py emits typed mjXAttr rows (mjcf_read_table.inc,
doc_test-gated) binding each attribute to its spec struct field; field
offsets are offsetof() expressions, so binding mistakes are compile
errors, and the field's C type -- parsed from the headers -- selects the
row kind, so mjtNum-versus-double is decided by the struct, not the
schema. mjXReader::ReadAttrTable is the generic loop; its static core
also serves the section parsers and records XML-authored fields via
mjs_setAuthored for attach conflict resolution. Row kinds cover
strings, string lists, numeric scalars and vectors (exact and ranged),
enums (int- and byte-width), bitwise flag sets, bools, unbounded typed
vectors, fixed char arrays, and identity constants declared by 'set'.
The rows are inline variables, and carry the writing=custom flag,
because the writer will share them.

The keyword maps the rows reference are generated too: the ~48
hand-written mjMap tables become mjcf_map.h, one map and size constant
per enum as C++17 inline variables, retiring the hand-maintained
extern block in xml_base.h. Map names follow the schema enum names
(fluid->fluidshape, TFAuto->FalseTrueAuto, FAuto->FalseAuto,
joint->jointtype, geom->geomtype, jac->jacobian); all maps are
key-order- and value-identical to the hand tables they replace, and
bool_map is hand-emitted (the bool type is built in, not a schema
enum).

The OneX() parsers reduce to genuine irregulars, schema-marked as
reading=custom: orientation alternatives, file attributes (VFS and
asset-dir context), the actuator shorthand remappings and per-type
input maps, springlength's one-value copy, mesh builtin construction,
hfield elevation, texture cube files, flexcomp seeding, the memory
suffix parse, and the flag bit families. All 41 sensors that are pure
identity-plus-references -- including the frame family and insidesite
-- dispatch through a generated tag table; frame-sensor
objtype/reftype vocabulary tightens from the full mju_str2Type
namespace to the documented body/xbody/geom/site/camera subset, so an
invalid keyword now fails at parse time instead of compile time. The
equality family and both tendon types read shared group rows; the
twelve actuator shorthands share the general rows, with per-tag
legality enforced by the schema check. Sections bind non-mjs structs,
the visual sub-sections reaching their anonymous sub-structs through
member paths declared by an element-level field= facet.

Latent irregularities surfaced by the migration and preserved via
schema declarations or remnants: key's name is set even when absent,
eulerseq and gridlayout are fixed char arrays (chars[n], arity in
characters), gridlayout's length-must-match-gridsize stays a
value-conditional remnant, and constructor-style elements (tendon
wraps, asset model, replicate, attach) are annotated as such -- their
attributes are arguments, not field writes.

Two coherence tests guard the schema against the C sources: every
schema enum constant must be a member of the C enum it claims, and
every C member must be a keyword, a count sentinel, or a documented
exemption; and generate_default_table.py emits one row per defaulted
attribute (mjcf_default_table.inc), compared by SchemaDefaultsTest
against a freshly-constructed spec -- the schema cannot disagree with
the C default-constructors without failing the suite.

Verified: doc_test regenerates and diffs every artifact; the full
suite; and an A/B harness compiling the model corpus against the
pre-migration reader -- saved XML and binary models are byte-identical.
PiperOrigin-RevId: 958075724
Change-Id: I9715fe4deeb438eec988fd5084d74ba8b466b10b
2026-08-02 17:24:45 -07:00
Yuval Tassa 790f8fac30 Generate the MJCF grammar table and enforce its constraints.
The hand-written MJCF[] table in xml_native_reader.cc is replaced by
mjcf_table.inc, emitted from mjcf.schema by generate_mjcf_table.py and
checked for freshness by doc_test. nMJCF is now self-sizing. The two
tables are identical as trees of (tag, cardinality, attribute-set);
within-row attribute order changes where the schema factors shared
groups and projects default-context rows, and top-level rows follow
the schema's dependency order -- neither affects validation, which is
set-based, nor XMLschema.rst, whose generator orders sections itself
(regenerated here, reading the .inc instead of the reader source).

The schema's constraint declarations become enforcement: the emitter
writes a companion MJCF_constraints[] array (row-indexed into MJCF[]),
and mjXSchema::Check evaluates each element's constraints after its
attribute check, with uniform messages derived from the declaration:
"at most one of 'fovy', 'sensorsize' can be specified", "attributes
'reftype', 'refname' must be specified together", and so on.
Multi-attribute bundles render as ('site1', 'site2').

Fifteen hand-written co-occurrence checks across fourteen elements are
deleted -- connect/weld semantics mixing and completeness, the actuator
transmission mutex, camera fovy/sensorsize, light directional/type,
inertial fullinertia-versus-orientation, rangefinder and the distance
family, contact's matching criteria, user-sensor pairing, the frame
family's reftype/refname, size memory exclusivities, mesh builtin
exclusions, and attach body/frame (newly declared). Tests assert the
uniform messages.

Two findings along the way: sensorsize-requires-resolution is a
value-level compiler rule (positive resolution), not a presence rule --
a presence constraint would be wrong and is not declared; and Size()'s
nstack/njmax range checks tested the spec value before assignment, so
they never validated the parsed value -- now they do.

Verified by compiling all 81 models in the model/ corpus.

PiperOrigin-RevId: 958064622
Change-Id: I802cf5c0aee08a62926e36a281320ff9e34c0668
2026-08-02 16:30:02 -07:00
Yuval Tassa 3f8db4c17a Add mjcf.schema and its declarative schema language.
The complete MJCF surface in one hand-maintained file: 144 elements, 8
shared attribute groups, 47 enums, 1,497 typed attributes with
defaults, the presence-constraint inventory previously visible only as
hand-written reader checks, and the save policies previously visible
only as hand-written writer logic.

The language is a small IDL: elements bound to their mjSpec structs,
typed attributes with arities and defaults, enum keyword sets with C
bindings, reusable and variant groups, explicit name/reference
namespaces (id<ns>/ref<ns>, following dm_control's
identifier/reference model), child cardinalities, presence constraints
(exclusive/together/requires/oneof over attribute bundles), bitwise
flag sets, identity constants (set field = CONST), fixed char arrays
(chars[n], arity counting characters), numeric range facets, and two
escape hatches: reading=custom (no typed binding is generated; both
reading and saving are hand-written) and writing=custom (the binding
drives the reader, the save policy is hand-written).
doc/generate/mjcf_schema.py is the dependency-free parser and semantic
validator; errors report file:line; 55 unit tests. The language is
documented by the cheat-sheet legend at the top of the schema file.

The schema was bootstrapped by extraction from the sources of record --
the MJCF[] table, the mjMap keyword tables, the ~660 ReadAttr*/MapValue
call sites, mjspec.h struct fields, and the default-constructors in
user_init.c and engine_init.c -- then hand-curated. Same-tag elements
that differ by context are distinct declarations carrying an xml=
facet; worldbody, frame and replicate carry alias=body, mirroring
mjXSchema::NameMatch. The top-level order is by dependency, what a
saved file should read like: front matter, declarations before use,
the tree, the sections that reference it, the data tail.
PiperOrigin-RevId: 958060695
Change-Id: Ie10fd9f0ef202a3626f4d635d02c8731a4d287df
2026-08-02 16:10:14 -07:00
Yuval Tassa fb07a9ca50 Fix missing contacts for deeply penetrating boxes.
When penetration exceeds a box's smallest half-size, the midpoint
between the contact surfaces can land outside both boxes. The outside-
box filter in mjc_BoxBox then removed every contact of the manifold,
returning nothing for a visibly overlapping pair, letting boxes fall
through each other. Fixes #1800.

If the filter would remove all contacts, restore the penetrating ones.
This is strictly additive: configurations where any contact survives
the filter are unchanged.

The removed midpoints are bitwise-identical to the witness midpoints
computed by mj_geomDistance for these configurations, so the positions
follow the engine-wide contact position convention; re-anchoring them
onto a box surface would not.

Fixes #1800

PiperOrigin-RevId: 957867315
Change-Id: Ia9c858661d4badeb2a832d25455e33402936011d
2026-08-02 01:34:59 -07:00
Yuval Tassa 8655446f25 Fix spurious deep contacts in box-box collision.
In the edge-edge path of the box-box collider, when line clipping yields
no points, the corner generators accept points whose projection
parameters are out of range and clamp them into the valid range. The
depth of such a point is the Euclidean distance between two unrelated
points, mixing lateral offset into penetration depth, and on the
penetrating side it is admitted with no margin check. For thin boxes
meeting edge-to-face within margin, this produced a contact with
penetration three orders of magnitude larger than the boxes' true
separation, exploding resting stacks.

No contact can penetrate deeper than the support-interval overlap along
the separating axis, which the SAT stage has already computed. Enforce
this bound on all points emitted by the edge-edge path. The bound
carries margin plus relative and size-scaled slack covering rounding
error: the depth of the deepest legitimate point is algebraically equal
to the bound, so an exact comparison would drop real contacts. The
slack is precision-dependent: in mjUSESINGLE builds the two
computations of the same overlap disagree by tens of ulps, and slack
calibrated for double precision rejects real single-precision contacts.

Differential fuzzing against the nativeccd oracle over 200k random
near-contact thin-box configurations, in both precisions: impossibly
deep contacts drop from 1018 to 4 (worst excess from 2.5x the bounding
diameter to 0.001x), with no legitimate shallow-penetration contact
lost.

PiperOrigin-RevId: 957628830
Change-Id: Iaa1f10742f91c55bf831296cba0936eb50ea09b0
2026-08-01 07:48:32 -07:00
Matija Kecman b389b28b87 Support parsing .mjz files in the Studio parser module
PiperOrigin-RevId: 957616406
Change-Id: I582d23039b4aec745e0525392c062102f4d9ae25
2026-08-01 06:47:01 -07:00
Copybara-Service 2bb152b77b Merge pull request #3445 from giusenso:fix/actuator-velocity-index
PiperOrigin-RevId: 957597256
Change-Id: I10a1c85fb49f00d60aa65d0cbdedc110423adb95
2026-08-01 05:10:55 -07:00
Yuval Tassa 279df98cd0 Add the pid actuator: setpoint inputs, integral action, slew rate limiting.
<pid kp kv|dampratio [ki imax] [slewmax]> is a PID controller with real position and velocity setpoint inputs on a single force output, plus an optional feedforward input. With a zero velocity setpoint it reproduces <position> bit-exactly; the input signature is any subset of [pos, vel, ff], selected with input="..." and recorded as mjtCtrlInput bits in
actuator_ctrlspec; absent setpoint inputs are fixed at zero, so the control vector contains no inert entries.

kp and kv are single-sourced in the affine bias parameters (biasprm[1,2]) with no gainprm mirror: every consumer of the position-servo shape
(dampratio conversion, inheritrange, qDeriv) reads one location, which is what makes the bit-exact <position> parity possible. Controller state uses dyntype 'pid' with slot-gated activations in the order [slew, integral], following the dcmotor slot idiom: slewmax (dynprm[1]) rate limits the effective position setpoint through an activation holding it;
ki (gainprm[0]) integrates the position error -- wrapped on rotational transmissions -- with anti-windup clamping of the integrand at imax (dynprm[0]). Both features require the pos input. Servo input unpacking is shared with the dcmotor controller (unpackServoInputs); per-input ranges are exposed as posrange/velrange/ffrange.

This subsumes the functionality of the mujoco.pid plugin with proper activation state: correct under all integrators, visible to keyframes, act sensors and reset. Migration: kp/ki/kd map to kp/ki/kv, plugin imax is in force units (divide by ki), slewmax carries over; the single ctrl becomes input="pos".

PiperOrigin-RevId: 957588898
Change-Id: Id2786836ca6e76f58e5b5cc8323fc23be0a53784
2026-08-01 04:28:43 -07:00
Yuval Tassa 7bc1aa9b05 Add Filament lighting and shadow features and fixes.
- Add a hidden directional light to Filament scenes with no lights to work around soft shadow blackout bug.
- Respect quality/shadowsize as default shadow map resolution.
- Interpret light/bulbradius in correct units for each shadow type and update XML reference docs.
- Support updating the shadow map resolution of live Filament lights.
- Clamp light intensities to non-negative values in the Filament debug panel.

PiperOrigin-RevId: 957305808
Change-Id: Ic7a3430aaa3b117be7fbb7ace836d68e54cdf65a
2026-07-31 13:28:01 -07:00
Matija Kecman 0ca53dacf8 Update SDL2 copybara transformations
PiperOrigin-RevId: 957294480
Change-Id: Ied7131cafe83b11379e275ab4287609674251db5
2026-07-31 13:04:33 -07:00
Yuval Tassa e295b31c60 Improve wireframe rendering support in Filament renderer and Studio.
- Draw complete wireframes in the Filament renderer.
- Bind the 'W' key to toggle the wireframe render flag in Studio.

PiperOrigin-RevId: 957230911
Change-Id: Ib583c81ddcfa834686c7cf01d2b12842479993ea
2026-07-31 11:00:38 -07:00
Matija Kecman 6c78c98418 MuJoCo Web Viewer: update code to support the web viewer
PiperOrigin-RevId: 957147035
Change-Id: Ibe5d68b2654a7faac23c297d4f492929209c078d
2026-07-31 08:09:38 -07:00
Matija Kecman a1e90c24b3 MuJoCo Web Viewer: top-level web_viewer.py component
PiperOrigin-RevId: 957119030
Change-Id: If6c8265dfa62f9a6378898644935ee335f3fa8b2
2026-07-31 08:09:05 -07:00
Matija Kecman f8344301e9 MuJoCo Web Viewer: server component
PiperOrigin-RevId: 957086932
Change-Id: Idcac876206a2df7e962481c12c2fc74ff9997948
2026-07-31 08:08:32 -07:00
Yuval Tassa e9197e1e9d Use logarithmic sliders in the object launcher.
Projectile parameters are positive scale factors, best adjusted
multiplicatively. Replace the input boxes with logarithmic sliders
spanning 0.1x to 10x the seeded default, which sits at the geometric
midpoint of the range; mass spans 0.1x to 100x since heavy projectiles
are a common want. Ctrl+Click still allows typing values outside the
slider range, and each slider gets a reset button restoring its
default. Adds an ImGui_SliderLog widget operating on mjtNum.

PiperOrigin-RevId: 957071873
Change-Id: Id46eae28f73308d98681ccbeb2764c949f98f9d9
2026-07-31 08:08:00 -07:00
Copybara-Service de26b05861 Merge pull request #3439 from smallquail:flex-metric-blocks
PiperOrigin-RevId: 957063540
Change-Id: I86e7b2ec92c7b2acd1f1f7140e3b8a7578c48dbf
2026-07-31 08:07:22 -07:00
Matija Kecman f1f52a92b8 Add headless EGL/OSMesa OpenGL UI context rendering for web viewer
PiperOrigin-RevId: 957060514
Change-Id: I8a0df22255c5a938d18e172c638a8c83dfe64b1b
2026-07-31 04:36:14 -07:00
Yuval Tassa 47e1b1bd1f Seed object launcher defaults from model statistics.
PiperOrigin-RevId: 957053250
Change-Id: Iba103877136c31bf1310f2b55bd8cfc5593a87ec
2026-07-31 04:14:10 -07:00
Yuval Tassa 0f90722c1a Arm the object launcher by opening its window.
The launch key binding was gated behind a checkbox because it stayed
active with the plugin window closed. Condition it on the window being
open instead: the arming state is visible, so the checkbox is redundant
and the press-proof chord can relax to plain Enter. Text fields and
dialogs are unaffected: plugin chords are not checked while ImGui
captures the keyboard, and built-in shortcuts dispatch first.

PiperOrigin-RevId: 956796864
Change-Id: I4e5b2bdcaafbcc1b1ba113dd37ef8314b3ade49e
2026-07-30 16:26:17 -07:00
Yuval Tassa 24297edfda Add close button to Studio plugin windows.
Plugin windows could only be closed from the Plugins menu. Pass the
plugin's active flag to ImGui::Begin so the window gets a close button
that writes the same persisted state as the menu toggle. Skip the
update callback while the window is collapsed.

PiperOrigin-RevId: 956795070
Change-Id: I61cb5c26e7af935b6bb296f1b89142a72b0daca1
2026-07-30 16:22:52 -07:00
Matija Kecman 4dd70d2367 MuJoCo Web Viewer: add web client containing code that runs in the browser
PiperOrigin-RevId: 956698568
Change-Id: Ia4bebcb25b488d255994018da03e9115187b890c
2026-07-30 13:17:48 -07:00
Haroon Qureshi 8b78378868 Add mjv_camera2GLCamera to mujoco.h.
PiperOrigin-RevId: 956698065
Change-Id: I36856d7142bb5e798c5a90c19609288ddd7c4aac
2026-07-30 13:16:37 -07:00
Yuval Tassa a3425c72a7 Ignore unsupported light types in the classic renderer.
The classic renderer supports only directional and spot lights, but initLights() set GL light colors for every scene light before dispatching on type, and the render passes enabled GL light slots without filtering. Since no position was ever set for unsupported types (mjLIGHT_POINT, mjLIGHT_IMAGE), OpenGL's default eye-space position turned them into phantom headlights with the model light's diffuse color, washing out the scene. A cast-shadow image light additionally triggered a full shadow pass with an unset light projection.

Filter all light setup and enable sites on a shared type predicate, so unsupported light types contribute nothing. The no-lights ambient fallback now applies when no supported lights are present.

PiperOrigin-RevId: 956696548
Change-Id: Ic29763df7f9330f21d94f14501ae2559fd460f2b
2026-07-30 13:13:42 -07:00
Taylor Howell b46d76683d Import Warp v1.15.0
PiperOrigin-RevId: 956678131
Change-Id: I09a672b7335a85a17c95773ffc29eb9272744986
2026-07-30 12:39:05 -07:00
Yuval Tassa 98ecadcdf2 Add reset buttons to Studio sliders.
Slider rows in the joints and controls tabs could only be reset through
a hidden right-click context menu. Replace it with a visible reset
button at the right edge of each row, disabled while the value is at
its reset target so the button column doubles as a modified indicator.
Rows split the remaining width equally between slider and label, and
labels clip at the button column. Adds an ImGui_ResetButton widget.

PiperOrigin-RevId: 956627705
Change-Id: I9c178f6cd1cc806c7ffd6f531acf7f2d470d9346
2026-07-30 11:10:26 -07:00
Haroon Qureshi e662350357 Simple window class for python.
PiperOrigin-RevId: 956544312
Change-Id: I52d0e2f555592bed3889f05a1406e7633eb6d468
2026-07-30 08:39:09 -07:00
Giuseppe Sensolini Arrà a670a6ac10 Merge branch 'google-deepmind:main' into fix/actuator-velocity-index 2026-07-30 16:53:10 +02:00
Haroon Qureshi 58a54ef474 Move resource provider registration into a separate library.
PiperOrigin-RevId: 956506812
Change-Id: I9acde018e282171f41e0f8c756cd02b39c35dc67
2026-07-30 07:19:08 -07:00