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);