variabletime/bin/em/variabletime/web/js/theatre-play.js
themancalledjakob 18300baf46 add recorded to timeline
dependencies hashes:
openFrameworks d78075f4bca6be2a2533c6e51a75cc1f18404501
ofxMsdfgen e14da13d02c4dff04fb69d7923469f606924e6c3
ofxGPUFont d482bb7cbdf6b296fa4ab5abcf73fb5ff8c8b239
ofxVariableLab 0b5f9bdebc1e5550621957e73c040c258ec6317b
ofxProfiler a868e34fa1a79189dd4fbdede2938e308535e5e8
theatre 86d3e07f6f2c75fd6e08fca8c97e3617c9e23b18
2024-04-12 16:32:47 +02:00

838 lines
35 KiB
JavaScript

import '../theatre_modules/core-and-studio.js'
import {
downloadFile,
uploadFile,
verifyVariableTimeProject,
hashFromString,
clone,
getParents,
arraysEqual,
sequencialPromises,
getNestedProperty,
} from './utils.js';
const TheatrePlay = function(autoInit = false) {
//private
const {
core,
studio
} = Theatre;
let project = false;
const theatreObjects = {};
let theatrePanel = null;
let sequencePanelLeft = null;
const getSequencePanelLeft = () => {
sequencePanelLeft = tp.shadowRoot.querySelector('[data-testid="SequencePanel-Left"]');
return sequencePanelLeft;
};
const getPanel = () => {
if (theatrePanel === null) {
theatrePanel = tp.shadowRoot.querySelector('[data-testid="DetailPanel-Object"]');
}
return theatrePanel;
};
const setPanelClasses = () => {
const parents = getParents(getPanel().querySelector('[title^="obj.props."]'), getPanel())
const panelControlsWrapper = parents[parents.length - 3];
const panelWrapper = parents[parents.length - 2];
const panelMomWrapper = parents[parents.length - 1];
panelControlsWrapper.classList.add("panelControlsWrapper");
panelWrapper.classList.add("panelWrapper");
panelMomWrapper.classList.add("panelMomWrapper");
getPanel().classList.add('panel');
getPanel().setAttribute('id', 'panel');
};
const getPanelPropTitle = (propTitle) => {
const panel = getPanel();
let panelPropTitle = panel.querySelector(`[title="obj.props.${propTitle}"]`);
if (panelPropTitle !== null) {
return panelPropTitle;
}
panelPropTitle = panel.querySelector(`[title^="obj.props.${propTitle}"]`);
if (panelPropTitle !== null) {
return panelPropTitle.parentElement.parentElement;
}
return null;
}
const getPanelPropContainer = (panelPropTitle) => {
if (typeof panelPropTitle === 'string') {
panelPropTitle = getPanelPropTitle(panelPropTitle);
}
if (panelPropTitle === null) {
return null;
}
const panel = getPanel();
let panelControls = panel.querySelector('.panelControlsWrapper');
if (panelControls === null) {
setPanelClasses();
}
panelControls = panel.querySelector('.panelControlsWrapper');
if (panelControls === null) {
return null;
}
const parents = getParents(panelPropTitle, panelControls);
if (parents === null || parents.length < 1) {
return null;
}
return parents[parents.length - 1];
};
const getPropKeyframes = (layer, propPath) => {
if (!Array.isArray(propPath) || propPath.length <= 0) {
return false;
}
let prop = layer.theatreObject.props;
let value = layer.theatreObject.value;
for (let i = 0; i < propPath.length; i++) {
const p = propPath[i];
prop = prop[p];
value = value[p];
if (typeof value === 'undefined') {
return false;
}
}
return this.sheet.sequence.__experimental_getKeyframes(prop);
};
// wtf, this function was being written in one go
// without any errors. huh?
const getKeyframes = (layer, valuePath = []) => {
const keyframes = [];
const theatreValues = layer.theatreObject.value;
let value = theatreValues;
for (let i = 0; i < valuePath.length; i++) {
value = value[valuePath[i]];
if (typeof value === 'undefined') {
return false;
}
}
const isColor = valuePath.length > 0 &&
typeof value === 'object' &&
valuePath[valuePath.length - 1] === 'color';
if (typeof value === 'object' && !isColor) {
Object.keys(value).forEach((key) => {
const newValuePath = [...valuePath, ...[key]];
const subkeyframes = getKeyframes(layer, newValuePath);
if (subkeyframes !== false && subkeyframes.length > 0) {
for (let i = 0; i < subkeyframes.length; i++) {
keyframes.push(subkeyframes[i]);
}
}
});
} else {
const propKeyframes = getPropKeyframes(layer, valuePath);
if (propKeyframes.length > 0) {
keyframes.push({path: valuePath, keyframes: propKeyframes});
}
}
return keyframes;
};
const getSequenceButton = (path) => {
let t = getPanelPropTitle(Array.isArray(path) ? path.join('.') : path);
if (t === null) {
return null;
}
return t.parentElement.querySelector('[title="Sequence this prop"]');
};
const isSequenced = (path, layer = getLayer()) => {
if (!Array.isArray(path)) {
path = path.split('.');
}
const prop = getNestedProperty(layer.theatreObject.props, path);
return studio.__experimental.__experimental_isPropSequenced(prop);
};
const setSequenced = (path, sequenced = true, layer = getLayer()) => {
if (!Array.isArray(path)) {
path = path.split('.');
}
return new Promise((resolve) => {
if(isSequenced(path, layer) === sequenced) {
resolve(true);
} else {
const prop = getNestedProperty(layer.theatreObject.props, path);
if (sequenced) {
tp.studio.__experimental.__experimental_setPropAsSequenced(prop);
} else {
tp.studio.__experimental.__experimental_setPropAsStatic(prop);
}
let count = 0;
const interval = setInterval(() => {
if (isSequenced(path, layer) === sequenced) {
clearInterval(interval);
resolve(true);
} else if (count >= 10) {
clearInterval(interval);
resolve(false);
}
count++;
}, 10);
}
});
};
/*
* layer = getLayer()
* keyframes = [
* {
* path: ['fontVariationAxes','Weight'],
* keyframes: [
* {
* "id": "yHFP-HCINm", // not sure if used when sent back
* "position": 0,
* "connectedRight": true, // optional
* "handles": [ 0.5, 1, 0.5, 0 ], // optional
* "type": "bezier", // optional
* "value": 200
* }, ...
* ]
* }, ...
* ]
*/
const addKeyframes = (layer, keyframes) => {
return new Promise((resolve) => {
const promises = [];
keyframes.forEach((k) => {
promises.push(() => {
return new Promise((subResolve) => {
let prop = layer.theatreObject.props;
for (let i = 0; i < k.path.length; i++) {
prop = prop[k.path[i]];
}
setSequenced(k.path, true, layer).then(() => {
tp.studio.transaction(({
__experimental_addKeyframes
}) => {
__experimental_addKeyframes(prop, k.keyframes);
});
subResolve();
});
});
});
});
sequencialPromises(promises, resolve);
});
};
// NOTE: instead of setting proptitle static and then sequenced again,
// we could simply delete all keyframes. but hey, pfff...
const setKeyframes = (layer, keyframes) => {
return new Promise((resolve) => {
if (!Array.isArray(keyframes)) {
resolve(false);
return false;
}
const promises = [];
let waitify = false;
keyframes.forEach((k) => {
const propTitle = k.path.join('.');
if (isSequenced(propTitle, layer)) {
waitify = true;
promises.push(() => {
return new Promise((subResolve) => {
setSequenced(propTitle, false, layer)
.then(() => {
subResolve();
});
});
});
}
});
sequencialPromises(promises, () => {
const timeout_ms = waitify ? 1000 : 0;
setTimeout(() => {
addKeyframes(layer, keyframes)
.then(resolve);
}, timeout_ms);
});
});
};
const friendlySequenceNames = () => {
const sequencePanelLeft = tp.getSequencePanelLeft();
let doItAgain = true;
if (sequencePanelLeft !== null) {
const titles = sequencePanelLeft.querySelectorAll('[data-testid="SequencePanel-Title"]');
const propTitles = sequencePanelLeft.querySelectorAll('[data-testid="SequencePanel-PropTitle"]');
const allTitles = [...[...titles], ...[...propTitles]];
if (allTitles.length > 0) {
allTitles.forEach((title) => {
// NOTE: should we have the same artboard and layer friendlyName,
// the layer friendlyName will be picked
Object.keys(config.layer.friendlyNames).forEach((key) => {
if (title.innerHTML === key) {
title.innerHTML = config.layer.friendlyNames[key];
}
});
Object.keys(config.artboard.friendlyNames).forEach((key) => {
if (title.innerHTML === key) {
title.innerHTML = config.artboard.friendlyNames[key];
}
});
});
}
doItAgain = false;
}
if (doItAgain) {
setTimeout(() => {
friendlySequenceNames();
}, 1000);
}
};
//public
this.setSequenced = setSequenced;
this.friendlySequenceNames = friendlySequenceNames;
this.getKeyframes = getKeyframes;
this.addKeyframes = addKeyframes;
this.setKeyframes = setKeyframes;
this.theatreObjects = theatreObjects;
this.addObject = (name, props, onValuesChange) => {
const obj = this.sheet.object(name, props);
const listener = obj.onValuesChange(onValuesChange);
theatreObjects[name] = {
obj,
listener
};
return obj;
};
this.changeObject = (name, props) => {
this.sheet.object(name, props, {
reconfigure: true
});
};
this.removeObject = (name) => {
// detach listener
// yeah, it looks weird, but this is how it is described
// https://www.theatrejs.com/docs/latest/manual/objects#detaching-objects
theatreObjects[name].listener();
// make sure object is DELETED (or is it?)
studio.transaction(({unset}) => unset(theatreObjects[name].obj.props))
// detach object
this.sheet.detachObject(name);
// make sure object is DELETED (possibly is)
tp.studio.transaction((api) => {
api.__experimental_forgetObject(theatreObjects[name].obj);
});
// remove object from objects list
delete theatreObjects[name];
};
this.isSequenced = isSequenced;
this.getSequenceButton = getSequenceButton;
this.getSequencePanelLeft = getSequencePanelLeft;
this.getPanel = getPanel;
this.getPanelPropTitle = getPanelPropTitle;
this.getPanelPropContainer = getPanelPropContainer;
this.setPanelClasses = setPanelClasses;
this.findInjectPanels = () => {
const id = project.address.projectId;
{ // hierarchy panel
const panel = tp.shadowRoot.querySelector(`.layerMover${id}`);
if (panel !== null) {
if (panel.querySelector('addLayerButton') !== null) {
panel.querySelector('addLayerButton').remove();
}
const addLayerButton = document.createElement('div');
addLayerButton.classList.add('addLayerButton');
addLayerButton.innerHTML = `<img src="/web/assets/add_layer.svg" />`;
addLayerButton.addEventListener('click', (clickEvent) => {
window.addLayer();
});
panel.append(addLayerButton);
}
}
};
this.addShadowCss = () => {
if (this.shadowRoot.querySelector(`#tpShadowCss`) === null) {
this.shadowRoot.insertBefore(Picker.StyleElement.cloneNode(true), this.shadowRoot.querySelector('#pointer-root'));
let style = document.createElement("link");
style.setAttribute('id', 'tpShadowCss');
style.setAttribute('rel', 'stylesheet');
style.setAttribute('href', '/web/css/theatre.css');
this.shadowRoot.insertBefore(style, this.shadowRoot.querySelector('#pointer-root'));
}
};
const waitingForShadowRoot = (callback) => {
let studioRoot = document.getElementById('theatrejs-studio-root');
if (studioRoot !== null && studioRoot.shadowRoot !== null) {
callback();
} else {
setTimeout(() => {
waitingForShadowRoot(callback);
}, 10);
}
};
this.addUserFont = (previousName = "", filePath = "") => {
return new Promise((resolve) => {
const fileName = filePath.split("/").reverse().shift(); // basename
let uploadFontButton = document.createElement('div');
let uploadFontButtonContainer = document.createElement('div');
uploadFontButton.classList.add('upload_font_button');
uploadFontButtonContainer.classList.add('upload_font_button_container');
uploadFontButton.innerHTML = "upload font " +
(previousName === "" ? "" : `(${previousName})`);
uploadFontButton.style.cursor = 'pointer';
uploadFontButtonContainer.append(uploadFontButton);
document.getElementById('body').append(uploadFontButtonContainer);
uploadFontButton.addEventListener('click', () => {
uploadFontButtonContainer.remove();
uploadFile('font')
.then((fontFile) => {
if (fileName !== "") {
fontFile.name = fileName;
}
moduleFS
.save(fontFile)
.then(() => {
resolve(fontFile);
})
});
});
});
};
this.possiblyAskForFontsPromise = (vt_project) => {
return new Promise((resolve) => {
if (vt_project.fontsHashMap !== false) {
this.possiblyAskForFonts(vt_project, resolve);
} else {
resolve(vt_project);
}
});
};
this.projectUsesFont = (vt_project, hash) => {
const layerKeys = Object.keys(vt_project
.theatre
.sheetsById
.mainSheet
.staticOverrides
.byObject);
for (let l = 0; l < layerKeys.length; l++) {
if (vt_project
.theatre
.sheetsById
.mainSheet
.staticOverrides
.byObject[layerKeys[l]].fontFamily === hash) {
return true;
} else {
//console.log(hash, "not used by ", vt_project);
}
}
return false;
};
this.possiblyAskForFonts = (vt_project, resolve, ignoreThese = []) => {
const availables = listAvailableFontsAndAxes();
const hashes = Object.keys(vt_project.fontsHashMap);
let isRecursive = false;
for (let h = 0; h < hashes.length; h++) {
const hash = hashes[h];
if (ignoreThese.indexOf(hash) >= 0){
continue;
}
const fontInfo = vt_project.fontsHashMap[hash];
let found = false;
for (let i = 0; i < availables.length; i++) {
if (availables[i].fontPath === fontInfo.fontPath) {
found = true;
}
}
if (!found) {
const used = this.projectUsesFont(vt_project, hash);
let satisfied = false;
for (let a = 0; a < availables.length; a++) {
if (fontInfo.fontName === availables[a].fontName) {
satisfied = true;
const uploadedPath = availables[a].fontPath;
const uploadedHash = hashFromString(uploadedPath);
delete vt_project.fontsHashMap[hash]; // will be generated? or maybe not
vt_project.fontsHashMap[uploadedHash] = {
fontName: availables[a].fontName,
fontPath: availables[a].fontPath,
axes: availables[a].axes,
};
const layerKeys = Object.keys(vt_project
.theatre
.sheetsById
.mainSheet
.staticOverrides
.byObject);
for (let l = 0; l < layerKeys.length; l++) {
if (vt_project
.theatre
.sheetsById
.mainSheet
.staticOverrides
.byObject[layerKeys[l]].fontFamily === hash) {
vt_project
.theatre
.sheetsById
.mainSheet
.staticOverrides
.byObject[layerKeys[l]].fontFamily = uploadedHash;
}
}
break;
}
}
if (!satisfied && used && confirm(`font ${fontInfo.fontName} not found.\n` +
`do you want to upload it (or a substitute) now?\n` +
`Otherwise it will be later substituted.\n\n` +
`If you click okay, click on the upcoming button`)) {
isRecursive = true;
this.addUserFont(fontInfo.fontName).then((uploadedFile) => {
const uploadedPath = `${config.fs.idbfsFontDir}/${uploadedFile.name}`;
const uploadedHash = hashFromString(uploadedPath);
delete vt_project.fontsHashMap[hash]; // will be generated?
const layerKeys = Object.keys(vt_project
.theatre
.sheetsById
.mainSheet
.staticOverrides
.byObject);
for (let l = 0; l < layerKeys.length; l++) {
if (vt_project
.theatre
.sheetsById
.mainSheet
.staticOverrides
.byObject[layerKeys[l]].fontFamily === hash) {
vt_project
.theatre
.sheetsById
.mainSheet
.staticOverrides
.byObject[layerKeys[l]].fontFamily = uploadedHash;
}
}
this.possiblyAskForFonts(vt_project, resolve, ignoreThese);
});
break;
} else if (satisfied) {
isRecursive = true;
this.possiblyAskForFonts(vt_project, resolve, ignoreThese);
} else {
ignoreThese.push(hash);
}
}
}
if (!isRecursive) {
resolve(vt_project);
}
};
this.variableTime2theatre = (vt_project) => {
return vt_project.theatre;
};
this.theatre2variableTime = (theatre_project, vt_params) => {
vt_params.theatre = theatre_project;
vt_params.theatre.revisionHistory = [];
return vt_params;
};
this.listProjects = () => {
const projectIds = [];
for (let i = 0; i < localStorage.length; i++) {
let key = localStorage.key(i);
if (key.indexOf(config.projects.savePrefix) === 0) {
const projectId = key.replace(config.projects.savePrefix, '');
projectIds.push(projectId);
}
}
return projectIds;
};
this.uploadProject = (reeeload = false) => {
uploadFile().then((vt_project) => {
if (vt_project.type === 'application/zip') {
moduleFS.save(vt_project).then((fileLocation) => {
const jsonString = Module.importProjectAsZip(fileLocation, `${config.fs.idbfsTmpDir}/outdir`);
const json = JSON.parse(jsonString);
if (verifyVariableTimeProject(json.project)) {
this.possiblyAskForFontsPromise(json.project).then((vt_project_u) => {
vt_project = vt_project_u;
window.debug_vt_project = vt_project;
config.autoSave = false;
this.saveProject(vt_project.projectId, vt_project, true);
if (reeeload) {
this.reloadToProject(vt_project.projectId);
}
});
} else {
console.log('TheatrePlay::uploadProject', 'could not verify project');
}
});
} else if (verifyVariableTimeProject(vt_project)) {
this.possiblyAskForFontsPromise(vt_project).then((vt_project_u) => {
vt_project = vt_project_u;
this.saveProject(vt_project.projectId, vt_project, true);
if (reeeload) {
this.reloadToProject(vt_project.projectId);
}
});
} else {
console.log('TheatrePlay::uploadProject', 'could not verify project');
}
}, (error) => {
console.error(error);
});
};
// we always save the currently opened project,
// but we may save it under a different id
this.createSaveFile = (projectId = project.address.projectId) => {
const currentProjectId = project.address.projectId;
const fontsHashMap = window.getLayers().length > 0 ? window.getLayers()[0].fontsHashMap : false;
const vt_params = {
variable_time_version: VARIABLE_TIME_VERSION,
layerOrder: window.layerOrder.get(),
fontsHashMap,
projectId,
audioSavedMapping: audio.getSavedMapping(),
audioMapping: audio.getMapping(),
};
const theatre = tp.studio.createContentOfSaveFile(currentProjectId);
return this.theatre2variableTime(theatre, vt_params);
};
this.saveProject = (projectId = project.address.projectId, vt_project = false, silent = true) => {
if (!silent) {
projectId = prompt("Please choose a name for your project", projectId);
}
if (vt_project === false) {
vt_project = this.createSaveFile();
}
localStorage.setItem(`${config.projects.savePrefix}${projectId}`, JSON.stringify(vt_project));
};
this.getProject = (projectId, unwrapped = false) => {
const json = localStorage.getItem(`${config.projects.savePrefix}${projectId}`);
if (json === null) {
return false
}
return unwrapped ? JSON.parse(json) : json;
}
this.downloadProject = (projectId = project.address.projectId, saveBeforeDownloading = true) => {
if (projectId === project.address.projectId) {
let vt_project = this.createSaveFile();
if (saveBeforeDownloading) {
this.saveProject(projectId, vt_project, true);
}
Module.downloadProject(projectId, JSON.stringify(vt_project));
} else {
const p = this.getProject(projectId);
if (p !== false) {
Module.downloadProject(projectId, JSON.stringify(p));
} else {
console.error('TheatrePlay::downloadProject', `cannot download project with id ${projectId}, because it is neither current project or saved in localStorage`);
}
}
};
this.reloadToProject = (projectId, hardReload = true) => {
const p = this.getProject(projectId, true);
if (p !== false) {
localStorage.setItem('currentProject', projectId);
if (hardReload) {
window.location.reload();
} else {
const layers = getLayers();
for (let l = 0; l < layers.length; l++) {
const doSaveProject = false;
console.log('TheatrePlay::reloadToProject','deleting layer' , layers[l].id());
deleteLayer(layers[l].id(), doSaveProject);
}
localStorage.removeItem('theatre-0.4.persistent');
studio.initialize();
this.initProject(projectId, p.theatre).then(() => {
this.loadProject(projectId, p);
});
}
} else {
console.error('TheatrePlay::reloadToProject', `no saved project with id ${projectId}`);
}
};
this.initProject = (projectId, projectJson = false) => {
return new Promise((resolve) => {
project = projectJson === false ? core.getProject(projectId) : core.getProject(projectId, {
state: projectJson
});
//console.log({project, projectJson});
window.setLoadingTask('setting up animation', 10);
project.ready.then(() => {
this.sheet = project.sheet('mainSheet');
window.setLoadingTask('setting up animation', 30);
waitingForShadowRoot(() => {
this.shadowRoot = document.getElementById('theatrejs-studio-root').shadowRoot;
this.addShadowCss();
resolve();
window.setLoadingTask('setting up animation', 42);
});
localStorage.setItem('currentProject', project.address.projectId);
});
});
};
this.duration = 0;
this.loadProject = (projectId = false, project = false) => {
console.log('TheatrePlay::loadProject');
this.isProjectLoaded = false;
return new Promise((resolve) => {
if (projectId === false) {
projectId = this.sheet.project.address.projectId;
}
if (project === false) {
project = this.getProject(projectId, true);
}
if (project !== false) { // if project is not saved yet, create new
// get all objects
const objects = project
.theatre
.sheetsById
.mainSheet
.staticOverrides
.byObject;
// load artboard
let artboardValues = objects['artboard'];
// for backward compatibility rename old values
if (artboardValues.hasOwnProperty('scale')) {
artboardValues['zoom'] = artboardValues['scale'];
delete artboardValues['scale'];
}
if (artboardValues.hasOwnProperty('backgroundColor')) {
artboardValues['color'] = artboardValues['backgroundColor'];
delete artboardValues['backgroundColor'];
}
// for backward compatibility merge with current values
// for backward compatibility merge with current values
const defaultArtboardValues = window.getArtboard().theatreObject.value;
const artboardProps = {...defaultArtboardValues, ...artboardValues};
window.setLoadingTask('setting up artboard', 90);
studio.transaction(({
set
}) => {
set(window.getArtboard().theatreObject.props, artboardProps);
});
if (project.hasOwnProperty('audioMapping')) {
audio.setMapping(project.audioMapping);
}
if (project.hasOwnProperty('audioSavedMapping')) {
audio.setSavedMapping(project.audioSavedMapping);
}
// load layers
const layerPromises = [];
Object.keys(objects)
.filter((e) => e.indexOf('layer-') === 0)
.forEach((layerId) => {
window.setLoadingTask(`setting up the shapes of ${layerId} to come`, 90);
window.project_fontsHashMap = project.fontsHashMap;
layerPromises.push(window.addExistingLayer(layerId, objects[layerId]));
});
//console.log(clone(objects));
Object.keys(objects)
.filter((e) => e.indexOf('audio-') === 0)
.forEach((layerId) => {
window.setLoadingTask(`setting up the sounds of ${layerId} to come`, 90);
window.project_fontsHashMap = project.fontsHashMap;
layerPromises.push(window.addExistingAudioLayer(layerId, objects[layerId]));
});
Promise.all(layerPromises).then(() => {
window.layerOrder.set(project.layerOrder);
this.duration = this.core.val(this.sheet.sequence.pointer.length);
if (project.layerOrder.length > 0) {
getLayers().forEach((layer) => {
if (layer.id() === project.layerOrder[project.layerOrder.length - 1]) {
layer.select();
}
});
}
resolve();
this.isProjectLoaded = true;
});
} else {
if (getLayers().length === 0 && config.layer.autoCreateFirstLayer) {
getFontsAndAxes().then((newFontsAndAxes) => {
const autoInitLayer = false;
const layer = addLayer(autoInitLayer);
layer.init().then(() => {
layer.select();
this.duration = this.core.val(this.sheet.sequence.pointer.length);
resolve();
this.isProjectLoaded = true;
});
});
} else {
const layers = getLayers();
if (layers.length > 0) {
}
this.duration = this.core.val(this.sheet.sequence.pointer.length);
resolve();
this.isProjectLoaded = true;
}
}
});
};
this.startNewProject = () => {
if(confirm('Starting a new project will clear all project data and spin up a blank project from scratch. Uploaded assets (a.k.a. fonts) will stay. Is this fine?')) {
setTimeout(() => {
window.localStorage.clear();
window.location.reload();
}, 100);
}
};
this.isInitialized = false;
this.isProjectLoaded = false;
this.init = () => {
return new Promise((resolve) => {
console.log('TheatrePlay', 'init');
localStorage.removeItem('theatre-0.4.persistent');
window.setLoadingTask('setting up animation', 0);
studio.initialize();
const currentProjectId = localStorage.getItem('currentProject');
if (currentProjectId === null ||
this.listProjects().indexOf(currentProjectId) < 0) {
this.initProject('variable-time').then(() => {
this.findInjectPanels();
window.setLoadingTask('setting up animation', 60);
this.isInitialized = true;
resolve();
});
} else {
const currentProject = this.getProject(currentProjectId, true);
this.initProject(currentProjectId, currentProject.theatre).then(() => {
this.findInjectPanels();
window.setLoadingTask('setting up animation', 60);
this.isInitialized = true;
resolve();
});
}
});
}
this.connectModuleCallbacks = () => {
console.log('TheatrePlay::connectModuleCallbacks');
if (config.timeline.rolloverReset) {
core.onChange(this.sheet.sequence.pointer.position, (position) => {
if (position < config.timeline.rolloverThreshold_s) {
Module.resetLetterDelay();
}
});
}
core.onChange(this.sheet.sequence.pointer.playing, (playing) => {
Module.setPlaying(playing);
});
};
this.isPlaying = () => {
return this.core.val(this.sheet.sequence.pointer.playing);
};
this.studio = studio;
this.core = core;
//action
if (autoInit) {
this.init();
}
};
export {
TheatrePlay
};