diff --git a/package.json b/package.json index e4763a5..c4e9950 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@types/react-dom": "16.9.4", "@types/react-redux": "^7.1.5", "@types/webpack-env": "^1.14.1", + "between.js": "^0.1.2-fix.2", "lodash": "^4.17.15", "qs": "^6.9.1", "react": "^0.0.0-experimental-38dd17ab9", diff --git a/src/App.css b/src/App.css index 1f8f529..1ce6bb5 100644 --- a/src/App.css +++ b/src/App.css @@ -38,13 +38,15 @@ } .sp-col { - display: block; - height: 80%; + display: flex; + height: 60%; overflow-y: scroll; border: 1px solid black; margin-left: .2vw; margin-right: .2vw; padding: .2vw; + flex-direction: column; + flex-wrap: nowrap; } .sp-main-col{ @@ -52,7 +54,7 @@ } .sp-col-inner { - height: 99%; + flex: 1; } .sp-track { @@ -70,7 +72,7 @@ } .sp-track-active { - background-color: #10c998; + background-color: #10c998 !important; } html, body, #root { @@ -120,6 +122,31 @@ button{ } .player div { - height: 16%; overflow-x: hidden; -} \ No newline at end of file +} + +.sp-player-button { + height: 2em; +} + +.sp-mixer-buttons { + display: flex; + flex-direction: row; + flex-wrap: nowrap; + position: relative; +} + +.sp-mixer-buttons-backdrop { + position: absolute; + top: 0; + left: 0; + height: 100%; + background-color: #78acf1; +} + +.sp-mixer-buttons button { + flex: 1; + background: transparent; + border: 1px solid black; + z-index: 100; +} diff --git a/src/lib/between.d.ts b/src/lib/between.d.ts new file mode 100644 index 0000000..a790d98 --- /dev/null +++ b/src/lib/between.d.ts @@ -0,0 +1,424 @@ +// Stolen from https://github.com/sasha240100/between.js/blob/master/types/Between.d.ts +// Declare your modules properly, people! + +declare module "between.js" { + /** + * Loop mode + */ + export type LoopMode = "repeat" | "bounce"; + export type EventEmmit = "start" | "update" | "complete"; + + /** + * A collection of easing methods defining ease-in ease-out curves. + */ + export interface Easing extends Function { + /** + * Linear easing. + * + * @class Easing.Linear + */ + Linear: { + /** + * Ease-in. + * + * @method Easing.Linear#In + * @param {number} k - The value to be tweened. + * @returns {number} k^2. + */ + None: Function; + }; + + /** + * Quadratic easing. + * + * @class Easing.Quadratic + */ + Quadratic: { + /** + * Ease-in. + * + * @method Easing.Quadratic#In + * @param {number} k - The value to be tweened. + * @returns {number} k^2. + */ + In: Function; + + /** + * Ease-out. + * + * @method Easing.Quadratic#Out + * @param {number} k - The value to be tweened. + * @returns {number} k* (2-k). + */ + Out: Function; + + /** + * Ease-in/out. + * + * @method Easing.Quadratic#InOut + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + InOut: Function; + }; + + /** + * Cubic easing. + * + * @class Easing.Cubic + */ + Cubic: { + /** + * Cubic ease-in. + * + * @method Easing.Cubic#In + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + In: Function; + + /** + * Cubic ease-out. + * + * @method Easing.Cubic#Out + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + Out: Function; + + /** + * Cubic ease-in/out. + * + * @method Easing.Cubic#InOut + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + InOut: Function; + }; + + /** + * Quartic easing. + * + * @class Easing.Quartic + */ + Quartic: { + /** + * Quartic ease-in. + * + * @method Easing.Quartic#In + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + In: Function; + + /** + * Quartic ease-out. + * + * @method Easing.Quartic#Out + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + Out: Function; + + /** + * Quartic ease-in/out. + * + * @method Easing.Quartic#InOut + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + InOut: Function; + }; + + /** + * Quintic easing. + * + * @class Easing.Quintic + */ + Quintic: { + /** + * Quintic ease-in. + * + * @method Easing.Quintic#In + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + In: Function; + + /** + * Quintic ease-out. + * + * @method Easing.Quintic#Out + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + Out: Function; + + /** + * Quintic ease-in/out. + * + * @method Easing.Quintic#InOut + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + InOut: Number; + }; + + /** + * Sinusoidal easing. + * + * @class Easing.Sinusoidal + */ + Sinusoidal: { + /** + * Sinusoidal ease-in. + * + * @method Easing.Sinusoidal#In + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + In: Function; + + /** + * Sinusoidal ease-out. + * + * @method Easing.Sinusoidal#Out + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + Out: Function; + + /** + * Sinusoidal ease-in/out. + * + * @method Easing.Sinusoidal#InOut + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + InOut: Function; + }; + + /** + * Exponential easing. + * + * @class Easing.Exponential + */ + Exponential: { + /** + * Exponential ease-in. + * + * @method Easing.Exponential#In + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + In: Function; + + /** + * Exponential ease-out. + * + * @method Easing.Exponential#Out + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + Out: Function; + + /** + * Exponential ease-in/out. + * + * @method Easing.Exponential#InOut + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + InOut: Function; + }; + + /** + * Circular easing. + * + * @class Easing.Circular + */ + Circular: { + /** + * Circular ease-in. + * + * @method Easing.Circular#In + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + In: Function; + + /** + * Circular ease-out. + * + * @method Easing.Circular#Out + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + Out: Function; + + /** + * Circular ease-in/out. + * + * @method Easing.Circular#InOut + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + InOut: Function; + }; + + /** + * Elastic easing. + * + * @class Easing.Elastic + */ + Elastic: { + /** + * Elastic ease-in. + * + * @method Easing.Elastic#In + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + In: Function; + + /** + * Elastic ease-out. + * + * @method Easing.Elastic#Out + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + Out: Function; + + /** + * Elastic ease-in/out. + * + * @method Easing.Elastic#InOut + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + InOut: Function; + }; + + /** + * Back easing. + * + * @class Easing.Back + */ + Back: { + /** + * Back ease-in. + * + * @method Easing.Back#In + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + In: Function; + + /** + * Back ease-out. + * + * @method Easing.Back#Out + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + Out: Function; + + /** + * Back ease-in/out. + * + * @method Easing.Back#InOut + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + InOut: Function; + }; + + /** + * Bounce easing. + * + * @class Easing.Bounce + */ + Bounce: { + /** + * Bounce ease-in. + * + * @method Easing.Bounce#In + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + In: Function; + + /** + * Bounce ease-out. + * + * @method Easing.Bounce#Out + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + Out: Function; + + /** + * Bounce ease-in/out. + * + * @method Easing.Bounce#InOut + * @param {number} k - The value to be tweened. + * @returns {number} The tweened value. + */ + InOut: Function; + }; + } + + export class Between { + /** + * Creates a new Between instance + * @param from start + * @param to end + */ + constructor( + from: Number | Object | [Number | Object], + to: Number | Object | [Number | Object] + ); + + /** + * Sets duration + * @param duration duration in ms + */ + time(duration: Number): this; + + /** + * Set loop mode and repeat times + * @param mode the loop mode + * @param repeatTime if not defined, then treats as endless + */ + loop(mode: LoopMode, repeatTime?: Number): this; + + /** + * Set easing function + * @param easing Easing type + */ + easing(easing: Easing | Function): this; + + /** + * Adds event listener + * @param eventName + * @param callback + */ + on(eventName: EventEmmit, callback: Function): this; + + /** + * Pauses + */ + pause(): this; + + /** + * Starts (if was paused) + */ + play(): this; + + /** + * Returns `true` if paused + */ + isPaused: boolean; + } +} diff --git a/src/mixer/state.ts b/src/mixer/state.ts new file mode 100644 index 0000000..00fb0f5 --- /dev/null +++ b/src/mixer/state.ts @@ -0,0 +1,209 @@ +import { createSlice, PayloadAction } from "@reduxjs/toolkit"; +import * as Between from "between.js"; +import { PlanItem } from "../showplanner/state"; +import { Track, MYRADIO_NON_API_BASE } from "../api"; +import { AppThunk } from "../store"; + +console.log(Between); + +const audioContext = new AudioContext(); +const playerSources: MediaElementAudioSourceNode[] = []; +const playerGains: GainNode[] = []; +const playerGainTweens: Between.Between[] = []; +// TODO +// const destination = audioContext.createWebcastSource(4096, 2); +const destination = audioContext.createDynamicsCompressor(); +destination.connect(audioContext.destination); + +type PlayerStateEnum = "playing" | "paused" | "stopped"; +type VolumePresetEnum = "off" | "bed" | "full"; + +interface PlayerState { + loadedItem: PlanItem | Track | null; + loading: boolean; + state: PlayerStateEnum; + volume: number; +} + +interface MixerState { + players: PlayerState[]; +} + +const mixerState = createSlice({ + name: "Player", + initialState: { + players: [ + { + loadedItem: null, + loading: false, + state: "stopped", + volume: 1 + }, + { + loadedItem: null, + loading: false, + state: "stopped", + volume: 1 + }, + { + loadedItem: null, + loading: false, + state: "stopped", + volume: 1 + } + ] + } as MixerState, + reducers: { + loadItem( + state, + action: PayloadAction<{ player: number; item: PlanItem | Track }> + ) { + state.players[action.payload.player].loadedItem = + action.payload.item; + state.players[action.payload.player].loading = true; + }, + itemLoadComplete(state, action: PayloadAction<{ player: number }>) { + state.players[action.payload.player].loading = false; + }, + setPlayerState( + state, + action: PayloadAction<{ player: number; state: PlayerStateEnum }> + ) { + state.players[action.payload.player].state = action.payload.state; + }, + setPlayerVolume( + state, + action: PayloadAction<{ player: number; volume: number }> + ) { + state.players[action.payload.player].volume = action.payload.volume; + } + } +}); + +export default mixerState.reducer; + +export const load = (player: number, item: PlanItem | Track): AppThunk => ( + dispatch, + getState +) => { + if (typeof playerSources[player] !== "undefined") { + if (!playerSources[player].mediaElement.paused) { + // already playing, don't kill playback + return; + } + } + dispatch(mixerState.actions.loadItem({ player, item })); + const el = new Audio(); + el.crossOrigin = "use-credentials"; + if ("album" in item) { + // track + el.src = + MYRADIO_NON_API_BASE + + "/NIPSWeb/secure_play?recordid=" + + item.album.recordid + + "&trackid=" + + item.trackid; + } else if ("type" in item && item.type == "aux") { + el.src = + MYRADIO_NON_API_BASE + + "/NIPSWeb/managed_play?managedid=" + + item.managedid; + } else { + throw new Error( + "Unsure how to handle this!\r\n\r\n" + JSON.stringify(item) + ); + } + el.oncanplay = () => { + dispatch(mixerState.actions.itemLoadComplete({ player })); + }; + el.load(); + const sauce = audioContext.createMediaElementSource(el); + const gain = audioContext.createGain(); + gain.gain.value = getState().mixer.players[player].volume; + sauce.connect(gain); + gain.connect(destination); + console.log("Connected to", destination); + playerSources[player] = sauce; + playerGains[player] = gain; +}; + +export const play = (player: number): AppThunk => dispatch => { + try { + console.log("PLAY YOU FASCIST") + playerSources[player].mediaElement.play(); + dispatch( + mixerState.actions.setPlayerState({ player, state: "playing" }) + ); + playerSources[player].mediaElement.addEventListener( + "ended", + function() { + dispatch( + mixerState.actions.setPlayerState({ + player, + state: "stopped" + }) + ); + } + ); + } catch { + console.log("nothing selected/loaded"); + } +}; + +export const pause = (player: number): AppThunk => dispatch => { + try { + if (playerSources[player].mediaElement.paused) { + playerSources[player].mediaElement.play(); + dispatch( + mixerState.actions.setPlayerState({ player, state: "playing" }) + ); + } else { + playerSources[player].mediaElement.pause(); + dispatch( + mixerState.actions.setPlayerState({ player, state: "paused" }) + ); + } + } catch { + console.log("nothing selected/loaded"); + } +}; + +export const stop = (player: number): AppThunk => dispatch => { + try { + playerSources[player].mediaElement.pause(); + playerSources[player].mediaElement.currentTime = 0; + dispatch( + mixerState.actions.setPlayerState({ player, state: "stopped" }) + ); + } catch { + console.log("nothing selected/loaded"); + } +}; + +export const setVolume = ( + player: number, + level: VolumePresetEnum +): AppThunk => (dispatch, getState) => { + let volume: number; + switch (level) { + case "off": + volume = 0; + break; + case "bed": + volume = 0.25; + break; + case "full": + volume = 1; + break; + } + const currentLevel = getState().mixer.players[player].volume; + playerGainTweens[player] = new (Between as any)(currentLevel, volume) + .on("update", (value: number) => { + console.log(value); + dispatch(mixerState.actions.setPlayerVolume({ player, volume })); + if (playerGains[player]) { + playerGains[player].gain.value = value; + } + }) + .time(1000); +}; diff --git a/src/showplanner/player/webcast.d.ts b/src/mixer/webcast.d.ts similarity index 100% rename from src/showplanner/player/webcast.d.ts rename to src/mixer/webcast.d.ts diff --git a/src/rootReducer.ts b/src/rootReducer.ts index 1f63b23..d0ec353 100644 --- a/src/rootReducer.ts +++ b/src/rootReducer.ts @@ -1,11 +1,11 @@ import { combineReducers } from "@reduxjs/toolkit"; import ShowplanReducer from "./showplanner/state"; -import PlayerReducer from "./showplanner/player/state"; +import MixerReducer from "./mixer/state"; const rootReducer = combineReducers({ showplan: ShowplanReducer, - player: PlayerReducer + mixer: MixerReducer }); export type RootState = ReturnType; diff --git a/src/showplanner/index.tsx b/src/showplanner/index.tsx index 6d7bcb6..fdd7030 100644 --- a/src/showplanner/index.tsx +++ b/src/showplanner/index.tsx @@ -31,23 +31,33 @@ import { removeItem } from "./state"; -import * as PlayerState from "./player/state"; +import * as PlayerState from "../mixer/state"; -import playLogo from '../assets/icons/play.svg' -import pauseLogo from '../assets/icons/pause.svg' -import stopLogo from '../assets/icons/stop.svg' +import playLogo from "../assets/icons/play.svg"; +import pauseLogo from "../assets/icons/pause.svg"; +import stopLogo from "../assets/icons/stop.svg"; const CML_CACHE: { [recordid_trackid: string]: Track } = {}; const TS_ITEM_MENU_ID = "SongMenu"; -function Item({ item: x, index, column }: { item: PlanItem | Track; index: number; column: number }) { +function Item({ + item: x, + index, + column +}: { + item: PlanItem | Track; + index: number; + column: number; +}) { const dispatch = useDispatch(); const id = itemId(x); const isReal = "timeslotitemid" in x; const isGhost = "ghostid" in x; - const playerState = useSelector((state: RootState) => state.player.players[column]); + const playerState = useSelector( + (state: RootState) => state.mixer.players[column] + ); function triggerClick() { if (column > -1) { @@ -61,12 +71,20 @@ function Item({ item: x, index, column }: { item: PlanItem | Track; index: numbe
- ({ id })}> + ({ id })} + > {x.title} {"artist" in x && " - " + x.artist} @@ -80,33 +98,43 @@ function Item({ item: x, index, column }: { item: PlanItem | Track; index: numbe } function Player({ id }: { id: number }) { - const playerState = useSelector((state: RootState) => state.player.players[id]); + const playerState = useSelector( + (state: RootState) => state.mixer.players[id] + ); const dispatch = useDispatch(); return ( -
- {playerState.loadedItem == null && (
No Media Selected
)} - {(playerState.loadedItem !== null && playerState.loading == false) && (
{playerState.loadedItem.title}
)} +
+ {playerState.loadedItem == null &&
No Media Selected
} + {playerState.loadedItem !== null && playerState.loading == false && ( +
{playerState.loadedItem.title}
+ )} {playerState.loading && LOADING} -
- - - +
+ + + +
+
+
+ + +
); @@ -129,7 +157,12 @@ function Column({ id, data }: { id: number; data: PlanItem[] }) { .filter(x => x.channel === id) .sort((a, b) => a.weight - b.weight) .map((x, index) => ( - + ))} {provided.placeholder}
@@ -184,28 +217,28 @@ function CentralMusicLibrary() { function LibraryColumn() { const [sauce, setSauce] = useState("None"); return ( -
- - {sauce === "CentralMusicLibrary" && } -
+
+ + {sauce === "CentralMusicLibrary" && } +
); } -function MixingInterface(){ +function MixingInterface() { const [sauce, setSauce] = useState("None"); return ( -
-

Mixing Interface

-
+
+

Mixing Interface

+
); } @@ -275,9 +308,12 @@ const Showplanner: React.FC<{ timeslotId: number }> = function({ timeslotId }) { } return (
-
+

baps3 ayy lmao

- +
{planSaving && Plan saving...} @@ -292,9 +328,9 @@ const Showplanner: React.FC<{ timeslotId: number }> = function({ timeslotId }) { -
- - +
+ +
diff --git a/src/showplanner/player/state.ts b/src/showplanner/player/state.ts deleted file mode 100644 index d9197fc..0000000 --- a/src/showplanner/player/state.ts +++ /dev/null @@ -1,126 +0,0 @@ -import "../../lib/webcast"; - -import { createSlice, PayloadAction } from "@reduxjs/toolkit"; -import { PlanItem } from "../state"; -import { Track, MYRADIO_NON_API_BASE } from "../../api"; -import { AppThunk } from "../../store"; - -/// - -const audioContext = new AudioContext(); -const playerSources: MediaElementAudioSourceNode[] = []; -const playerGains: GainNode[] = []; -// TODO -// const destination = audioContext.createWebcastSource(4096, 2); -const destination = audioContext.createDynamicsCompressor(); -destination.connect(audioContext.destination); - -type PlayerStateEnum = "playing" | "paused" | "stopped"; - -interface SinglePlayerState { - loadedItem: PlanItem | Track | null - loading: boolean; - state: PlayerStateEnum; -} - -interface PlayerState { - players: SinglePlayerState[]; -} - -const playerState = createSlice({ - name: "Player", - initialState: { - players: [{ - loadedItem: null, - loading: false, - state: "stopped" - }, { - loadedItem: null, - loading: false, - state: "stopped" - }, { - loadedItem: null, - loading: false, - state: "stopped" - }] - } as PlayerState, - reducers: { - loadItem(state, action: PayloadAction<{ player: number, item: PlanItem | Track }>) { - state.players[action.payload.player].loadedItem = action.payload.item - state.players[action.payload.player].loading = true; - }, - itemLoadComplete(state, action: PayloadAction<{ player: number}>) { - state.players[action.payload.player].loading = false; - }, - setPlayerState(state, action: PayloadAction<{ player: number, state: PlayerStateEnum }>) { - state.players[action.payload.player].state = action.payload.state; - } - } -}); - -export default playerState.reducer; - -export const load = (player: number, item: PlanItem | Track): AppThunk => dispatch => { - if (typeof playerSources[player] !== "undefined") { - if (!playerSources[player].mediaElement.paused) { - // already playing, don't kill playback - return; - } - } - dispatch(playerState.actions.loadItem({ player, item })); - const el = new Audio(); - el.crossOrigin = "use-credentials"; - if ("album" in item) { - // track - el.src = MYRADIO_NON_API_BASE + "/NIPSWeb/secure_play?recordid=" + item.album.recordid + "&trackid=" + item.trackid; - } else if ("type" in item && item.type == "aux") { - el.src = MYRADIO_NON_API_BASE + "/NIPSWeb/managed_play?managedid=" + item.managedid; - } else { - throw new Error("Unsure how to handle this!\r\n\r\n" + JSON.stringify(item)); - } - el.oncanplay = () => { - dispatch(playerState.actions.itemLoadComplete({ player })); - } - el.load(); - const sauce = audioContext.createMediaElementSource(el); - const gain = audioContext.createGain(); - sauce.connect(gain); - gain.connect(destination); - console.log("Connected to", destination); - playerSources[player] = sauce; - playerGains[player] = gain; -} - -export const play = (player: number): AppThunk => dispatch => { - try{ - playerSources[player].mediaElement.play(); - dispatch(playerState.actions.setPlayerState({ player, state: "playing" })); - playerSources[player].mediaElement.addEventListener("ended", function(){dispatch(playerState.actions.setPlayerState({ player, state: "stopped" }));}) - } catch { - console.log("nothing selected/loaded"); - } -}; - -export const pause = (player: number): AppThunk => dispatch => { - try{ - if (playerSources[player].mediaElement.paused) { - playerSources[player].mediaElement.play(); - dispatch(playerState.actions.setPlayerState({ player, state: "playing" })); - } else { - playerSources[player].mediaElement.pause(); - dispatch(playerState.actions.setPlayerState({ player, state: "paused" })); - } - } catch { - console.log("nothing selected/loaded"); - } -}; - -export const stop = (player: number): AppThunk => dispatch => { - try{ - playerSources[player].mediaElement.pause(); - playerSources[player].mediaElement.currentTime = 0; - dispatch(playerState.actions.setPlayerState({ player, state: "stopped" })); - } catch { - console.log("nothing selected/loaded"); - } -}; \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 230b29d..43ab5e2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2138,6 +2138,19 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" +between.js@^0.1.2-fix.2: + version "0.1.2-fix.2" + resolved "https://registry.yarnpkg.com/between.js/-/between.js-0.1.2-fix.2.tgz#3cdc2b728decf7fc1c3c66042afe98cbaedb3259" + integrity sha512-9rkmzYDM6fW6LV99qD9cF17IjRRIQrOFKnZYuR1W2vqPGJtc9Y3UGs+UH6FJ0xqNYv0i9wRu+ZSqG6gM1xX1eg== + dependencies: + color "^3.0.0" + color-string "^1.5.2" + easing-functions "^1.0.1" + lerp "^1.0.3" + minivents "^2.2.0" + raf "^3.4.0" + rollup-plugin-alias "^1.4.0" + big.js@^5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" @@ -3519,6 +3532,11 @@ duplexify@^3.4.2, duplexify@^3.6.0: readable-stream "^2.0.0" stream-shift "^1.0.0" +easing-functions@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/easing-functions/-/easing-functions-1.0.1.tgz#66eaadafb4593212b700e867553d876009848ef4" + integrity sha512-5eHZ+InobokmzyYTs3BtL+bNoKVQiDF1iQoh1FQ0pWNAhhgqA2/o9z4LX/G6fq0jWFu16LdAxidxQi/fnRqfdw== + ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -5991,6 +6009,11 @@ left-pad@^1.3.0: resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e" integrity sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA== +lerp@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/lerp/-/lerp-1.0.3.tgz#a18c8968f917896de15ccfcc28d55a6b731e776e" + integrity sha1-oYyJaPkXiW3hXM/MKNVaa3Med24= + leven@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" @@ -6364,6 +6387,11 @@ minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: safe-buffer "^5.1.2" yallist "^3.0.0" +minivents@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/minivents/-/minivents-2.2.0.tgz#559492edc04bc00b62168850af5b8ca06d5e088b" + integrity sha1-VZSS7cBLwAtiFohQr1uMoG1eCIs= + minizlib@^1.2.1: version "1.3.3" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" @@ -8091,7 +8119,7 @@ raf-schd@^4.0.2: resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.2.tgz#bd44c708188f2e84c810bf55fcea9231bcaed8a0" integrity sha512-VhlMZmGy6A6hrkJWHLNTGl5gtgMUm+xfGza6wbwnE914yeQ5Ybm18vgM734RZhMgfw4tacUrWseGZlpUrrakEQ== -raf@3.4.1: +raf@3.4.1, raf@^3.4.0: version "3.4.1" resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA== @@ -8721,6 +8749,13 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" +rollup-plugin-alias@^1.4.0: + version "1.5.2" + resolved "https://registry.yarnpkg.com/rollup-plugin-alias/-/rollup-plugin-alias-1.5.2.tgz#f15a1cc8ee0debf74ab5c2bb68a944a66b568411" + integrity sha512-ODeZXhTxpD48sfcYLAFc1BGrsXKDj7o1CSNH3uYbdK3o0NxyMmaQPTNgW+ko+am92DLC8QSTe4kyxTuEkI5S5w== + dependencies: + slash "^3.0.0" + rsvp@^4.8.4: version "4.8.5" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734"