What’s New in Scenic

This page describes what new features have been added in each version of Scenic, as well as any syntax changes which break backwards compatibility. Scenic uses semantic versioning, so a program written for Scenic 2.1 should also work in Scenic 2.5, but not necessarily in Scenic 3.0. You can run scenic --version to see which version of Scenic you are using.

Scenic 3.x

The Scenic 3.x series adds native support for 3D geometry, precise modeling of the shapes of objects, and temporal requirements. It also features a new parser enabling clearer error messages, greater language extensibility, and various improvements to the syntax.

See Porting to Scenic 3 for tools to help migrate existing 2D scenarios.

Scenic 3.0.0

Backwards-incompatible syntax changes:

  • Objects must be explicitly created using the new keyword, e.g. new Object at (1, 2) instead of the old Object at (1, 2). This removes an ambiguity in the Scenic grammar, and makes non-creation uses of class names like myClasses = [Car, Bicycle, Pedestrian] clearer.

  • Monitor definitions must include a parenthesized list of arguments, like behaviors: you should write monitor MyMonitor(): for example instead of the old monitor MyMonitor:. Furthermore, monitors are no longer automatically enforced in the scenario where they are defined: you must explicitly instantiate them with the new require monitor statement.

  • As the heading property is now derived from the 3D orientation (see below), it can no longer be set directly. Classes providing a default value for heading should instead provide a default value for parentOrientation. Code like with heading 30 deg should be replaced with the more idiomatic facing 30 deg.

Backwards-incompatible semantics changes:

  • Objects are no longer required to be visible from the ego by default. (The requireVisible property is now False by default.)

  • Visibility checks take occlusion into account by default (see below). The visible regions of objects are now 3D regions.

  • Checking containment of objects in regions is now precise (previously, Scenic only checked if all of the corners of the object were contained in the region).

  • While evaluating a precondition or invariant of a behavior or scenario, code that would cause the simulation to be rejected (such as sampling from an empty list) is now considered as simply making the precondition/invariant false.

  • The left of Object specifier and its variants now correctly take into account the dimensions of both the object being created and the given object (the implementation previously did not account for the latter, despite the documentation saying otherwise).

  • The offset by specifier now optionally specifies parentOrientation.

  • The visible and not visible specifiers now take into account occlusion and the shapes of objects. In previous versions, they only checked whether the center of the object was visible/not visible, ignoring occlusion.

Backwards-incompatible API changes:

  • The maxIterations argument of Simulator.simulate now has default value 1, rather than 100. A default value of 1 is the most reasonable in general since it means that when a simulation is rejected, a new scene will have to be generated (instead of trying many simulations from the same starting scene, which might well fail in the same way).

  • For simulator interface writers: the Simulator.createSimulation and Simulation APIs have changed; initial creation of objects is now done automatically, and other initialization must be done in the new Simulation.setup method. See scenic.core.simulators for details.

Major new features:

  • Scenic uses 3D geometry. Vectors now have 3 coordinates: if a third coordinate is not provided, it is assumed to be zero, so that scenarios taking place entirely in the z=0 plane will continue to work as before. Orientations of objects in space are represented by a new orientation property (internally a quaternion), which is computed by applying intrinsic yaw, pitch, and roll rotations, given by new properties by those names. These rotations are applied to the object’s parentOrientation, which by default aligns with the Scenic global coordinate system but is optionally specified by left of and similar specifiers; this makes it easy to orient an object with respect to another object. See the relevant section of the tutorial for examples.

  • Scenic models the precise shapes of objects, rather than simply using bounding boxes for collision detection and visibility checks. Objects have a new shape property (an instance of the Shape class) representing their shape; shapes can be created from standard 3D mesh formats such as STL.

  • Visibility checks now take occlusion into account as well as precise shapes of objects. This is done using raytracing: the number of rays can be controlled on a per-object basis using viewRayDensity and related properties.

  • The require statement accepts arbitrary properties in Linear Temporal Logic (not just the require always and require eventually forms previously allowed).

  • Sampled Scene objects can now be serialized to short sequences of bytes and restored later. Similarly, executed Simulation objects can be saved and replayed. See Storing Scenes/Simulations for Later Use for details.

  • Scenic syntax highlighters for Sublime Text, Visual Studio Code, and other TextMate-compatible editors are now available: see Getting Started with Scenic. For users of Pygments, the scenic package automatically installs a Pygments lexer (and associated style) for Scenic.

Minor new features:

  • It is no longer necessary to define an ego object. If no ego is defined, the egoObject attribute of a sampled Scene is None.

  • Syntax errors should now always indicate the correct part of the source code.

Scenic 2.x

The Scenic 2.x series is a major new version of Scenic which adds native support for dynamic scenarios, scenario composition, and more.

Scenic 2.1.0

Major new features:

  • Modular scenarios and ways to compose them together, introduced as a prototype in 2.0.0, are now finalized, with many fixes and improvements. See Composing Scenarios for an overview of the new syntax.

  • The record statement for recording values at every step of dynamic simulations (or only at the start/end).

  • A built-in Newtonian physics simulator for debugging dynamic scenarios without having to install an external simulator (see scenic.simulators.newtonian).

  • The interface to the Webots simulator has been greatly generalized, and now supports dynamic scenarios (see scenic.simulators.webots).

Minor new features:

  • You can now write require expr as name to give a name to a requirement; similarly for require always, termination conditions, etc.

  • Compatibility with Python 3.7 is restored. Scenic 2 now supports all versions of Python from 3.7 to 3.11.

Scenic 2.0.0

Backwards-incompatible syntax changes:

  • The interval notation (low, high) for uniform distributions has been removed: use Range(low, high) instead. As a result of this change, the usual Python syntax for tuples is now legal in Scenic.

  • The height property of Object, measuring its extent along the Y axis, has been renamed length to better match its intended use. The name height will be used again in a future version of Scenic with native support for 3D geometry.

Major new features:

  • Scenic now supports writing and executing dynamic scenarios, where agents take actions over time according to behaviors specified in Scenic. See Dynamic Scenarios for an overview of the new syntax.

  • An abstract Driving Domain allowing traffic scenarios to be written in a platform-agnostic way and executed in multiple simulators (in particular, both CARLA and LGSVL). This library includes functionality to parse road networks from standard formats (currently OpenDRIVE) and expose information about them for use in Scenic scenarios.

  • A much generalized and improved interface to CARLA. (Many thanks to the CARLA team for contributing this.)

  • An interface to the LGSVL driving simulator. (Many thanks to the LG team for helping develop this interface.)

Minor new features:

  • Operators and specifiers which take vectors as arguments will now accept tuples and lists of length 2; for example, you can write Object at (1, 2). The old syntax Object at 1@2 is still supported.

  • The model statement allows a scenario to specify which world model it uses, while being possible to override from the command line with the --model option.

  • Global parameters can be overridden from the command line using the --param option (e.g. to specify a different map to use for a scenario).

  • The unpacking operator * can now be used with Uniform to select a random element of a random list/tuple (e.g. lane = Uniform(*network.lanes); sec = Uniform(*lane.sections)).

  • The Python built-in function filter is now supported, and can be used along with unpacking as above to select a random element of a random list satisfying a given condition (see filter for an example).

(Many other minor features didn’t make it into this list.)