aboutsummaryrefslogtreecommitdiff
path: root/pages
diff options
context:
space:
mode:
Diffstat (limited to 'pages')
-rw-r--r--pages/editor.tsx62
-rw-r--r--pages/present.tsx40
2 files changed, 40 insertions, 62 deletions
diff --git a/pages/editor.tsx b/pages/editor.tsx
index f07d915..1ae1587 100644
--- a/pages/editor.tsx
+++ b/pages/editor.tsx
@@ -131,34 +131,20 @@ var global = createState<globalState>({
update: {
refreshLiveTimeline: () => {
if (typeof player.timeline === 'undefined') return;
- player.timeline.slides = Array(...(global.timeline.workingTimeline.value));
- player.timeline.slides = player.timeline.slides.filter(slide => slide != null);
- player.timeline.slides.sort((a, b) => a.frame - b.frame);
- player.timeline.slides[-1] = { // TODO: dry
+ player.timeline = Array(...(global.timeline.workingTimeline.value));
+ player.timeline = player.timeline.filter(slide => slide != null);
+ player.timeline.sort((a, b) => a.frame - b.frame);
+ player.timeline[-1] = { // TODO: dry
id: '00000000-0000-0000-0000-000000000000',
frame: 0,
type: 'default',
clickThroughBehaviour: 'ImmediatelySkip',
};
- project.timeline.slides.set(player.timeline.slides);
- player.timeline = project.timeline.attach(Downgraded).value;
+ projectFile.timeline = player.timeline;
},
},
});
-interface project {
- timeline: timeline;
-}
-
-var project = createState<project>({
- timeline: {
- name: '',
- slides: [],
- framerate: 0,
- framecount: 0,
- },
-});
-
var settings = {
'default': {
node: <DefaultSettings />,
@@ -511,7 +497,7 @@ function TimelineSelection(props: { selectionDragArea: Ref<ReactNode>; }) {
selectionPosAPI.start({ visibility: 0 });
} else {
var endingFrame = startingFrame + frameWidth;
- var expandedTimeline = new Array(...project.timeline.slides.value);
+ var expandedTimeline = new Array(...projectFile.timeline);
for (let i = 0; i < expandedTimeline.length; i++) {
var slide = expandedTimeline[i];
if (slide.type != 'loop') continue;
@@ -670,7 +656,7 @@ function divs(int: number) {
function getMarkerSpacing() {
var zoom = global.timeline.zoom.value;
var frameWidth = zoomToPx(zoom);
- var divvable = divs(Math.round(project.timeline.framerate.value));
+ var divvable = divs(Math.round(projectFile?.video?.framerate));
if (divvable.length == 0) return 30;
var minSpacing = 120;
var multiply = 1;
@@ -693,7 +679,6 @@ function TimelineEditor() {
var mouseX = 0;
var ready = useHookstate(global).ready;
- var proj = useHookstate(project).timeline;
var timelineRef = useRef(null);
var selectionDragArea = useRef(null);
@@ -724,7 +709,7 @@ function TimelineEditor() {
useMousetrap(['.'], () => { // TODO: dry
if (!global.ready.timeline.value) return;
- var frame = Math.min(project.timeline.framecount.value, global.timeline.frame.value + 1);
+ var frame = Math.min(projectFile?.video?.framecount, global.timeline.frame.value + 1);
global.timeline.frame.set(frame);
scrubberSpring.start({ frame });
});
@@ -934,7 +919,7 @@ function TimelineEditor() {
</animated.div>
<div
className='keyframes'
- style={{ '--total-frames': proj.framecount.get() } as CSSProperties}
+ style={{ '--total-frames': projectFile?.video?.framecount } as CSSProperties}
>
<div className='selectionarea posabs v0' ref={selectionDragArea} />
{workingTimeline.map(slide =>
@@ -1113,9 +1098,9 @@ function DefaultSettings() {
reader.addEventListener('load', async ev => {
await projectFile.openProject(ev.target.result as ArrayBuffer);
- player.loadSlides(JSON.stringify(projectFile.project));
- project.timeline.set(player.timeline);
- global.timeline.workingTimeline.set(player.timeline.slides);
+ player.loadSlides(projectFile.timeline);
+ projectFile.timeline = player.timeline;
+ global.timeline.workingTimeline.set(player.timeline);
global.update.refreshLiveTimeline.value();
global.ready.timeline.set(true);
@@ -1146,7 +1131,7 @@ function DefaultSettings() {
children='Download .prspr'
startIcon={<DescriptionRoundedIcon />}
onClick={async () => {
- projectFile.loadProject(player.timeline);
+ projectFile.timeline = player.timeline;
projectFile.saveProject();
projectFile.downloadProjectFile();
}}
@@ -1156,15 +1141,10 @@ function DefaultSettings() {
color='default'
children='New project'
onClick={() => {
- var newProj: timeline = {
- slides: [],
- name: 'New project',
- framerate: 0,
- framecount: 0,
- };
- player.loadSlides(JSON.stringify(newProj));
- project.timeline.set(player.timeline);
- global.timeline.workingTimeline.set(player.timeline.slides);
+ player.loadSlides([]);
+ projectFile.timeline = player.timeline;
+ projectFile.name = 'New project';
+ global.timeline.workingTimeline.set(player.timeline);
global.update.refreshLiveTimeline.value();
global.ready.timeline.set(true);
}}
@@ -1292,7 +1272,6 @@ function Tools() {
var tool = useHookstate(global).timeline.tool;
var timelineZoom = useHookstate(global).timeline.zoom;
var ready = useHookstate(global).ready;
- var framerate = useHookstate(project).timeline.framerate;
useMousetrap(['v'], switchToTool('cursor'));
useMousetrap(['d'], switchToTool('default'));
@@ -1304,7 +1283,7 @@ function Tools() {
return <div className='tools'>
<div className={'time posrel ' + (ready.timeline.get() ? '' : 'disabled')}>
- <span className='framerate numbers posabs l0 t0'>@{framerate.get()}fps</span>
+ <span className='framerate numbers posabs l0 t0'>@{projectFile?.video?.framerate}fps</span>
<h2 className='timecode numbers posabs r0 t0'>
{player.frameToTimestampString(frame.get(), false)}
</h2>
@@ -1439,7 +1418,6 @@ function Player() {
function TitleBar() {
var ready = useHookstate(global).ready;
- var proj = useHookstate(project).timeline;
var nameRef = useRef(null);
@@ -1455,8 +1433,8 @@ function TitleBar() {
contentEditable
spellCheck={false}
ref={nameRef}
- onBlur={() => proj.name.set((nameRef.current as HTMLSpanElement).textContent.trim())}
- children={proj.name.get()}
+ onBlur={() => projectFile.name = (nameRef.current as HTMLSpanElement).textContent.trim()}
+ children={projectFile.name}
/>
</div>
</Toolbar>
diff --git a/pages/present.tsx b/pages/present.tsx
index a99d239..f1fbc58 100644
--- a/pages/present.tsx
+++ b/pages/present.tsx
@@ -1,9 +1,8 @@
import Button from '@material-ui/core/Button';
-import Ajv from 'ajv';
import { useEffect, useState } from 'react';
import Timecode from 'timecode-boss';
+import Project from '../project';
import timeline, { delaySlide, loopSlide, slide, speedChangeSlide } from '../timeline';
-import * as timelineSchema from '../timeline.schema.json';
import ExitToAppRoundedIcon from '@material-ui/icons/ExitToAppRounded';
import PlayArrowRoundedIcon from '@material-ui/icons/PlayArrowRounded';
@@ -21,6 +20,7 @@ export class TimedVideoPlayer {
video: string;
registeredEventListeners: boolean;
frame: number;
+ project: Project;
constructor() {
this.slide = -1;
@@ -30,7 +30,7 @@ export class TimedVideoPlayer {
}
frameToTimestampString(frame: number, trim: boolean = true) {
- var timecodeString = new Timecode(frame, this.timeline?.framerate).toString();
+ var timecodeString = new Timecode(frame, this.project?.video?.framerate).toString();
if (trim) timecodeString = timecodeString.replace(/^(00:)+/, '');
timecodeString = timecodeString.replace(';', '.')
.replace(/(:)(\d+?)$/, '.$2')
@@ -40,11 +40,11 @@ export class TimedVideoPlayer {
}
timestampToFrame(timestamp: number): number {
- return Math.ceil((timestamp * 1e3) / (1e3 / this.timeline?.framerate));
+ return Math.ceil(timestamp * this.project?.video?.framerate);
}
frameToTimestamp(frame: number): number {
- return frame / this.timeline?.framerate;
+ return frame / this.project?.video?.framerate;
}
registerPlayer(player: HTMLVideoElement) {
@@ -69,11 +69,11 @@ export class TimedVideoPlayer {
getPlaybackSpeed(slide: number) {
for (var i = slide; i > -1; i--) {
- var previousSlide = this.timeline.slides[i];
+ var previousSlide = this.timeline[i];
if (previousSlide.type != 'speedChange') {
continue;
}
- return this.timeline?.framerate / (previousSlide as speedChangeSlide).newFramerate;
+ return this.project?.video?.framerate / (previousSlide as speedChangeSlide).newFramerate;
}
return 1;
}
@@ -87,7 +87,7 @@ export class TimedVideoPlayer {
case 'delay': {
this.player.playbackRate = 0;
this.slide++;
- var event = new CustomEvent('TimedVideoPlayerSlide', { detail: this.timeline.slides[this.slide] });
+ var event = new CustomEvent('TimedVideoPlayerSlide', { detail: this.timeline[this.slide] });
this.dispatchEvent(event);
setTimeout(() => {
this.player.playbackRate = this.getPlaybackSpeed(this.slide - 1);
@@ -96,9 +96,9 @@ export class TimedVideoPlayer {
}
case 'speedChange': {
this.slide++;
- var event = new CustomEvent('TimedVideoPlayerSlide', { detail: this.timeline.slides[this.slide] });
+ var event = new CustomEvent('TimedVideoPlayerSlide', { detail: this.timeline[this.slide] });
this.dispatchEvent(event);
- this.player.playbackRate = this.timeline?.framerate / (slide as speedChangeSlide).newFramerate;
+ this.player.playbackRate = this.project?.video?.framerate / (slide as speedChangeSlide).newFramerate;
break;
}
default: {
@@ -134,13 +134,13 @@ export class TimedVideoPlayer {
var event = new CustomEvent('TimedVideoPlayerOnFrame', { detail: this.frame });
this.dispatchEvent(event);
- var slide = this.timeline.slides[this.slide];
+ var slide = this.timeline[this.slide];
if (!slide) return;
if (this.frame >= slide.frame) {
this.handleSlide(slide);
}
- }, 1e3 / (this.precision * this.timeline?.framerate));
+ }, 1e3 / (this.precision * this.project?.video?.framerate));
this.registeredEventListeners = true;
}
@@ -151,10 +151,10 @@ export class TimedVideoPlayer {
this.registerEventListeners();
}
- loadSlides(jsonString: string) {
- this.timeline = JSON.parse(jsonString) as timeline;
+ loadSlides(timeline: timeline) {
+ this.timeline = timeline;
- this.timeline.slides[-1] = {
+ this.timeline[-1] = {
id: '00000000-0000-0000-0000-000000000000',
frame: 0,
type: 'default',
@@ -165,7 +165,7 @@ export class TimedVideoPlayer {
}
skip() {
- var slide = this.timeline.slides[this.slide - 1];
+ var slide = this.timeline[this.slide - 1];
if (slide.clickThroughBehaviour == 'ImmediatelySkip') this.jumpToSlide(slide);
}
@@ -174,7 +174,7 @@ export class TimedVideoPlayer {
this.slide++;
- var slide = this.timeline.slides[this.slide];
+ var slide = this.timeline[this.slide];
var event = new CustomEvent('TimedVideoPlayerSlide', { detail: slide });
this.dispatchEvent(event);
@@ -188,7 +188,7 @@ export class TimedVideoPlayer {
this.slide = Math.max(this.slide - 1, -1);
- var slide = this.timeline.slides[this.slide];
+ var slide = this.timeline[this.slide];
if (!slide) return;
var event = new CustomEvent('TimedVideoPlayerSlide', { detail: slide });
@@ -255,7 +255,7 @@ export default function Present() {
<div className='info sidebyside posabs h0 b0'>
<div className='timetitle floatb'>
<h3 className='time numbers nobr' id='time'>14:00:41</h3>
- <h1 className='title nobr'>{player.timeline?.name || '???'}</h1>
+ <h1 className='title nobr'>{player.project?.name || '???'}</h1>
</div>
<div className='buttons floatb'>
<div className='inner center'>
@@ -336,7 +336,7 @@ export default function Present() {
</div>
<div className='slide posrel floatb'>
<h3 className='time numbers nobr posrel'>
- slide {player.slide + 1}/{player.timeline?.slides.length || 0}
+ slide {player.slide + 1}/{player.timeline?.length || 0}
</h3>
</div>
</div>