NarraLeaf

Incompatible Changes

For complete changes, see the CHANGELOG.

0.23.0

  • A Sound's type is now SoundBusId (SoundType | (string & {})) rather than SoundType. SoundType is unchanged, still exported, and its three values still mean what they meant, so nothing that uses only those values needs to change — but a switch over a sound's type that relied on it being an exhaustive union of three now needs a default arm
  • Sound.voice(), Sound.bgm() and Sound.sound() default type instead of overwriting it. Sound.voice({src, type: "alice"}) used to silently produce a voice clip; it now produces one on the alice bus. Code that passed a type to a factory and depended on it being ignored will now be honoured
  • A Preference copies the defaults object it is handed rather than writing into it. Two Games in one process no longer share one settings object, and moving a slider no longer rewrites Game.DefaultPreference for the rest of the process. A host that mutated the shared object on purpose must now go through game.preference

0.22.0

  • LiveGame.playSound and a dialog line's voice start a clip at the Sound's configured volume rather than at full volume. Sound.voice({src, volume: 0.4}) played through either path used to sound at 1 and now sounds at 0.4. Callers that pass an explicit target are unaffected
  • Sound.play() on a bgm-typed clip no longer throws StaticScriptWarning. It logs a console.warn and plays. A story that relied on the throw to fail loudly at chain-build time now runs

0.20.0

  • The Chained* type aliases — ChainedControl, ChainedPersistent, and their siblings — were removed. They were @internal, so they never appeared in the emitted declarations, and the public signatures that used them now name the chained type directly: Control.do() returns Proxied<Control, Chained<LogicAction.Actions>>, Persistent.set() returns Proxied<Persistent<T>, Chained<LogicAction.Actions>>. No signature changed shape and no runtime behaviour moved

0.19.1

  • StackFrameSnapshot.branches is now StackSnapshot[] rather than an array of frame arrays, so a branch arrives whole — with its loop and tag — instead of being reduced to its frames. branches[i][0] becomes branches[i].frames[0]. The type is experimental and read-only, which is why it was corrected rather than duplicated into a parallel field

0.17.1

  • fastForward's reason gained "stalled". Runtime behaviour for the existing values is unchanged, but the return type is wider: an exhaustive switch over reason needs the extra arm to keep compiling. Hosts that ignore the result are unaffected
  • A fast-forward run can now end early on a step that cannot be skipped. Each suspended line is given options.stepTimeout ms (default 10000) to settle; a step that outlives it ends the run with "stalled" instead of continuing past it. Previously the run hung there and the promise settled neither way, so nothing that works today starts failing — but a host that treats any non-"menu" reason as success should now distinguish "stalled". Raise stepTimeout for a story that fast-forwards through long unskippable media

0.17.0

  • onPreloadComplete, oncePreloadComplete, whenPreloadComplete() and event:preloaded.complete now fire before the game is entered — while a menu may still be on screen — rather than after newGame() has mounted a scene. The entry scene is registered for preloading as soon as the story is loaded, which is the point of the release. Nothing fails to compile; the callback simply runs at a different moment
    • If you used it to gate a loading step, it now does its job better and needs no change
    • If you used it to mean "the game has content on screen", switch to onFirstSceneReady / whenFirstSceneReady(). Those are unchanged and still require a real mounted scene
    • See Preloading

0.16.0

The transition API was redesigned around two ideas: transition engines are instantiated with new and take a single options object, while the mask patterns they animate are built with the static factories on Mask and passed as the pattern option.

  • Dissolve and FadeIn no longer take positional arguments
    • new Dissolve(1000, easing)new Dissolve({duration: 1000, easing})
    • new FadeIn(500, [x, y], easing)new FadeIn({duration: 500, offset: [x, y], easing}) — note the parameter rename from startPos to offset
  • SoftWipe, SoftIris, and Blinds were removed; use Reveal with the matching pattern
    • new SoftWipe({duration, direction, feather})new Reveal({duration, pattern: Mask.wipe({direction, feather})})
    • new SoftIris({duration, center, feather})new Reveal({duration, pattern: Mask.iris({center, feather})})
    • new Blinds({duration, orientation, slats})new Reveal({duration, pattern: Mask.blinds({orientation, slats})})
  • MaskTransition was removed; its hard-edged clips are Reveal with a zero-feather pattern
    • MaskTransition.circle({duration, center})new Reveal({duration, pattern: Mask.iris({center, feather: 0})})
    • MaskTransition.wipe({duration, direction})new Reveal({duration, pattern: Mask.wipe({direction, feather: 0})})
  • ThroughColor's static factories were removed; it is now constructed with new and takes its geometry as a pattern
    • ThroughColor.fade({duration, color, hold})new ThroughColor({duration, color, hold})
    • ThroughColor.wipe({direction, feather, ...rest})new ThroughColor({...rest, pattern: Mask.wipe({direction, feather})})
    • ThroughColor.blinds({orientation, slats, ...rest})new ThroughColor({...rest, pattern: Mask.blinds({orientation, slats})})
    • ThroughColor.iris({center, feather, ...rest})new ThroughColor({...rest, pattern: Mask.iris({center, feather}), inverted: true}) — note the inverted: true: the classic iris-to-black closes rim-in, which is the pattern's inverted orientation
  • Removed option types: SoftWipeOptions, SoftIrisOptions, BlindsOptions, MaskTransitionCircleOptions, MaskTransitionWipeOptions, ThroughColorFadeOptions, ThroughColorWipeOptions, ThroughColorBlindsOptions, ThroughColorIrisOptions. New exported types: DissolveOptions, FadeInOptions, RevealOptions, ThroughColorOptions, ThroughColorUncover, MaskPattern, and the per-factory *PatternOptions types

