Live Studio
Change history for jp.lilium.livestudio.
[0.25.3] - 2026-07-22
Added
- Opening a project asks before discarding unsaved live-scene edits (Save / Don't Save / Cancel), instead of dropping them silently. The prompt is raised through
RemoteConfirmSystem, so it shows both on the machine and in the remote app that asked for the project — a cancelled "Save As" abandons the open rather than discarding the very edits the user just chose to keep.
Fixed
- Opening a project now leaves the app in the state a launch into that project would produce, instead of carrying the previously open project over.
OpenProjectreused the ordinary live-scene load, which only reloads the base Unity scene when the incoming scene targets a different one — so two projects sharing a base scene skipped the reload entirely, leaving the old project's loaded props/avatars in place and keeping every value the incoming (delta) scene file omits. Project-scoped settings were worse off: they are not in the scene file at all and are applied additively, so any setting the new project does not record kept the old project's value.LiveSceneManager.OpenProjectSceneresets every exposed object to its captured defaults and forces the base-scene reload before restoring. The project folder crawl also moved after the reset, so the previous project's enabled/loaded catalog entries — which the crawl deliberately never prunes — no longer survive the switch.
Changed
- The built-in asset catalog is no longer
AnimationClip-specific. Which asset types are baked out of theResourcesfolders now comes fromBuiltinAssetTypeRegistry, the built-in counterpart ofAssetTypeRegistry: a kind declares the Unity asset type it owns and theAssetBaseentry it lists as, so a package can add one without touching the baker or the runtime registry.BuiltinAssetCatalogstores a single entry list whose entries name their owning kind instead of one array per type;BuiltinAssetCatalogBuilderscans once per registered kind, classifies imports by asset type rather than by file extension (so a kind never enumerates the extensions its type can come from), and rebuilds once per editor load, which is what picks up a newly registered kind — no asset import announces one. The reference-resource behavior ofBuiltinAnimationAsset(no load/unload toggle, never pruned, never persisted) moved to a sharedBuiltinAssetBase, leaving each kind as its own exposed@type. Existing baked catalogs are rewritten in the new shape on the next editor load.
[0.25.2] - 2026-07-21
Fixed
- A child process started through
ChildProcessHostis now tied to the host's lifetime by a kill-on-close job object. Every graceful stop path ran from managed cleanup, so a host that died without unwinding (a crash, End task, the quit watchdog) orphaned Fusion and the Remote app, which went on holding their ports and locking build output.StartChildApplicationalso returns early when the process fails to start instead of falling through to use it. ExpressionEntry.weightno longer throws on the empty-named template instance that the array diff builds:FacialKeyrejects an empty custom name, and there is no expression slot to drive, so the property now reads0and ignores writes. The exception escapedwantsToQuit, and Unity then let the quit through without the unsaved-changes check ever running — which looks like a successful quit and is not.
Changed
- The render quality setting moved off the static
LiveSceneManagerclass intoRenderQuality, a serializableIExposedObject(likeStageManager). Whether the remote app's settings page shows the quality section is now decided by registration: the settingsNavigatePagelists theRenderQualityid, andNavigateObjectSelectorskips ids that resolve to nothing, so an app exposes quality control by putting aRenderQualityin aRemoteControlContainer(or the hostRemoteControlBehaviour) object list and hides it by leaving the instance out. TheLive Studio Systemprefab registers one by default.LiveSceneManager.quality/.qualityNames/.currentQualityIndex/.SetQualityare removed, and the persisted level moves fromLiveSceneManager.settings.jsontoRenderQuality.settings.json(the level resets to the project default once).
[0.25.0] - 2026-07-17
Added
AddSwitchAvatarOperationcreates an operation set that switches the active avatar, with the deck tile's full-frame background set to that avatar's thumbnail.DeckControlgains abackgroundAssetIdstored as a portable project-relative reference (resolved back byAvatarImageHandler), so a saved deck survives moving the project or opening it on another machine.InvokeFunctionOperationcan invoke exposed functions that take arguments and reach nested functions: it stores the positional call arguments as a JSON array (argsJson) plus an optionalpropertyPath(e.g. aStageManagerset element'sWarpTo), not just a no-argument function on the target.AddFunctionOperationgains trailing optionalargsJson/propertyPathparameters, keeping the existing no-argument overload source-compatible.VRCAvatarnow drives body animation, tracking gating, mesh visibility and the lower-body lock throughAvatarBodyDriver(PlayableGraph) likeVRCFTAvatar, so VRChat avatars gain untracked-part body-override clips and the lower-body pose lock. Viseme / voice and expression parameters are read and written through the wrapped controller playable.- Built-in animation asset catalog:
AnimationClips shipped inResourcesare baked into aBuiltinAssetCatalog(EditorBuiltinAssetCatalogBuilder) and surfaced asBuiltinAnimationAssetresources.BuiltinAssetRegistryregisters each clip inAssetRegistryby GUID eagerly and idempotently (play start, editor load, on demand), so persisted body-override references resolve synchronously on scene restore. Catalog entries are injected into the project asset list and markedisBuiltin, soExternalAssetManagernever prunes or persists them and removal is rejected. AvatarController's body-override slot now sources its candidates fromGET /api/assets?type=AnimationClip(built-inResourcesclips plus external*.anim.lsbbundles) instead of the inspector_bodyOverrideClipPresetsarray, which is removed.VRCFTAvatarexposes_bodyOverrideClipas a serialized field and forwards it onInitialize/OnValidate.AvatarExpressionConfig.syncBlinklevels both eye-blink weights to the smaller of the two. Some avatars have asymmetric blink-weight accuracy between the left and right eyes and blink lopsidedly; enabling this makes the eyes blink symmetrically.LiveStudioOrbitalFollow: a Body-stage Cinemachine component that orbits a single target on a sphere (yaw/pitch/distance, with position damping and a local-frame target offset), resolved in the camera's own parent frame so rotating the camera's parent rotates the whole orbit rig.OrbitalFollowCameraControllernow positions through it and drives a single tracking target for both position and aim.- The Studio Template scene ships with an
OrbitalFollowcamera out of the box.
Changed
- Cut per-frame GC and hitches along the Operation-driven property path:
SetPropertyOperationcaches its resolvedExposedProperty(self-healing on a failed typed read) and uses box-free typed accessors for its per-framebool/floatwrites instead of re-walkingFindPropertyand allocating element paths and component arrays every frame.AvatarControllercaches its expressions array (invalidated on avatar /AvatarItemchange) to avoid O(N^2) GC when resolving keyed-array paths, bumps the registry's keyed-collection generation fromInvalidateExpressionsso cached resolutions re-resolve after expression elements are rebuilt (preventing writes to stale keys), and narrowsOnPropertyChangedto reapply only the changed property instead of the full_PostSetupAvatar— which re-ran the T-pose / socket rebuild every frame and caused multi-millisecond hitches. CustomFacialKeyhashing is now allocation-free. - The Fusion UI Definition orders the capture page ahead of the license settings.
- Avatar attachment sockets created by
AvatarControllerare now prefixed withS_(S_Hips/S_Spine/S_Chest/S_Head/S_Neck/S_WristLeft/S_WristRight) so a bone of the same name can no longer shadow them; the name-based references were updated (PropAttachmentdefault socket, the bone-follower / look-at / orbital-cameraS_Headtarget). Props and cameras that referenced the old socket names need re-selecting.
Fixed
- The lower-body lock now honors a body-override clip's "Root Transform Position (Y)" offset (the humanoid muscle-clip
levelsetting).AvatarBodyDriverbaked the locked hip position and foot-IK goals withAnimationClip.SampleAnimationwhileapplyRootMotionwas disabled, which silently drops that offset, so a sitting clip authored with a Y offset (to sink the hips) locked at the un-offset height and floated — while a clip with a zero offset looked fine. The lock offset and foot goals are now re-sampled with root motion enabled so the clip's Y offset is applied; the base pose used off the lock path is unchanged. - A momentary deck button no longer intermittently misses its action on fast taps: press and release arrive as two REST calls, and when both collapsed within one
Updateframe the manager never observedheld=true, silently losing the release trigger.SetHeldnow latches a release pulse on the rising edge so it fires exactly once. - The lower-body lock no longer shakes the head from side to side on rigs whose hips parent carries a rotation (e.g. Blender Z-up armatures imported with X=-90). The root-yaw compensation was prepended to the hips local rotation, which turned the world yaw delta into roll; it is now applied as a world-space delta on the hips world rotation, independent of the rig's parent chain.
- The lower-body lock no longer clamps the legs fully straight with a degenerate knee axis on avatars whose
humanScaleis not 1. Foot IK goals were captured as raw root-local positions while the locked hip is humanScale-normalized, so the hip-to-foot distance changed and the clip's leg pose became unreachable. Goals are now captured relative to the sampled hips and rebased onto the normalized lock hip offset. - The lower-body lock height no longer shifts with avatar height:
AvatarBodyDriverlocks the hips to the override clip's hip position through a humanScale-normalized, root-relative offset applied in world space. QuitTerminationGuardnow arms a detached watchdog process on quitting instead of a managed watchdog thread, which dies with the Mono runtime before a late native teardown (WGI) wedge — this left the Player-built Fusion lingering after quit. The fire-time log, which can itself deadlock during teardown, is dropped.LookAtCameraControlleragain drives the LookAt target on its own under Cinemachine 3: it setsCustomLookAtTargetso the aim uses the assigned look-at target instead of silently falling back to the tracking target (Cinemachine 2 parity), and clears the flag on teardown.
[0.24.3] - 2026-07-09
Added
AvatarControllercan drive body parts the capture does not track with an overrideAnimationClip. The clip is chosen from Inspector presets or from an external animation bundle (*.anim.lsb, which packs several clips) via a unified asset key — a bare GUID for baked assets,file:<path>#<clip>for external ones — resolved lazily and re-applied after scene restore and REST writes so the selection survives the bundle's asynchronous load. VRM1 / VRCFT playback is supported.- A "lock lower body pose" toggle pins the hips and root to the capture anchor with foot IK, holding the lower body in place while the upper body keeps following the capture.
- Per-project session log: the Unity log is mirrored into
{project}/.livestudio/logas one file per session, alongside the native Player.log.ProjectPathsgainsGetLogDir/EnsureLogDirhelpers.
Changed
- Operation set manual hold and manual value now persist across scene reloads (previously both reset). On restore the edge baseline is seeded to the restored hold, so reloading a scene with a set left on no longer manufactures a rising edge that would re-fire the operation.
Fixed
- Avatar meshes no longer blink while the subject leaves the capture frustum. The avatar root's valid byte is now a body/face tracking bitmask (body = MediaPipe, face = ARKit) and visibility is asymmetric — hidden only when both signals drop, shown on the face rising edge — so the frame-to-frame body-validity beat can no longer flicker the meshes.
[0.24.2] - 2026-07-05
Added
- The editor gains a toolbar button to launch and close the Remote app, matching the runtime RemoteAppHost (same configured path / args and child-process handling).
LookAtCameraController(ICameraController) assigns a bone — resolved from aTransformRef(target owner name + bone name / path) — to a camera'sLookAttarget, re-resolving only when the reference changes or the avatar is swapped, so a look-at bone survives avatar reloads. OnlyLookAtis touched, leaving theTrackingtarget and any Aim component intact.BoneFollowercomponent drives its own transform to follow a bone resolved from aTransformRef, re-resolving on avatar swap. It bridges a swappable avatar bone to a Cinemachine camera authored in a separate stage / set bundle (outside the LiveStudio camera pipeline), where a direct cross-scene reference to the bone cannot survive the swap.AvatarControllergains an avatar animation layer override, letting a loaded avatar's layer be overridden per scene.ProjectManagerexposes selected / unselected camera-preview polling interval settings (per-project persist scope), controlling how often camera previews are refreshed.
Changed
- Value-mode Deck sliders now map their drag onto the source property's min/max range instead of always writing the raw normalized 0..1 value, so a slider bound to a property spanning e.g. 0..100 can drive the full range. The normalized value is retained internally so gauges and edge detection are unaffected.
- Loaded prop / avatar objects are now persisted through the live scene's top-level diff as the single source of truth. State whose owning asset has not finished loading is queued and bound once the asset arrives, and any entry that never binds during a session is preserved verbatim across a load→save cycle instead of being warned about and dropped.
Fixed
- Operation sets authored directly in a scene or prop bundle now have a stable id backfilled on init and restore. Previously they kept the default empty id, so every id-addressed function was a silent no-op and the set was skipped when rebuilding the input map.
- Multiple single-prefab props that shared the same internal AssetBundle CAB could collide when loaded concurrently ("same files already loaded"). Bundle opens are now serialized, and each built bundle is given a unique internal CAB seeded from its source asset GUID so props no longer share one.
- Loaded prop / avatar overrides (e.g. a prop moved from its authored position) are no longer lost when the live scene reloads. The load-complete re-baseline now preserves restore-applied overrides instead of folding the applied value back into the dirty-detection baseline.
[0.24.1] - 2026-06-30
Added
- Action sets can now be arranged on a Deck: a grid of push-button / toggle / slider controls, freely placed and editable from the remote app. The control type is chosen when a control is placed and is independent of the action set's input mode.
- Value-mode action sets gain a manual value override, so a slider control can drive a 0..1 value directly (throttled to the studio).
Changed
- The action "panel" concept was renamed to Deck throughout, and an action set's behaviour is now driven by a single control axis. Deck tile width is declared per control kind, missing deck panels are recreated automatically, and tile-layout fields are hidden from the generic remote editor.
Fixed
- Expression weights can now be read while the avatar is inactive.
KeyInputSource's control path is stored as a shadow field of its binding, so key bindings persist and resolve correctly.- The active live-scene path is re-resolved from startup state when entering play mode, so the last-opened scene restores reliably.
[0.24.0] - 2026-06-26
Added
- Action set / input binding system (
ActionManager/ActionSet/InputSource/ActionBase), editable from the remote app: bind a keyboard or gamepad input to an ordered list of actions (set an expression weight, switch avatar / stage, toggle a GameObject). Polymorphic input/actions use[SerializeReference]+[TypeSelector]; input modes are Button / Toggle / Value. Wired into theLive Studio Systemprefab. InvokeFunctionActionandSetPropertyActionback a generic "bind to key" affordance next to any[ExposedFunction]or bool/float control (addressed by stable id), replacing feature-specific bindings.- Mutually exclusive toggle groups for action sets: sets sharing a non-empty
groupwhose input is in Toggle mode behave as a radio group (turning one on clears the others; all-off is still allowed). SwitchStageActionperforms a complete stage switch (SwitchToSetByNameunloads the other loaded sets and loads the target on demand); the Stage page'sSetActiveSetkeeps its original non-exclusive selection behavior.AvatarChaircomponent for a chair prop the avatar sits on. It re-parents under theAvatarControllerso avatar root motion does not drag it, then makes its parts track the avatar's pelvis (Hips socket) relative to a recorded rest pose:swivel/reclinerotate a target transform about an authored local axis (hips yaw / pitch), andlateral/height/depthtranslate one along an axis (hips X / Y / Z). The rest pose is recorded via anActivateaction. Each axis (aChairAxis) has an operating range (min/max,0/0locks it), a deadzone that is the play/backlash between the source and the follow target (absorbs hips tremor), and damping (SmoothDampAnglefor rotation).- Per-project state and project-scoped settings: exposed members gain a persist scope (Scene / Project); project-scoped values are stored in per-class
{Class}.settings.json(screen output size/fullscreen/Spout and live-scene quality are now Project scope).StartupStateStoreremembers the last opened live scene per project (Settings/startup.json), andStartupSceneSwitcherredirects to it before the first scene load. - Two-tier (memory + file) thumbnail cache stored under a hidden
.livestudioproject folder (ProjectPaths).
Changed
- Breaking: the avatar-prop
AvatarPropcomponent was split into composable siblings: a new sharedProp(keeps the exposed name"Prop"; owns the socket follow + position/rotation/scale offsets) plus a behavior component.AvatarPropwas renamed toAvatarItem(the avatar→prop parameter bridge + expression driving); a[MovedFrom]keeps old type references resolving. Existing*.prop.lsbbundles carry only the old single component and therefore must be re-exported (a re-exported bundle root carries bothPropandAvatarItem); the live-scene"Prop"state key is unchanged. - Expression key bindings are now driven generically through the action system: a
SetPropertyActionwritesexpressions[name].weight(the data-driven expression slot), so the bespokeSetExpressionAction/ExpressionBindingSystemand the old/api/expressionsbind routes were removed. Existing expression key bindings must be re-created. - Shared
FormatHeaderunifies versioning across live-scene / project-settings / preset files (raw-JSON serialization, orphan prune). - Object presets (
.preset.json) now capture prop and avatar state as a delta with a lenient reader. - Button-mode one-shot actions (switch avatar / stage) now commit on key release instead of press (
ActionContext.triggered). - The
ActionManager,ExternalAssetManager, andStageManagersingletons are now hidden from the remote app's generic scene object list (HideInScene); they remain reachable through their dedicated pages.
[0.23.6] - 2026-06-23
Added
AvatarPropnow exposes ascaleOffset(Vector3, default1,1,1) that multiplies the prop's authored local scale, so an avatar-attached prop's size can be tuned from the remote app / inspector. It is applied every frame and persists across an unload/reload like the position/rotation offsets.
Changed
- Stage marks now warp the avatar through
StageManagerinstead of the standaloneAvatarStageController. EachSetBundleEntryexposes theStageMarklabels in its own set scene (the newmarksfield, scoped per set), andStageManager.WarpTo(setId, markLabel)moves the avatar's anchor to the named mark within that set's scene (an empty label warps to the origin).
Removed
- Breaking:
AvatarStageController(the "Avatar Placement" exposed object with theplace/availablePlacesdropdown of all loaded marks) was removed; warping is now per-set onStageManager.WarpTo(see above). It is also dropped from theLive Studio Systemprefab.
[0.23.5] - 2026-06-22
Changed
- Object preset files (
*.preset.json) now use thejp.lilium.remotecontrol.presetformat identifier with aformatVersionfield, aligned with the live-scene file format. The redundantsourceKindhint was dropped (it is derived from the source path).
Removed
- Backward-compatible reading of the legacy
prop.presetpreset format; presets saved before this change must be re-saved.
[0.23.1] - 2026-06-21
Fixed
- The Studio no longer reports unsaved changes on every launch (which blocked quit with an unsaved-changes dialog when a project folder contained files). Persisting the
ExternalAssetManagerasset array directly let the deferred project-folder crawl populate it after the live-scene save baseline was captured; the in-use-only persistence shadow is restored so the crawl-built catalog stays out of the saved/dirty state.
[0.23.0] - 2026-06-21
Added
ExternalAssetManager: a single runtime catalog that loads and unloads props, avatars and set bundles uniformly (replacing the oldPropManager). Avatar selection, prop loading and set-bundle management all flow through it.- Runtime avatar props: a
.prop.lsbbundle can be attached to an avatar at runtime, following a bone/socket throughAvatarProp. Socket attachment is now robust to the avatar's rig and scale, and a prop's exposed-object parameters and id persist across unload/reload. - Prop presets: a loaded prop's tweaked parameters can be saved as a
.preset.json(SaveAsPreset) and re-loaded as a new prop, storing only the delta from the prop's defaults. - Project asset catalog with live-scene assets and bundle thumbnails; exported
.prop.lsb/.avatar.lsbbundles embed a thumbnail used by the remote app's asset cards. - Avatar VRM thumbnail served over
/api/avatar/image?id=, extracted from the VRM's embedded thumbnail without a UniVRM dependency. - Cross-scene remote control: additively loaded set bundles expose their objects to the single persistent host server. New stage marks (
StageMark/StageMarkRegistry/AvatarStageController) warp the avatar to named marks (plus a built-in Zero origin) from the remote app, and the saved active scene is restored on load. - Adding an asset now imports it into the project:
AddAssetcopies the picked file into a kind-specific subfolder of the open project folder (Avatars/Props/Sets, resolved per asset kind, colliding names get a(n)suffix) and registers the in-project copy. A picked file already inside the project folder is registered in place without copying. Only the single picked file is copied for now. - A project folder is the home for all saved data: on first launch
Documents/<brand>/<project>is created and opened, it is used as the default Save As location for live scenes, and "Open Save Folder" opens it.
Changed
- The remote-control host and its managers now stay alive across base-scene reloads instead of being torn down and recreated, so remote connections and manager state survive scene switches; the Studio prefabs and template were reworked around this persistent host.
VRCFTAvatarexpression now flows throughExpressionResolver, and converted avatars auto-gain hand-gesture expressions.- Received poses are now time-interpolated between the two nearest received 60fps frames during the variable-fps render update (
AvatarAnimationSystem.Lerp), so the avatar advances smoothly and SpringBones no longer shiver on held frames. - Breaking: Renamed the scene-bundle concept to "set" and the world concept to "stage", aligning the vocabulary with virtual-production terms (a stage holds sets, props and marks). Set bundles are now exported as
.set.lsb;SceneBundleAsset→SetBundleAsset,SceneBundleLoader/LoadedSceneBundle→SetBundleLoader/LoadedSetBundle,SceneBundleExporter→SetBundleExporter(menu "Export Set Bundle (.set.lsb)"),LiveStudioBundle.SceneExtension/IsSceneBundle→SetExtension/IsSetBundle, andWorldManager→StageManager(exposed functionsAddSet/RemoveSet/SetActiveSet, exposed propertysets). The legacy.scene.lsbextension is still accepted on input (loaded as aSetBundleAsset), no longer produced on export. Saved live scenes referencing the old@typenames (e.g.SceneBundleAsset/WorldManager) are not migrated and must be re-saved; such unresolved entries now deserialize away instead of leaving a null hole.StageManagercarries[MovedFrom("WorldManager")]so in-scene[SerializeReference]wiring migrates automatically. ExternalAssetManagernow persists its asset array directly to the live scene; the project-folder crawl rebuilds the disabled catalog on load, so the separate persistence shadow was removed.SavedPathsderives its base directory from the configured brand name and organizes saved data into per-project folders, replacing the singleScenesubfolder and the standaloneLiveStudioPathsInitializer(folder setup now lives inProjectManager).
Fixed
ResetCameranow derives its yaw/position offset from the capture-camera channel instead of the pose-driven avatar root, so repeated resets are stable; a configurable camera height (default 1.5 m) keeps the virtual camera at eye level rather than dropping to the floor.- Arms Post Rig is now added only for
VRM1Avatar. - Stage/scene visibility and active state are restored correctly on startup, and the persistent active entry settles at restore so the save baseline matches the post-restore state (no false unsaved-changes prompt at quit).
- A runtime-loaded avatar re-applies its animation parameter overrides one frame after its
PlayableGraphbuilds, instead of reverting to the controller defaults;VRMAvatarSetupSystemskips adding a duplicate facial controller when anIAvataralready exists.
[0.22.0] - 2026-06-14
Added
- Scene bundle import: a
.scene.lsbAssetBundle can now be loaded additively at runtime. NewRuntimeSceneManagerandSceneBundleLoadercomponents plus a sharedBundleBuildUtility, withLiveStudioBundledetecting the compound extension so.scene.lsb(scene) and.avatar.lsb(avatar) bundles share one pipeline. CaptureCameraControllerexposes achannelIndexproperty (withCAMERA_CHANNELINDEXlocalization), so aCaptureCameraTrackercan choose which capture-camera channel (0 or 1) it follows.HumanoidPoseDatanow carries a per-bone tracking presence (bonePresences, 0..1).AvatarBodyDriver's pose job blends the mocap pose over the avatar's animation per bone by this weight: a bone with presence 1 takes the mocap rotation fully, presence 0 leaves the animation flowing through, and values in between slerp between the two. This lets untracked body parts keep playing theirAnimatorControlleranimation while tracked parts follow the mocap.
Changed
ExternalAvatarSource's file selector now filters the compound.avatar.lsbextension (was.lsb) to distinguish avatar bundles from.scene.lsb; the legacy.lsavatarextension is still accepted.- Avatar frames now carry multiple capture-camera channels per frame (one
CameraDataper channel), so the worldA / worldB cameras are conveyed independently. VRM1AvatarandVRCFTAvatarnow drive body animation through aPlayableGraph(new sharedAvatarBodyDriver) instead of writing the humanoid bone transforms directly every frame. An optionalAnimatorControlleron the avatar is wrapped into the graph: its animation (e.g. an idle or range-of-motion clip) plays through while tracking is lost and is overwritten by the mocap pose while tracking. Shared tracking-state handling, mesh visibility, and the avatar-build boilerplate were extracted intoAvatarBodyDriverandAvatarBuildNotifier.BuildAndNotify.
Fixed
VRM1Avatar/VRCFTAvatarnow resolve theirAnimatorlazily inBuildAvatar, which can run beforeStartduring a synchronous.lsavatarload and previously left the animator null and logged an error.AvatarBodyDrivernow disablesapplyRootMotionon the wrappedAnimator, so a controller's root motion no longer sinks the whole avatar to the floor (VRCFT avatars).
[0.21.3] - 2026-06-12
Changed
- The exposed
Light's shadow toggle now enables soft shadows (LightShadows.Soft) instead of hard shadows, both in the property setter and on deserialize, for smoother shadow edges.
[0.21.2] - 2026-06-11
Added
ChildProcessHost.RequestCloseAndReleaseposts WM_CLOSE to a windowed child without a quit signal and releases it immediately, without waiting for exit.
Changed
- Quitting Studio no longer blocks waiting for child processes to exit. The Fusion process is signaled to quit and released immediately (
RequestStopAndRelease), and the Remote app is asked to close (WM_CLOSE) and released immediately (RequestCloseAndRelease), instead of each blocking up to 5 seconds onWaitForExit. - The Studio build output folder and exe name are now derived from the project folder name, dropping the dedicated VRC build entry point and the App VRC build profile path.
Fixed
SkyboxBackgroundnow logs an error instead of propagating a null shader when the Skybox/Cubemap shader is stripped from a player build (it runs duringExposedObjectContainer.Initializeand must not throw).
[0.21.1] - 2026-06-09
Added
ExternalAvatarSourcecan now import avatars from AssetBundle files (.lsavatar) in addition to VRM, chosen automatically by file extension.
Changed
- Renamed
VRMAvatarSourcetoExternalAvatarSource(the former exposed name is preserved for existing scenes). The avatar load APIRequestLoadVRMwas renamed toRequestLoadacrossIAvatarService,AvatarController, andAvatarService. - Generalized the model file field label and scoped its help text to VRM-only guidance.
[0.21.0] - 2026-06-08
Fixed
- Windows builds could leave a lingering background process after quitting, caused by a native shutdown hang related to Windows.Gaming.Input. A watchdog (
QuitTerminationGuard) now force-terminates the process if graceful shutdown stalls.
[0.20.12] - 2026-06-04
Added
- Eye gaze is now delegated to the VRM10
LookAtcomponent, so the avatar's eyes follow the configured look-at target instead of being driven directly.
[0.20.11] - 2026-06-03
Added
ChildProcessQuitSignal: signals a specific child process (keyed by its PID) to quit gracefully via a Windows named event, so a windowless child can run its own save-on-quit instead of being hard-killed.- "Assets/Lilium Live Studio/Remove Missing Scripts" context-menu command that removes missing scripts from the selected prefab assets.
Changed
- Stopping a windowless child process now signals it to quit and returns immediately without waiting for it to exit (
ChildProcessHost.RequestStopAndRelease).
Fixed
- The package Readme inspector buttons (language toggle, section actions, Install) are now clickable even when the package is consumed as an immutable git/registry dependency.
[0.20.10] - 2026-06-02
Added
WindowsFirewallhelper that registers inbound UDP allow rules vianetsh. Rules are keyed by the listening port (not the program path), so a single rule survives the tool being relocated, reinstalled, or shipped from a different package-cache path. Elevation is requested only when the rule is missing.
[0.20.9] - 2026-06-02
Changed
- RemoteControl handlers are now registered per-instance with their routes declared in the constructor.
[0.19.1] - 2026-04-29
Added
- Initial release. Split out from
jp.lilium.virgo.studioto separate VTuber-app generic infrastructure (Camera / Lighting / Scene / Build / RemoteControl base / shared Localization) from VirgoMotion-specific motion reception and avatar control.