rive-app / rive-app/rive-runtime

Regression (runtime-v0.1.107): eager per-file ScriptingVM in File::import breaks deferred view-model binding

Open
#110 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C++
Stars
1.2k
Forks
121
PR merge metrics
No merged PRs in 30d

Description

Summary

Since runtime-v0.1.107, a script in a state machine that reads data-bound view-model properties throws attempt to index nil (and its effects never apply) when the host binds the view-model instance after loading the file via the CommandQueue. It worked on runtime-v0.1.106 and earlier.

Bisect

Built rive_render (headless CommandQueue host) against successive tags:

runtime result
v0.1.106 ✅ script runs, reads bound VM data correctly
v0.1.107 attempt to index nil on data-bound property access in the script
v0.1.127 ❌ same

Cause

src/command_server.cpp, CommandServer::processCommands() loadFile case, gained (v0.1.107):

#ifdef WITH_RIVE_SCRIPTING
    auto scriptingContext = std::make_unique<CPPRuntimeScriptingContext>(m_factory);
    scriptingContext->setRenderContext(m_factory);
    auto vm = make_rcp<ScriptingVM>(std::move(scriptingContext));
    rcp<rive::File> file = rive::File::import(rivBytes, m_factory, nullptr, m_fileAssetLoader, vm.get());
#else
    rcp<rive::File> file = rive::File::import(rivBytes, m_factory, nullptr, m_fileAssetLoader);
#endif

The per-file ScriptingVM is now created eagerly, inside File::import, so the file's script instances initialize during import. But a CommandQueue host typically binds view-model data after loadFile:

loadFile → instantiateArtboard/StateMachine → createDefaultInstance →
setViewModelInstance* → bindViewModelInstance → advance

So the script's first run happens against a view model that isn't bound yet. Reads of data-bound (incl. nested) properties resolve to nil. Even though the script re-runs when the VM is later bound, the data-bound targets it needs are unavailable at the point it errors.

Expected

A script should be able to observe view-model data that the host binds after a scripted import (the pre-v0.1.107 behavior), or there should be a documented way to defer/re-initialize the script VM after bindViewModelInstance.

Workaround

Importing without the eager VM (the pre-0.1.107 File::import(...) path) restores correct behavior — scripts then initialize lazily, after the view model is bound.

Environment

  • Headless CommandQueue/CommandServer host (Metal on macOS, Vulkan/SwiftShader on Linux), WITH_RIVE_SCRIPTING enabled.
  • Reproduces identically on macOS and Linux; not platform-specific.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in src/command_server.cpp, at CommandServer::processCommands() and its loadFile case, then trace the documented loadFile → instantiateArtboard/StateMachine → setViewModelInstance* → bindViewModelInstance → advance sequence. Compare the v0.1.107 eager ScriptingVM path with the pre-v0.1.107 File::import path and reproduce with a headless CommandQueue host. Done means a script can read bound, including nested, view-model data when binding occurs after import without attempting to index nil.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
65/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.