Repository navigation
v0.15.0 - Cutting Room
This release adds camera groups: SequencerCamera plays cameras one after another, and MixingCamera mixes them by weight.
It also makes the API consistent across core, three.js and React, so it breaks a lot of names - the table below maps each old one to the new one.
✨ New Features
- Camera groups - one camera to klipp, made of child cameras:
SequencerCamera/<SequencerCamera>- shows its cameras one after another:instructions({ camera, hold, blend? }),loop,isFinished.MixingCamera/<MixingCamera>- mixes its cameras byweights.
klippState.create('manual')withklippState.setActive(state, name)- pick the active camera yourself.<Noise.ImpulseListener>.<VirtualCamera priority>is optional,0by default.<InputController target>takes the axis owner itself, not only a ref.- A drag can drive one axis:
axes: { x: 'pan' }. - Axis settings in class options:
new OrbitFollowBody(target, { radial: { damping: 0.15 } }). setFromPosition/setFromRotationonOrbitFollowBodyThreeandPanTiltAimThreetakeVector3/Quaternion.damping.start,damping.startVector3,impulseListener.update(out, params, now?).PanTiltOptions,PositionComposerOptions,RotationComposerOptions,InputAxisOptions.
⚠️ Breaking Changes
- Core types are exported only from
@pmndrs/klipp, not from/three,/reactor/dom.CameraControlsBodyThreecomes from@pmndrs/klipp/three/camera-controls. <Aim.PanTilt>:damping,maxSpeed,recentering,panRange,tiltRange,panWrap,tiltWrapmove intopan={{ ... }}andtilt={{ ... }}.maxSpeedofRotationComposerandRotateWithFollowTargetis in degrees per secondbindingModeis a string:'lockToTarget'instead ofBindingModes.lockToTarget.GroupFramingtakesaspectinstead ofviewportWidth/viewportHeight.new GroupFramingExtension(members, { positionMode })instead of a second argument.readTargetPose(out, target, withRotation, slot?)-slotis last and optional.damping.dampVector3anddamping.dampQuaterniontakeoutfirst.primeofpositionComposer,rotationComposerandrotateWithFollowTargettakes only the state;primeFrom()takes no argument.InputSourceMapping,InputAxisMappingandInputControllerConfigtake the axis type:InputControllerConfig<string>.
| Before | Now |
|---|---|
klipp.activeCameraId, liveCameraId, activeState |
activeCameraName, liveCameraName, activeCameraState |
klipp.subscribeActiveId, subscribeLiveId |
subscribeActiveCamera, subscribeLiveCamera |
klipp.setDefaultBlend(b), setCustomBlends(b) |
klipp.defaultBlend = b, klipp.customBlends = b |
blendFinished event { liveId } |
{ incoming } |
klipp.blendTargetId, hasEverActivated |
klipp.state.blend |
klipp.addCamera(name, options) |
klipp.add(new VirtualCamera(name, options)) |
KlippEvents, VirtualCameraEvents |
<Klipp.Events>, <VirtualCamera.Events> |
KlippEventsProps, VirtualCameraEventsProps |
CameraTransitionEventProps |
klippState.register(state, { id }) |
{ name } |
klippState activeId, customBlendFromId |
activeName, customBlendFromName |
klippState events activeIdChanged, liveIdChanged |
activeCameraChanged, liveCameraChanged |
blend.targetId, BlendState.liveId |
blend.targetName, liveName |
BlendDriver.liveId, blendTargetId |
liveName, blendTargetName |
DEFAULT_BLEND |
klippState.createParams().defaultBlend |
OrbitFollowAxisSettings |
InputAxisSettings |
TargetGroupPositionMode |
GroupPositionMode |
MouseButton |
MouseButtons |
InputSourceConfig, InputAxisSourceConfig, InputAxisPair |
InputSourceMapping<string>, InputAxisMapping<string>, { x, y } |
ConsumedInput.touchRotateDelta (radians) |
twistDelta (degrees) |
copyCameraStateFromCamera, applyCameraState |
readCameraState, writeCameraState |
CameraControlsOptions |
CameraControlsThreeOptions |
perlinNoise, PerlinNoise* types |
basicMultiChannelPerlin, BasicMultiChannelPerlin* |
panTilt.seed |
panTilt.setFromRotation |
Predictor.predictPositionDelta |
predictDelta |
ImpulseField.sampleAt |
sample |
DebugZone.className |
kind: 'deadZone', 'hardLimit', 'groupFraming' |
hasBlendHint(hints, flag) |
(hints & flag) !== 0 |
Also removed from the exports: isInputAxisOwner, isVector3Like, resolveVec3, resolveTargetSize, InputAxisOwnerContext (use <InputController target>), ImpulseClockSeconds (a number).
🐛 Bug Fixes
OrbitFollowwithrecenteringTarget: 'trackingTarget'recenters tohorizontal.center, measured from behind the target (0behind,180in front).- With
frameloop="demand", every Body, Aim, Extension and Noise component requests a frame when its props change or it unmounts. HardLockToTargetandLenswith damping ease in frominitialStateon the first activation.PanTiltAim.setFromRotationlands on the rotation while an axis is still easing, the short way around.<Aim.PanTilt>axes no longer share their defaultrangeandrecenteringobjects.TargetGroup.computeBoundsreturns-1when no member resolves.
What's Changed
- ci: publish canaries and tagged npm releases by @krispya in #121
- refactor!: API consistency review by @kvvasuu in #122
- Feat/groups by @kvvasuu in #123
- refactor!: name cameras by name in klippState and blend by @kvvasuu in #124
- refactor!: drop addCamera and duplicate exports by @kvvasuu in #125
Full Changelog: v0.14.0...v0.15.0