From fb97aacaf66bcb2a890f3913144935d9efe75a4f Mon Sep 17 00:00:00 2001 From: Graham Trott <gtanyware@gmail.com> Date: Mon, 27 Jul 2020 20:43:25 +0100 Subject: [PATCH] Partial implementation of requestAnimationFrame() --- dist/plugins/iwsy.js | 4 +- iwsy/iwsy.js | 314 +++++++++++++++++----------- iwsy/resources/ecs/iwsy.txt | 6 +- iwsy/resources/ecs/steps.txt | 43 ++-- iwsy/resources/ecs/vfx.txt | 55 +---- iwsy/resources/help/iwsy.md | 4 +- iwsy/resources/icon/down.png | Bin 13133 -> 4124 bytes iwsy/resources/scripts/demo.json | 9 +- iwsy/resources/scripts/liguria.json | 218 +++++++++++++++---- js/plugins/iwsy.js | 4 +- 10 files changed, 419 insertions(+), 238 deletions(-) diff --git a/dist/plugins/iwsy.js b/dist/plugins/iwsy.js index 9112099..074ffa6 100644 --- a/dist/plugins/iwsy.js +++ b/dist/plugins/iwsy.js @@ -184,9 +184,7 @@ const EasyCoder_IWSY = { program.run(command.pc + 1); }); return 0; - } else { - program.run(command.pc + 1); - } + } break; case `load`: const playerRecord = program.getSymbolRecord(command.player); diff --git a/iwsy/iwsy.js b/iwsy/iwsy.js index 2e5db4b..646a8d4 100644 --- a/iwsy/iwsy.js +++ b/iwsy/iwsy.js @@ -18,6 +18,7 @@ const IWSY = (playerElement, scriptObject) => { current[name] = block.defaults[name]; } block.current = current; + block.vfx = []; } }; @@ -141,8 +142,14 @@ const IWSY = (playerElement, scriptObject) => { text.style[`text-align`] = defaults.textAlign; }; + // No operation + const noop = step => { + step.next(); + }; + // Set the content of one or more blocks const setcontent = step => { + let continueFlag = true; for (const item of step.blocks) { for (const block of script.blocks) { @@ -155,27 +162,75 @@ const IWSY = (playerElement, scriptObject) => { const converter = new showdown.Converter({ extensions: [`IWSY`] }); - block.textPanel.innerHTML = - converter.makeHtml(text.content.split(`%0a`).join(`\n`)); + const converted = converter.makeHtml(text.content.split(`%0a`).join(`\n`)); + const tag = converted.match(/data-slide="([\w-_.]*)"/); + if (tag) { + const imagesLoading = []; + for (const vfx of script.vfx) { + if (vfx.name === tag[1]) { + vfx.container = block.textPanel; + if (vfx.url) { + if (vfx.url[0] === `=`) { + const lastVFX = vfx.url.slice(1); + for (const index in block.vfx) { + const vfx2 = block.vfx[index]; + if (vfx2.name === lastVFX) { + vfx.image = vfx2.image; + initImage(vfx); + vfx.startsize = vfx2.endsize; + vfx.startxoff = vfx2.endxoff; + vfx.startyoff = vfx2.endyoff; + vfx.w = vfx2.w2; + vfx.h = vfx2.h2; + vfx.xoff = vfx2.xoff2; + vfx.yoff = vfx2.yoff2; + if (!vfx.image) { + throw new Error(`Unknown vfx ${lastVFX}`); + } + block.vfx[index] = vfx; + } + break; + } + } else { + block.vfx.push(vfx); + continueFlag = false; + block.textPanel.innerHTML = converted; + const image = new Image(); + vfx.image = image; + image.id = vfx.name; + image.src = vfx.url; + image.addEventListener(`load`, () => { + initImage(vfx); + const index = imagesLoading.indexOf(image); + if (index > -1) { + imagesLoading.splice(index, 1); + } + if (imagesLoading.length === 0) { + step.next(); + } + }); + imagesLoading.push(image); + block.textPanel.appendChild(image); + } + break; + } + break; + } + } + } else { + block.textPanel.innerHTML = converted; + } break; } } - const vfxElements = block.textPanel.getElementsByClassName(`iwsy-vfx`); - // Save all the vfx items in this step - if (!Array.isArray(script.vfxElements)) { - script.vfxElements = []; - } - for (const vfxElement of vfxElements) { - script.vfxElements.push({ - block, - vfxElement - }); - } + block.element.style.display = step.display; break; } } } - step.next(); + if (continueFlag) { + step.next(); + } }; // Set the visibility of a block @@ -327,48 +382,129 @@ const IWSY = (playerElement, scriptObject) => { doFade(step, false); }; + const initImage = vfx => { + const container = vfx.container; + const image = vfx.image; + let aspectW = 4; + let aspectH = 3; + const colon = vfx.aspect.indexOf(`:`); + if (colon) { + aspectW = vfx.aspect.slice(0,colon); + aspectH = vfx.aspect.slice(colon + 1); + } + const ratio = aspectW / aspectH; + const width = container.offsetWidth; + const height = width / ratio; + container.style.height = `${Math.round(height)}px`; + container.style.display = `inline-block`; + container.style.overflow = `hidden`; + + const realWidth = image.naturalWidth; + const realHeight = image.naturalHeight; + const realRatio = realWidth / realHeight; + let w; + let h; + if (ratio < realRatio) { + h = height; + w = height * realRatio; + } else { + w = width; + h = width / realRatio; + } + const w2 = w * vfx.endsize / 100; + const h2 = h * vfx.endsize / 100; + w *= vfx.startsize / 100; + h *= vfx.startsize / 100; + const xoff = -width * vfx.startxoff / 100; + const yoff = -height * vfx.startyoff / 100; + const xoff2 = -width * vfx.endxoff / 100; + const yoff2 = -height * vfx.endyoff / 100; + + vfx.w = w; + vfx.w2 = w2; + vfx.h = h; + vfx.h2 = h2; + vfx.xoff = xoff; + vfx.xoff2 = xoff2; + vfx.yoff = yoff; + vfx.yoff2 = yoff2; + + image.style.position = `absolute`; + image.style.width = `${w}px`; + image.style.height = `${h}px`; + image.style.left = `${xoff}px`; + image.style.top = `${yoff}px`; + }; + + const doPanzoom = (timestamp, vfx) => { + if (vfx.start === undefined) { + vfx.start = timestamp; + } + const image = vfx.image; + const elapsed = timestamp - vfx.start; + const duration = vfx.duration * 1000; + if (elapsed < duration) { + const ratio = 0.5 - Math.cos(Math.PI * elapsed / duration) / 2; + image.style.width = `${vfx.w + (vfx.w2 - vfx.w) * ratio}px`; + image.style.height = `${vfx.h + (vfx.h2 - vfx.h) * ratio}px`; + image.style.left = `${vfx.xoff + (vfx.xoff2 - vfx.xoff) * ratio}px`; + image.style.top = `${vfx.yoff + (vfx.yoff2 - vfx.yoff) * ratio}px`; + requestAnimationFrame(timestamp => { + doPanzoom(timestamp, vfx); + }); + } else { + image.style.width = `${vfx.w2}px`; + image.style.height = `${vfx.h2}px`; + image.style.left = `${vfx.xoff2}px`; + image.style.top = `${vfx.yoff2}px`; + if (vfx.then) { + vfx.then(); + } + } + }; + // This is where the vfx animations are started - const startVFX = (step, vfxElement) => { + const startVFX = (step, vfx) => { + const vfxElement = vfx.container; vfxElement.style.position = `relative`; vfxElement.style.display = `inline-block`; - const slide = vfxElement.dataset.slide; - const vfx = script.vfx; - for (const item of vfx) { - if (item.name === slide) { - if (!Array.isArray(step.vfxRunning)) { - step.vfxRunning = []; + for (const item of script.vfx) { + if (item.name === vfx.name) { + if (!Array.isArray(step.vfx)) { + step.vfx = []; } - step.vfxRunning.push(vfxElement); - doPanzoom(vfxElement, item, () => { - if (step.continue !== `yes`) { - const index = step.vfxRunning.indexOf(vfxElement); - if (index > -1) { - step.vfxRunning.splice(index, 1); - } - if (step.vfxRunning.length === 0) { - step.next(); - } + step.vfx.push(item); + vfx.then = () => { + const index = step.vfx.indexOf(item); + if (index > -1) { + step.vfx.splice(index, 1); + } + if (step.vfx.length === 0 && step.continue !== `yes`) { + step.next(); } + }; + delete(vfx.start); + requestAnimationFrame(timestamp => { + doPanzoom(timestamp, vfx); }); + break; } } + if (step.vfx.length === 0) { + step.next(); + } }; // Animate blocks const animate = step => { - const continueFlag = step.continue === `yes`; + let continueFlag = true; for (const name of step.blocks) { for (const block of script.blocks) { if (block.defaults.name === name) { - if (!block.element) { - createBlock(block); - setVisibility(block, true); - } - for (const item of script.vfxElements) { - if (item.block === block) { - startVFX(step, item.vfxElement); - } + for (const vfx of block.vfx) { + continueFlag = step.continue === `yes`; + startVFX(step, vfx); } break; } @@ -376,11 +512,29 @@ const IWSY = (playerElement, scriptObject) => { } if (script.runMode === `manual`) { enterManualMode(step); - } else if (continueFlag || step.vfxRunning.length === 0) { + } else if (continueFlag) { step.next(); } }; + // Run a pan-zoom + const panzoom = arg => { + player.innerText = ``; + const vfx = JSON.parse(arg); + vfx.container = player; + const image = new Image(); + vfx.image = image; + image.src = spec.url; + // image.style.display = `none`; + image.addEventListener(`load`, () => { + initImage(spec); + requestAnimationFrame(timestamp => { + doPanzoom(timestamp, vfx); + }); + }); + player.appendChild(image); + }; + // Handle a crossfade const crossfade = step => { for (const content of script.content) { @@ -902,7 +1056,6 @@ const IWSY = (playerElement, scriptObject) => { script.speed = `normal`; script.labels = {}; script.stop = false; - script.vfxElements = []; script.scanFinished = false; removeStyles(); for (const block of script.blocks) { @@ -955,6 +1108,7 @@ const IWSY = (playerElement, scriptObject) => { const actions = { init, + noop, setcontent, show, hide, @@ -1008,7 +1162,7 @@ const IWSY = (playerElement, scriptObject) => { }); }) .catch(err => { - throw Error(`Fetch Error :${err}`); + console.log(`Fetch Error :${err}`); }); return; } @@ -1016,7 +1170,6 @@ const IWSY = (playerElement, scriptObject) => { const actionName = step.action.split(` `).join(``); let handler = actions[actionName]; - step.vfxRunning = []; if (script.runMode === `auto`) { if (typeof handler === `undefined`) { handler = plugins[actionName]; @@ -1196,79 +1349,6 @@ const IWSY = (playerElement, scriptObject) => { } }; - // Run a pan-zoom - const panzoom = arg => { - player.innerText = ``; - doPanzoom(player, JSON.parse(arg)); - }; - - const doPanzoom = (container, spec, then) => { - let aspectW = 4; - let aspectH = 3; - const colon = spec.aspect.indexOf(`:`); - if (colon) { - aspectW = spec.aspect.slice(0,colon); - aspectH = spec.aspect.slice(colon + 1); - } - const ratio = aspectW / aspectH; - const width = container.offsetWidth; - const height = width / ratio; - container.style.height = `${Math.round(height)}px`; - container.style.display = `inline-block`; - container.style.overflow = `hidden`; - - const image = new Image(); - container.appendChild(image); - - image.addEventListener(`load`, () => { - const realWidth = image.naturalWidth; - const realHeight = image.naturalHeight; - const realRatio = realWidth / realHeight; - let w; - let h; - if (ratio < realRatio) { - h = height; - w = height * realRatio; - } else { - w = width; - h = width / realRatio; - } - const w2 = w * spec.endsize / 100; - const h2 = h * spec.endsize / 100; - w *= spec.startsize / 100; - h *= spec.startsize / 100; - const xoff = width * spec.startxoff / 100; - const yoff = height * spec.startyoff / 100; - const xoff2 = width * spec.endxoff / 100; - const yoff2 = height * spec.endyoff / 100; - - image.style.position = `absolute`; - image.style.width = `${w}px`; - image.style.height = `${h}px`; - image.style.left = `${xoff}px`; - image.style.top = `${yoff}px`; - const animSteps = Math.round(spec.duration * 25); - let animStep = 0; - const interval = setInterval(() => { - if (animStep < animSteps) { - const ratio = 0.5 - Math.cos(Math.PI * animStep / animSteps) / 2; - image.style.width = `${w + (w2 - w) * ratio}px`; - image.style.height = `${h + (h2 - h) * ratio}px`; - image.style.left = `${xoff + (xoff2 - xoff) * ratio}px`; - image.style.top = `${yoff + (yoff2 - yoff) * ratio}px`; - animStep++; - } else { - clearIntervalTimer(interval); - if (then) { - then(); - } - } - }, 40); - addIntervalTimer(interval); - }); - image.src = spec.url; - }; - /////////////////////////////////////////////////////////////////////////// setupShowdown(); diff --git a/iwsy/resources/ecs/iwsy.txt b/iwsy/resources/ecs/iwsy.txt index ba6d04b..57df792 100644 --- a/iwsy/resources/ecs/iwsy.txt +++ b/iwsy/resources/ecs/iwsy.txt @@ -49,7 +49,6 @@ module FileManModule module HelpModule variable Mobile - variable Resources variable CDN variable LastSavedState variable Content @@ -465,6 +464,7 @@ Start: put 0 into N gosub to SelectSection clear Running + print `Load IWSY` iwsy load Player Presentation create UserPanel in Controls @@ -509,7 +509,7 @@ Start: put property `home` of UserRecord into UserHome put UserHome cat `/` cat property `id` of UserRecord into UserHome put UserHome into storage as `user.home` -! iwsy path Resources cat `/users/` cat UserHome cat `/scripts/` + iwsy path `/resources/users/` cat UserHome cat `/scripts/` put property `email` of UserRecord into UserEmail get UserPassword from storage as `user.password` set attribute `src` of User to CDN cat `/resources/icon/user-loggedin.png` @@ -532,7 +532,7 @@ Start: put property `arg` of Args into Arg if Arg includes `.json` begin - rest get Presentation from Protocol cat Domain cat `/` cat Resources cat `/users/` cat Arg cat `?v=` cat now + rest get Presentation from Protocol cat Domain cat `/reaources/users/` cat Arg cat `?v=` cat now gosub to NotifyModules iwsy script Presentation set style `display` of Player to `block` diff --git a/iwsy/resources/ecs/steps.txt b/iwsy/resources/ecs/steps.txt index 521619b..a022397 100644 --- a/iwsy/resources/ecs/steps.txt +++ b/iwsy/resources/ecs/steps.txt @@ -24,6 +24,7 @@ tr TR td TD select ActionSelect + select DisplaySelect select BlockSelect select ContentSelect select TargetSelect @@ -71,9 +72,10 @@ variable InitProperty variable BlockNames variable ContentNames + variable DisplayTypes variable ContinueTypes variable ChainNames - variable YesNo + variable Options variable Response variable Message variable Running @@ -137,10 +139,12 @@ Start: if property `action` of Message is `step` begin put property `step` of Message into N - if N is not less than the json count of Steps stop - index StepButton to N - set style `background-color` of StepButton to `#cfc` - stop + if N is less than the json count of Steps + begin + index StepButton to N + set style `background-color` of StepButton to `#cfc` + end + stop end Start2: @@ -297,6 +301,7 @@ Start2: ! Set up the fixed lists set ActionNames to array + json add `noop` to ActionNames json add `set content` to ActionNames json add `show` to ActionNames json add `hide` to ActionNames @@ -314,6 +319,9 @@ Start2: json add `background` to InitProperties json add `border` to InitProperties json add `css` to InitProperties + set DisplayTypes to array + json add `block` to DisplayTypes + json add `hidden` to DisplayTypes set ContinueTypes to array json add `yes` to ContinueTypes json add `no` to ContinueTypes @@ -337,6 +345,7 @@ SetupArrays: set the elements of DurationInput to N set the elements of URLInput to N set the elements of ChainSelect to N + set the elements of DisplaySelect to N set the elements of ContinueSelect to N set the elements of Editor to N put property `blocks` of Presentation into Blocks @@ -556,6 +565,17 @@ EditInit: EditSetContent: create TR in Table create TD in TR + set the content of TD to `Display:` + create TD in TR + index DisplaySelect to SelectedStep + create DisplaySelect in TD + set the style of DisplaySelect to `width:100%` + put property `display` of CurrentStep into Options + if Options is not `block` put `hidden` into Options + set DisplaySelect from DisplayTypes as Options + + create TR in Table + create TD in TR set the content of TD to `Blocks:` create TD in TR create BlockTable in TD @@ -738,10 +758,8 @@ EditChain: if Static is `static` go to EditChainFromStorage if UserRecord go to EditChainFromUser -! if IsHome go to EditChainFromStorage EditChainFromAdmin: -print `EditChainFromAdmin` get AdminPassword from storage as `.password` if AdminPassword is empty put prompt `Please type the admin password` with `` into AdminPassword rest get Valid from `verify/` cat AdminPassword @@ -764,7 +782,6 @@ print `EditChainFromAdmin` go to ProcessChainNames EditChainFromUser: -print `EditChainFromUser` rest get Files from `ulist/` cat Email cat `/` cat Password cat `/` cat `users/` cat UserHome cat `/scripts` put the json count of Files into FileCount @@ -778,7 +795,6 @@ print `EditChainFromUser` go to ProcessChainNames EditChainFromStorage: -print `EditChainFromStorage` get Files from storage put the json count of Files into FileCount put 0 into N @@ -920,9 +936,9 @@ EditContinue: index ContinueSelect to SelectedStep create ContinueSelect in TD set the style of ContinueSelect to `width:100%` - put property `continue` of CurrentStep into YesNo - if not YesNo put `no` into YesNo - set ContinueSelect from ContinueTypes as YesNo + put property `continue` of CurrentStep into Options + if not Options put `no` into Options + set ContinueSelect from ContinueTypes as Options return ! Create a new action with a full set of empty properties @@ -1054,6 +1070,8 @@ SaveCurrentStep: end else if Action is `set content` begin + index DisplaySelect to SelectedStep + set property `display` of CurrentStep to DisplaySelect set Blocks to array put 0 into N while N is less than the elements of BlockSelect @@ -1167,7 +1185,6 @@ SaveCurrentStep: set property `path` of CurrentStep to Email cat `/` cat Password cat `/` cat `users/` cat UserHome cat `/scripts/` end - else if IsHome put `static` into Mode else begin put `admin` into Mode diff --git a/iwsy/resources/ecs/vfx.txt b/iwsy/resources/ecs/vfx.txt index 62ff504..0df5f30 100644 --- a/iwsy/resources/ecs/vfx.txt +++ b/iwsy/resources/ecs/vfx.txt @@ -14,9 +14,6 @@ input AspectRatioInput input URLInput input DurationInput - input StartSizeInput - input StartXOffsetInput - input StartYOffsetInput input EndSizeInput input EndXOffsetInput input EndYOffsetInput @@ -96,9 +93,6 @@ Restart: set the elements of AspectRatioInput to NumItems set the elements of URLInput to NumItems set the elements of DurationInput to NumItems - set the elements of StartSizeInput to NumItems - set the elements of StartXOffsetInput to NumItems - set the elements of StartYOffsetInput to NumItems set the elements of EndSizeInput to NumItems set the elements of EndXOffsetInput to NumItems set the elements of EndYOffsetInput to NumItems @@ -167,9 +161,6 @@ Restart: index AspectRatioInput to SelectedItem index URLInput to SelectedItem index DurationInput to SelectedItem - index StartSizeInput to SelectedItem - index StartXOffsetInput to SelectedItem - index StartYOffsetInput to SelectedItem index EndSizeInput to SelectedItem index EndXOffsetInput to SelectedItem index EndYOffsetInput to SelectedItem @@ -229,7 +220,7 @@ ReloadEditor: put property `url` of Item into Value if Value is empty put empty into Value set the text of URLInput to Value - + create Row in Editor set the style of Row to `display:flex` create Cell in Row @@ -238,42 +229,9 @@ ReloadEditor: create DurationInput in Row set the style of DurationInput to `flex:1` put property `duration` of Item into Value - if Value is empty put 1 into Value +! if Value is empty put 1 into Value set the text of DurationInput to Value - create Row in Editor - set the style of Row to `display:flex` - create Cell in Row - set the style of Cell to `width:5em` - set the content of Cell to `Start Size` - create StartSizeInput in Row - set the style of StartSizeInput to `flex:1` - put property `startsize` of Item into Value - if Value is empty put 100 into Value - set the text of StartSizeInput to Value - - create Row in Editor - set the style of Row to `display:flex` - create Cell in Row - set the style of Cell to `width:5em` - set the content of Cell to `Start Xoff` - create StartXOffsetInput in Row - set the style of StartXOffsetInput to `flex:1` - put property `startxoff` of Item into Value - if Value is empty put 0 into Value - set the text of StartXOffsetInput to Value - - create Row in Editor - set the style of Row to `display:flex` - create Cell in Row - set the style of Cell to `width:5em` - set the content of Cell to `Start Yoff` - create StartYOffsetInput in Row - set the style of StartYOffsetInput to `flex:1` - put property `startyoff` of Item into Value - if Value is empty put 0 into Value - set the text of StartYOffsetInput to Value - create Row in Editor set the style of Row to `display:flex` create Cell in Row @@ -282,7 +240,6 @@ ReloadEditor: create EndSizeInput in Row set the style of EndSizeInput to `flex:1` put property `endsize` of Item into Value - if Value is empty put 100 into Value set the text of EndSizeInput to Value create Row in Editor @@ -293,7 +250,6 @@ ReloadEditor: create EndXOffsetInput in Row set the style of EndXOffsetInput to `flex:1` put property `endxoff` of Item into Value - if Value is empty put 0 into Value set the text of EndXOffsetInput to Value create Row in Editor @@ -304,7 +260,6 @@ ReloadEditor: create EndYOffsetInput in Row set the style of EndYOffsetInput to `flex:1` put property `endyoff` of Item into Value - if Value is empty put 0 into Value set the text of EndYOffsetInput to Value end create Row in Editor @@ -375,18 +330,12 @@ SaveSelectedItem: index AspectRatioInput to SelectedItem index URLInput to SelectedItem index DurationInput to SelectedItem - index StartSizeInput to SelectedItem - index StartXOffsetInput to SelectedItem - index StartYOffsetInput to SelectedItem index EndSizeInput to SelectedItem index EndXOffsetInput to SelectedItem index EndYOffsetInput to SelectedItem set property `aspect` of Item to AspectRatioInput set property `url` of Item to URLInput set property `duration` of Item to DurationInput - set property `startsize` of Item to StartSizeInput - set property `startxoff` of Item to StartXOffsetInput - set property `startyoff` of Item to StartYOffsetInput set property `endsize` of Item to EndSizeInput set property `endxoff` of Item to EndXOffsetInput set property `endyoff` of Item to EndYOffsetInput diff --git a/iwsy/resources/help/iwsy.md b/iwsy/resources/help/iwsy.md index ad78a27..b9edfa4 100644 --- a/iwsy/resources/help/iwsy.md +++ b/iwsy/resources/help/iwsy.md @@ -20,9 +20,9 @@ These help pages contain everything there is to know about ~iwsy~, but there's a ## Feature summary -There are many slideshow/presentation packages, most being quite similar to PowerPoint. The aim here is not to create another identical one but to tackle one or two of the things the others don't do so well. Top of the list is the ability to embed a show into another web page in a seamless manner. The development of ~iwsy~ is driven by the desire to meet this need rather than to excel at formal presentations. +There are many slideshow/presentation packages, most being quite similar to PowerPoint. The aim here is not to create another clone but to tackle one or two of the things the others don't do so well. Top of the list is the ability to embed a show into another web page in a seamless manner. The development of ~iwsy~ is driven by the desire to meet this need rather than to excel at formal presentations. -We are also working on a range of features for making the pages themselves dynamic. This covers a number of areas such as transitions, "Ken Burns" effects and the use of audio. +The other difference is in making the pages themselves dynamic. This covers a number of areas such as transitions, "Ken Burns" effects and the use of audio. The basic features of ~iwsy~ are: diff --git a/iwsy/resources/icon/down.png b/iwsy/resources/icon/down.png index 58267a946233f44a14c9a23bbe3d52404db5503f..6ad348084753ae8d983520ed045ab0ff1ace1456 100644 GIT binary patch delta 4105 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 B#UB6w literal 13133 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 diff --git a/iwsy/resources/scripts/demo.json b/iwsy/resources/scripts/demo.json index a37ebd6..2a237f0 100644 --- a/iwsy/resources/scripts/demo.json +++ b/iwsy/resources/scripts/demo.json @@ -24,7 +24,8 @@ "block": "background", "content": "" } - ] + ], + "display": "hidden" }, { "title": "fade up background", @@ -55,7 +56,8 @@ "block": "subtitle", "content": "subtitle" } - ] + ], + "display": "hidden" }, { "title": "zoom up title", @@ -325,5 +327,6 @@ "name": "for example", "content": "## For example%0aHere are 3 slides from a presentation %0aabout villages in Liguria, Italy" } - ] + ], + "vfx": [] } \ No newline at end of file diff --git a/iwsy/resources/scripts/liguria.json b/iwsy/resources/scripts/liguria.json index 853b72c..bf97bcc 100644 --- a/iwsy/resources/scripts/liguria.json +++ b/iwsy/resources/scripts/liguria.json @@ -10,7 +10,7 @@ "css": "" }, { - "title": "set up blocks", + "title": "set up text blocks", "action": "set content", "label": "", "blocks": [ @@ -18,33 +18,67 @@ "block": "manarola text", "content": "Manarola" }, - { - "block": "manarola photo", - "content": "manarola photo" - }, { "block": "apricale text", "content": "Apricale" }, - { - "block": "apricale photo", - "content": "apricale photo" - }, { "block": "noli text", "content": "Noli" - }, + } + ], + "display": "hidden" + }, + { + "title": "set up Manarola start", + "action": "set content", + "label": "", + "blocks": [ + { + "block": "manarola photo", + "content": "Manarola start" + } + ], + "display": "block" + }, + { + "title": "set up Apricale start", + "action": "set content", + "label": "", + "duration": 9, + "blocks": [ + { + "block": "apricale photo", + "content": "Apricale start" + } + ], + "display": "block" + }, + { + "title": "set up Noli start", + "action": "set content", + "label": "", + "blocks": [ { "block": "noli photo", - "content": "noli photo" + "content": "Noli start" } - ] + ], + "display": "block" }, { - "title": "pause 1 second", - "action": "pause", + "title": "---", + "action": "noop", + "label": "" + }, + { + "title": "position Manarola", + "action": "animate", "label": "", - "duration": 1.1 + "blocks": [ + "manarola photo" + ], + "continue": "no" }, { "title": "fade up Manarola", @@ -55,7 +89,19 @@ "manarola photo" ], "duration": 3, - "continue": "yes" + "continue": "no" + }, + { + "title": "set up Manarola finish", + "action": "set content", + "label": "", + "blocks": [ + { + "block": "manarola photo", + "content": "Manarola finish" + } + ], + "display": "block" }, { "title": "animate Manarola", @@ -72,6 +118,33 @@ "label": "", "duration": 9 }, + { + "title": "---", + "action": "noop", + "label": "" + }, + { + "title": "position Apricale", + "action": "animate", + "label": "", + "blocks": [ + "apricale photo" + ], + "continue": "no" + }, + { + "title": "setup Apricale finish", + "action": "set content", + "label": "", + "blocks": [ + { + "block": "apricale photo", + "content": "Apricale finish" + } + ], + "continue": "no", + "display": "block" + }, { "title": "fade down Manarola", "action": "fade down", @@ -109,6 +182,32 @@ "label": "", "duration": 9 }, + { + "title": "---", + "action": "noop", + "label": "" + }, + { + "title": "position Noli", + "action": "animate", + "label": "", + "blocks": [ + "noli photo" + ], + "continue": "no" + }, + { + "title": "set up Noli finish", + "action": "set content", + "label": "", + "blocks": [ + { + "block": "noli photo", + "content": "Noli finish" + } + ], + "display": "block" + }, { "title": "fade down Apricale", "action": "fade down", @@ -146,6 +245,11 @@ "label": "", "duration": 9 }, + { + "title": "---", + "action": "noop", + "label": "" + }, { "title": "fade down Noli", "action": "fade down", @@ -206,7 +310,6 @@ "label": "", "script": "demo.json", "path": "/resources/scripts/", - "mode": "admin", "blocks": [] } ], @@ -240,7 +343,7 @@ "top": 0, "width": 500, "height": 1000, - "background": "url('https://easycoder.github.io/iwsy/resources/help/quickstart/manarola.jpg')", + "background": "", "border": "", "borderRadius": "", "fontFamily": "", @@ -282,7 +385,7 @@ "top": 0, "width": 500, "height": 1000, - "background": "url('https://easycoder.github.io/iwsy/resources/help/quickstart/apricale.jpg')", + "background": "", "border": "", "borderRadius": "", "fontFamily": "", @@ -324,7 +427,7 @@ "top": 0, "width": 500, "height": 1000, - "background": "url('https://easycoder.github.io/iwsy/resources/help/quickstart/noli.jpg')", + "background": "", "border": "", "borderRadius": "", "fontFamily": "", @@ -377,57 +480,90 @@ "content": "%0a... and so on.%0a%0aNow we'll chain back to the intro screen" }, { - "name": "manarola photo", - "content": "~vfx:100% manarola~" + "name": "Manarola start", + "content": "~vfx:manarola-start~" + }, + { + "name": "Manarola finish", + "content": "~vfx:manarola-finish~" + }, + { + "name": "Apricale start", + "content": "~vfx:apricale-start~" }, { - "name": "apricale photo", - "content": "~vfx:100% apricale~" + "name": "Apricale finish", + "content": "~vfx:apricale-finish~" }, { - "name": "noli photo", - "content": "~vfx:100% noli~" + "name": "Noli start", + "content": "~vfx:noli-start~" + }, + { + "name": "Noli finish", + "content": "~vfx:noli-finish~" } ], "vfx": [ { - "name": "manarola", + "name": "manarola-start", "type": "panzoom", "aspect": "8:9", "url": "https://easycoder.github.io/iwsy/resources/help/quickstart/manarola.jpg", + "duration": 0, + "endsize": 100, + "endxoff": 50, + "endyoff": 0 + }, + { + "name": "manarola-finish", + "type": "panzoom", + "aspect": "8:9", + "url": "=manarola-start", "duration": 10, - "startsize": 100, - "startxoff": -50, - "startyoff": 0, "endsize": 100, "endxoff": 0, "endyoff": 0 }, { - "name": "apricale", + "name": "apricale-start", "type": "panzoom", "aspect": "8:9", "url": "https://easycoder.github.io/iwsy/resources/help/quickstart/apricale.jpg", + "duration": 0, + "endsize": 100, + "endxoff": 0, + "endyoff": 0 + }, + { + "name": "apricale-finish", + "type": "panzoom", + "aspect": "8:9", + "url": "=apricale-start", "duration": 10, - "startsize": 100, - "startxoff": 0, - "startyoff": 0, "endsize": 100, - "endxoff": -50, + "endxoff": 50, "endyoff": 0 }, { - "name": "noli", + "name": "noli-start", "type": "panzoom", "aspect": "8:9", "url": "https://easycoder.github.io/iwsy/resources/help/quickstart/noli.jpg", + "duration": 0, + "endsize": 100, + "endxoff": 0, + "endyoff": 0 + }, + { + "name": "noli-finish", + "type": "panzoom", + "aspect": "8:9", + "url": "=noli-start", "duration": 10, - "startsize": 100, - "startxoff": 0, - "startyoff": 0, "endsize": 100, - "endxoff": -50, + "endxoff": 50, "endyoff": 0 } ] -} \ No newline at end of file +} diff --git a/js/plugins/iwsy.js b/js/plugins/iwsy.js index 9112099..074ffa6 100644 --- a/js/plugins/iwsy.js +++ b/js/plugins/iwsy.js @@ -184,9 +184,7 @@ const EasyCoder_IWSY = { program.run(command.pc + 1); }); return 0; - } else { - program.run(command.pc + 1); - } + } break; case `load`: const playerRecord = program.getSymbolRecord(command.player);