0.13.0

  • SavedGame's store is now typed as SerializedNamespaceData instead of StorableData. It always carried the tagged form; only the declaration was wrong. The save format itself did not change, so existing saves keep loading — but code that read savedGame.game.store by hand and relied on the old declaration will now see the tagged shape it was actually getting all along
  • Saves written by 0.12.x and earlier load correctly again, with one exception: a save produced by saving after loading on an affected version has its values tagged twice on disk, which cannot be told apart from a value the game legitimately stored. Such saves are not repaired
  • image.darken(darkness, duration) now animates over duration instead of applying instantly. Previously the animation only ran when an easing was passed as well, and the duration was silently dropped otherwise. Pass duration of 0 for the old jump-in-place behavior

0.9.0

  • JumpConfig.unloadScene was removed

0.8.0

  • Displayable.scale is changed. Now it takes two parameters scaleX and scaleY instead of the previous single scale parameter

0.7.0

  • Router is deprecated, use LayoutRouter as a more powerful router
  • Page is refactored
  • game.config.skipKey and game.config.nextKey are deprecated, use game.keyMap instead

0.6.0

  • The game has completely transitioned from a single node currentAction to a StackModel. The model ensures that:
    • Awaitable is handled in an explicit way
    • Support for sub-stack model recursive calls
    • Full support for serialization/deserialization
    • Support for scenario operations to break the call stack
    • Better branching/merging operations
    • Less prone to state clutter when deserializing and undoing
    • Is a complete solution for nested operations
  • game.config.skipInterval is deprecated, use GamePreference.skipInterval instead

0.5.0

  • game.config.cps is deprecated, use GamePreference.cps instead
  • Menu GameElementHistory.selected may be null

0.4.0

  • game.config.elements.say.textInterval is deprecated, use game.config.elements.say.cps instead
  • game.config has been refactored, see GameConfig for more details
    • game.config.player is deprecated, use game.config instead
    • game.config.elements is deprecated, use game.config instead
    • game.config.elementStyles is deprecated, use game.config instead

0.3.0

  • NarraLeaf-React now requires React 19 or later
  • Image Config has changed:
    • the type of config.src should be a tag definition or a string
    • In tag-based image config, config.src as a resolver function is moved to config.src.resolve
    • Image can't be marked as wearable anymore, use image.wear or image.asWearableOf instead
  • These methods of Image has been changed:
    • setAppearance, setTags, setSrc -> char
    • applyTransform -> transform
    • wear is a new alias for addWearable
    • asWearableOf is a new alias for bindWearable
    • init, setPosition, dispose, copy are removed
    • IImageTransition is removed, use ImageTransition instead
    • Fade is removed, use Dissolve instead, which takes the same duration and easing
  • These methods of Text has been changed:
    • applyTransform -> transform
    • applyTransition is removed, applying transitions are still in planning
    • ITextTransition is removed, use TextTransition instead
  • These methods of Transform has been changed:
    • overwrite is removed
    • Transformer API is completely deprecated
  • These methods/properties of Scene has been changed:
    • activate, deactivate are removed, the game will manage the scene's lifecycle automatically
    • applyTransform is removed, use scene.background.transform instead
    • inherit is removed
    • requestImagePreload -> preloadImage
  • These methods of Sound has been changed:
    • use copy to create a new sound instance
    • play, stop and setVolume method can receive a duration parameter
    • fade is removed, use setVolume instead
  • In displayable elements, the transform states are separated from the element states
  • These changes are made to Sound config
    • sync and type are removed
    • use preload to use Howler.js's preload feature
    • use seek property to set the initial seek position
  • Scene's config now can't specify the invertY and invertX properties, use story config origin instead
  • Top, Center, Bottom, HBox, and VBox are deprecated, use PageRouter API instead
  • ITransitions are all deprecated, use Transition API instead
    • FontSizeTransition -> FontSize
    • BaseImageTransition -> ImageTransition
    • BaseTextTransition -> TextTransition

0.2.2

  • SceneConfig invertY is now true by default

0.2.0

  • Image constructor signature has changed. Now the first argument must be a config object.

0.1.2

  • game.config.player.width and game.config.player.height cannot be string anymore

On this page