@mulsense/xnew 0.3.6 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/xnew.js CHANGED
@@ -206,10 +206,323 @@
206
206
  }
207
207
  }
208
208
 
209
- //----------------------------------------------------------------------------------------------------
210
- // utils
211
- //----------------------------------------------------------------------------------------------------
212
- const SYSTEM_EVENTS = ['start', 'logicupdate', 'update', 'stop', 'finalize'];
209
+ const SYSTEM_EVENTS = ['start', 'process', 'update', 'stop', 'finalize'];
210
+
211
+ class EventManager {
212
+ constructor() {
213
+ this.map = new MapMap();
214
+ }
215
+ add(props) {
216
+ let finalize;
217
+ if (props.type === 'resize') {
218
+ finalize = this.resize(props);
219
+ }
220
+ else if (props.type === 'wheel') {
221
+ finalize = this.wheel(props);
222
+ }
223
+ else if (props.type === 'click') {
224
+ finalize = this.click(props);
225
+ }
226
+ else if (props.type === 'click.outside') {
227
+ finalize = this.click_outside(props);
228
+ }
229
+ else if (['pointerdown', 'pointermove', 'pointerup', 'pointerover', 'pointerout'].includes(props.type)) {
230
+ finalize = this.pointer(props);
231
+ }
232
+ else if (['pointerdown.outside', 'pointermove.outside', 'pointerup.outside'].includes(props.type)) {
233
+ finalize = this.pointer_outside(props);
234
+ }
235
+ else if (['mousedown', 'mousemove', 'mouseup', 'mouseover', 'mouseout'].includes(props.type)) {
236
+ finalize = this.mouse(props);
237
+ }
238
+ else if (['touchstart', 'touchmove', 'touchend', 'touchcancel'].includes(props.type)) {
239
+ finalize = this.touch(props);
240
+ }
241
+ else if (['dragstart', 'dragmove', 'dragend'].includes(props.type)) {
242
+ finalize = this.drag(props);
243
+ }
244
+ else if (['gesturestart', 'gesturemove', 'gestureend'].includes(props.type)) {
245
+ finalize = this.gesture(props);
246
+ }
247
+ else if (['keydown', 'keyup'].includes(props.type)) {
248
+ finalize = this.key(props);
249
+ }
250
+ else if (['keydown.arrow', 'keyup.arrow'].includes(props.type)) {
251
+ finalize = this.key_arrow(props);
252
+ }
253
+ else {
254
+ finalize = this.basic(props);
255
+ }
256
+ this.map.set(props.type, props.listener, finalize);
257
+ }
258
+ remove({ type, listener }) {
259
+ const finalize = this.map.get(type, listener);
260
+ if (finalize) {
261
+ finalize();
262
+ this.map.delete(type, listener);
263
+ }
264
+ }
265
+ basic(props) {
266
+ const execute = (event) => {
267
+ props.listener({ event, type: event.type });
268
+ };
269
+ props.element.addEventListener(props.type, execute, props.options);
270
+ return () => {
271
+ props.element.removeEventListener(props.type, execute);
272
+ };
273
+ }
274
+ resize(props) {
275
+ const observer = new ResizeObserver(xnew$1.scope((entries) => {
276
+ for (const entry of entries) {
277
+ props.listener({ type: 'resize' });
278
+ break;
279
+ }
280
+ }));
281
+ observer.observe(props.element);
282
+ return () => {
283
+ observer.unobserve(props.element);
284
+ };
285
+ }
286
+ click(props) {
287
+ const execute = (event) => {
288
+ props.listener({ event, type: props.type, position: pointer(props.element, event).position });
289
+ };
290
+ props.element.addEventListener(props.type, execute, props.options);
291
+ return () => {
292
+ props.element.removeEventListener(props.type, execute);
293
+ };
294
+ }
295
+ click_outside(props) {
296
+ const execute = (event) => {
297
+ if (props.element.contains(event.target) === false) {
298
+ props.listener({ event, type: props.type, position: pointer(props.element, event).position });
299
+ }
300
+ };
301
+ document.addEventListener(props.type.split('.')[0], execute, props.options);
302
+ return () => {
303
+ document.removeEventListener(props.type.split('.')[0], execute);
304
+ };
305
+ }
306
+ pointer(props) {
307
+ const execute = (event) => {
308
+ props.listener({ event, type: props.type, position: pointer(props.element, event).position });
309
+ };
310
+ props.element.addEventListener(props.type, execute, props.options);
311
+ return () => {
312
+ props.element.removeEventListener(props.type, execute);
313
+ };
314
+ }
315
+ mouse(props) {
316
+ const execute = (event) => {
317
+ props.listener({ event, type: props.type, position: pointer(props.element, event).position });
318
+ };
319
+ props.element.addEventListener(props.type, execute, props.options);
320
+ return () => {
321
+ props.element.removeEventListener(props.type, execute);
322
+ };
323
+ }
324
+ touch(props) {
325
+ const execute = (event) => {
326
+ props.listener({ event, type: props.type, position: pointer(props.element, event).position });
327
+ };
328
+ props.element.addEventListener(props.type, execute, props.options);
329
+ return () => {
330
+ props.element.removeEventListener(props.type, execute);
331
+ };
332
+ }
333
+ pointer_outside(props) {
334
+ const execute = (event) => {
335
+ if (props.element.contains(event.target) === false) {
336
+ props.listener({ event, type: props.type, position: pointer(props.element, event).position });
337
+ }
338
+ };
339
+ document.addEventListener(props.type.split('.')[0], execute, props.options);
340
+ return () => {
341
+ document.removeEventListener(props.type.split('.')[0], execute);
342
+ };
343
+ }
344
+ wheel(props) {
345
+ const execute = (event) => {
346
+ props.listener({ event, type: props.type, delta: { x: event.wheelDeltaX, y: event.wheelDeltaY } });
347
+ };
348
+ props.element.addEventListener(props.type, execute, props.options);
349
+ return () => {
350
+ props.element.removeEventListener(props.type, execute);
351
+ };
352
+ }
353
+ drag(props) {
354
+ let pointermove = null;
355
+ let pointerup = null;
356
+ let pointercancel = null;
357
+ const pointerdown = (event) => {
358
+ const id = event.pointerId;
359
+ const position = pointer(props.element, event).position;
360
+ let previous = position;
361
+ pointermove = (event) => {
362
+ if (event.pointerId === id) {
363
+ const position = pointer(props.element, event).position;
364
+ const delta = { x: position.x - previous.x, y: position.y - previous.y };
365
+ if (props.type === 'dragmove') {
366
+ props.listener({ event, type: props.type, position, delta });
367
+ }
368
+ previous = position;
369
+ }
370
+ };
371
+ pointerup = (event) => {
372
+ if (event.pointerId === id) {
373
+ const position = pointer(props.element, event).position;
374
+ if (props.type === 'dragend') {
375
+ props.listener({ event, type: props.type, position, delta: { x: 0, y: 0 } });
376
+ }
377
+ remove();
378
+ }
379
+ };
380
+ pointercancel = (event) => {
381
+ if (event.pointerId === id) {
382
+ const position = pointer(props.element, event).position;
383
+ if (props.type === 'dragend') {
384
+ props.listener({ event, type: props.type, position, delta: { x: 0, y: 0 } });
385
+ }
386
+ remove();
387
+ }
388
+ };
389
+ window.addEventListener('pointermove', pointermove);
390
+ window.addEventListener('pointerup', pointerup);
391
+ window.addEventListener('pointercancel', pointercancel);
392
+ if (props.type === 'dragstart') {
393
+ props.listener({ event, type: props.type, position, delta: { x: 0, y: 0 } });
394
+ }
395
+ };
396
+ function remove() {
397
+ if (pointermove)
398
+ window.removeEventListener('pointermove', pointermove);
399
+ if (pointerup)
400
+ window.removeEventListener('pointerup', pointerup);
401
+ if (pointercancel)
402
+ window.removeEventListener('pointercancel', pointercancel);
403
+ pointermove = null;
404
+ pointerup = null;
405
+ pointercancel = null;
406
+ }
407
+ props.element.addEventListener('pointerdown', pointerdown, props.options);
408
+ return () => {
409
+ props.element.removeEventListener('pointerdown', pointerdown);
410
+ remove();
411
+ };
412
+ }
413
+ gesture(props) {
414
+ let isActive = false;
415
+ const map = new Map();
416
+ const element = props.element;
417
+ const options = props.options;
418
+ const dragstart = ({ event, position }) => {
419
+ map.set(event.pointerId, Object.assign({}, position));
420
+ isActive = map.size === 2 ? true : false;
421
+ if (isActive === true && props.type === 'gesturestart') {
422
+ props.listener({ event, type: props.type });
423
+ }
424
+ };
425
+ const dragmove = ({ event, position, delta }) => {
426
+ if (map.size >= 2 && isActive === true) {
427
+ const a = map.get(event.pointerId);
428
+ const b = getOthers(event.pointerId)[0];
429
+ let scale = 0.0;
430
+ {
431
+ const v = { x: a.x - b.x, y: a.y - b.y };
432
+ const s = v.x * v.x + v.y * v.y;
433
+ scale = 1 + (s > 0.0 ? (v.x * delta.x + v.y * delta.y) / s : 0);
434
+ }
435
+ // let rotate = 0.0;
436
+ // {
437
+ // const c = { x: a.x + delta.x, y: a.y + delta.y };
438
+ // const v1 = { x: a.x - b.x, y: a.y - b.y };
439
+ // const v2 = { x: c.x - b.x, y: c.y - b.y };
440
+ // const l1 = Math.sqrt(v1.x * v1.x + v1.y * v1.y);
441
+ // const l2 = Math.sqrt(v2.x * v2.x + v2.y * v2.y);
442
+ // if (l1 > 0.0 && l2 > 0.0) {
443
+ // const angle = Math.acos((v1.x * v2.x + v1.y * v2.y) / (l1 * l2));
444
+ // const sign = v1.x * v2.y - v1.y * v2.x;
445
+ // rotate = sign > 0.0 ? +angle : -angle;
446
+ // }
447
+ // }
448
+ if (props.type === 'gesturemove') {
449
+ props.listener({ event, type: props.type, scale });
450
+ }
451
+ }
452
+ map.set(event.pointerId, position);
453
+ };
454
+ const dragend = ({ event }) => {
455
+ if (isActive === true) {
456
+ props.listener({ event, type: props.type, scale: 1.0 });
457
+ }
458
+ isActive = false;
459
+ map.delete(event.pointerId);
460
+ };
461
+ this.add({ element, options, type: 'dragstart', listener: dragstart });
462
+ this.add({ element, options, type: 'dragmove', listener: dragmove });
463
+ this.add({ element, options, type: 'dragend', listener: dragend });
464
+ function getOthers(id) {
465
+ const backup = map.get(id);
466
+ map.delete(id);
467
+ const others = [...map.values()];
468
+ map.set(id, backup);
469
+ return others;
470
+ }
471
+ return () => {
472
+ this.remove({ type: 'dragstart', listener: dragstart });
473
+ this.remove({ type: 'dragmove', listener: dragmove });
474
+ this.remove({ type: 'dragend', listener: dragend });
475
+ };
476
+ }
477
+ key(props) {
478
+ const execute = (event) => {
479
+ if (props.type === 'keydown' && event.repeat)
480
+ return;
481
+ props.listener({ event, type: props.type, code: event.code });
482
+ };
483
+ window.addEventListener(props.type, execute, props.options);
484
+ return () => {
485
+ window.removeEventListener(props.type, execute);
486
+ };
487
+ }
488
+ key_arrow(props) {
489
+ const keymap = {};
490
+ const keydown = (event) => {
491
+ if (event.repeat)
492
+ return;
493
+ keymap[event.code] = 1;
494
+ if (props.type === 'keydown.arrow' && ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(event.code)) {
495
+ const vector = {
496
+ x: (keymap['ArrowLeft'] ? -1 : 0) + (keymap['ArrowRight'] ? +1 : 0),
497
+ y: (keymap['ArrowUp'] ? -1 : 0) + (keymap['ArrowDown'] ? +1 : 0)
498
+ };
499
+ props.listener({ event, type: props.type, code: event.code, vector });
500
+ }
501
+ };
502
+ const keyup = (event) => {
503
+ keymap[event.code] = 0;
504
+ if (props.type === 'keyup.arrow' && ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(event.code)) {
505
+ const vector = {
506
+ x: (keymap['ArrowLeft'] ? -1 : 0) + (keymap['ArrowRight'] ? +1 : 0),
507
+ y: (keymap['ArrowUp'] ? -1 : 0) + (keymap['ArrowDown'] ? +1 : 0)
508
+ };
509
+ props.listener({ event, type: props.type, code: event.code, vector });
510
+ }
511
+ };
512
+ window.addEventListener('keydown', keydown, props.options);
513
+ window.addEventListener('keyup', keyup, props.options);
514
+ return () => {
515
+ window.removeEventListener('keydown', keydown);
516
+ window.removeEventListener('keyup', keyup);
517
+ };
518
+ }
519
+ }
520
+ function pointer(element, event) {
521
+ const rect = element.getBoundingClientRect();
522
+ const position = { x: event.clientX - rect.left, y: event.clientY - rect.top };
523
+ return { position };
524
+ }
525
+
213
526
  //----------------------------------------------------------------------------------------------------
214
527
  // unit
215
528
  //----------------------------------------------------------------------------------------------------
@@ -302,7 +615,8 @@
302
615
  components: [],
303
616
  listeners: new MapMap(),
304
617
  defines: {},
305
- systems: { start: [], logicupdate: [], update: [], stop: [], finalize: [] },
618
+ systems: { start: [], process: [], update: [], stop: [], finalize: [] },
619
+ eventManager: new EventManager(),
306
620
  });
307
621
  // nest html element
308
622
  if (typeof unit._.target === 'string') {
@@ -412,15 +726,15 @@
412
726
  }
413
727
  }
414
728
  static update(unit) {
415
- if (unit._.state === 'started') {
729
+ if (unit._.state === 'started' || unit._.state === 'stopped') {
416
730
  unit._.children.forEach((child) => Unit.update(child));
417
731
  unit._.systems.update.forEach((listener) => Unit.scope(Unit.snapshot(unit), listener));
418
732
  }
419
733
  }
420
- static logicupdate(unit) {
734
+ static process(unit) {
421
735
  if (unit._.state === 'started') {
422
- unit._.children.forEach((child) => Unit.logicupdate(child));
423
- unit._.systems.logicupdate.forEach((listener) => Unit.scope(Unit.snapshot(unit), listener));
736
+ unit._.children.forEach((child) => Unit.process(child));
737
+ unit._.systems.process.forEach((listener) => Unit.scope(Unit.snapshot(unit), listener));
424
738
  }
425
739
  }
426
740
  static reset() {
@@ -430,7 +744,7 @@
430
744
  (_b = Unit.ticker) === null || _b === void 0 ? void 0 : _b.clear();
431
745
  Unit.ticker = new Ticker(() => {
432
746
  Unit.start(Unit.root);
433
- Unit.logicupdate(Unit.root);
747
+ Unit.process(Unit.root);
434
748
  Unit.update(Unit.root);
435
749
  });
436
750
  }
@@ -487,7 +801,7 @@
487
801
  this._.listeners.set(type, listener, { element: this.element, execute });
488
802
  Unit.type2units.add(type, this);
489
803
  if (/^[A-Za-z]/.test(type)) {
490
- this.element.addEventListener(type, execute, options);
804
+ this._.eventManager.add({ element: this.element, type, listener: execute, options });
491
805
  }
492
806
  }
493
807
  });
@@ -500,11 +814,11 @@
500
814
  }
501
815
  (listener ? [listener] : [...this._.listeners.keys(type)]).forEach((listener) => {
502
816
  const item = this._.listeners.get(type, listener);
503
- if (item !== undefined) {
504
- this._.listeners.delete(type, listener);
505
- if (/^[A-Za-z]/.test(type)) {
506
- item.element.removeEventListener(type, item.execute);
507
- }
817
+ if (item === undefined)
818
+ return;
819
+ this._.listeners.delete(type, listener);
820
+ if (/^[A-Za-z]/.test(type)) {
821
+ this._.eventManager.remove({ type, listener: item.execute });
508
822
  }
509
823
  });
510
824
  if (this._.listeners.has(type) === false) {
@@ -923,279 +1237,12 @@
923
1237
  };
924
1238
  }
925
1239
 
926
- function ResizeEvent(resize) {
927
- const observer = new ResizeObserver(xnew$1.scope((entries) => {
928
- for (const entry of entries) {
929
- xnew$1.emit('-resize');
930
- break;
931
- }
932
- }));
933
- if (resize.element) {
934
- observer.observe(resize.element);
935
- }
936
- resize.on('finalize', () => {
937
- if (resize.element) {
938
- observer.unobserve(resize.element);
939
- }
940
- });
941
- }
942
- function DirectEvent(unit) {
943
- const state = {};
944
- const keydown = xnew$1.scope((event) => {
945
- state[event.code] = 1;
946
- xnew$1.emit('-keydown', { event, type: '-keydown', code: event.code });
947
- if (['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(event.code)) {
948
- xnew$1.emit('-keydown.arrow', { event, type: '-keydown.arrow', code: event.code, vector: getVector() });
949
- }
950
- });
951
- const keyup = xnew$1.scope((event) => {
952
- state[event.code] = 0;
953
- xnew$1.emit('-keyup', { event, type: '-keyup', code: event.code });
954
- if (['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(event.code)) {
955
- xnew$1.emit('-keyup.arrow', { event, type: '-keyup.arrow', code: event.code, vector: getVector() });
956
- }
957
- });
958
- window.addEventListener('keydown', keydown);
959
- window.addEventListener('keyup', keyup);
960
- unit.on('finalize', () => {
961
- window.removeEventListener('keydown', keydown);
962
- window.removeEventListener('keyup', keyup);
963
- });
964
- function getVector() {
965
- return {
966
- x: (state['ArrowLeft'] ? -1 : 0) + (state['ArrowRight'] ? +1 : 0),
967
- y: (state['ArrowUp'] ? -1 : 0) + (state['ArrowDown'] ? +1 : 0)
968
- };
969
- }
970
- const internal = xnew$1();
971
- internal.on('pointerdown', (event) => xnew$1.emit('-pointerdown', { event, position: getPosition(unit.element, event) }));
972
- internal.on('pointermove', (event) => xnew$1.emit('-pointermove', { event, position: getPosition(unit.element, event) }));
973
- internal.on('pointerup', (event) => xnew$1.emit('-pointerup', { event, position: getPosition(unit.element, event) }));
974
- internal.on('wheel', (event) => xnew$1.emit('-wheel', { event, delta: { x: event.wheelDeltaX, y: event.wheelDeltaY } }));
975
- internal.on('click', (event) => xnew$1.emit('-click', { event, position: getPosition(unit.element, event) }));
976
- internal.on('pointerover', (event) => xnew$1.emit('-pointerover', { event, position: getPosition(unit.element, event) }));
977
- internal.on('pointerout', (event) => xnew$1.emit('-pointerout', { event, position: getPosition(unit.element, event) }));
978
- const pointerdownoutside = xnew$1.scope((event) => {
979
- if (unit.element.contains(event.target) === false) {
980
- xnew$1.emit('-pointerdown.outside', { event, position: getPosition(unit.element, event) });
981
- }
982
- });
983
- const pointerupoutside = xnew$1.scope((event) => {
984
- if (unit.element.contains(event.target) === false) {
985
- xnew$1.emit('-pointerup.outside', { event, position: getPosition(unit.element, event) });
986
- }
987
- });
988
- const clickoutside = xnew$1.scope((event) => {
989
- if (unit.element.contains(event.target) === false) {
990
- xnew$1.emit('-click.outside', { event, position: getPosition(unit.element, event) });
991
- }
992
- });
993
- document.addEventListener('pointerdown', pointerdownoutside);
994
- document.addEventListener('pointerup', pointerupoutside);
995
- document.addEventListener('click', clickoutside);
996
- unit.on('finalize', () => {
997
- document.removeEventListener('pointerdown', pointerdownoutside);
998
- document.removeEventListener('pointerup', pointerupoutside);
999
- document.removeEventListener('click', clickoutside);
1000
- });
1001
- const drag = xnew$1(DragEvent);
1002
- drag.on('-dragstart', (...args) => xnew$1.emit('-dragstart', ...args));
1003
- drag.on('-dragmove', (...args) => xnew$1.emit('-dragmove', ...args));
1004
- drag.on('-dragend', (...args) => xnew$1.emit('-dragend', ...args));
1005
- drag.on('-dragcancel', (...args) => xnew$1.emit('-dragcancel', ...args));
1006
- const gesture = xnew$1(GestureEvent);
1007
- gesture.on('-gesturestart', (...args) => xnew$1.emit('-gesturestart', ...args));
1008
- gesture.on('-gesturemove', (...args) => xnew$1.emit('-gesturemove', ...args));
1009
- gesture.on('-gestureend', (...args) => xnew$1.emit('-gestureend', ...args));
1010
- gesture.on('-gesturecancel', (...args) => xnew$1.emit('-gesturecancel', ...args));
1011
- }
1012
- function KeyboardEvent(keyboard) {
1013
- const state = {};
1014
- const keydown = xnew$1.scope((event) => {
1015
- state[event.code] = 1;
1016
- xnew$1.emit('-keydown', { event, type: '-keydown', code: event.code });
1017
- if (['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(event.code)) {
1018
- xnew$1.emit('-keydown.arrow', { event, type: '-keydown.arrow', code: event.code, vector: getVector() });
1019
- }
1020
- });
1021
- const keyup = xnew$1.scope((event) => {
1022
- state[event.code] = 0;
1023
- xnew$1.emit('-keyup', { event, type: '-keyup', code: event.code });
1024
- if (['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(event.code)) {
1025
- xnew$1.emit('-keyup.arrow', { event, type: '-keyup.arrow', code: event.code, vector: getVector() });
1026
- }
1027
- });
1028
- window.addEventListener('keydown', keydown);
1029
- window.addEventListener('keyup', keyup);
1030
- keyboard.on('finalize', () => {
1031
- window.removeEventListener('keydown', keydown);
1032
- window.removeEventListener('keyup', keyup);
1033
- });
1034
- function getVector() {
1035
- return {
1036
- x: (state['ArrowLeft'] ? -1 : 0) + (state['ArrowRight'] ? +1 : 0),
1037
- y: (state['ArrowUp'] ? -1 : 0) + (state['ArrowDown'] ? +1 : 0)
1038
- };
1039
- }
1040
- }
1041
- function PointerEvent(unit) {
1042
- const internal = xnew$1();
1043
- internal.on('pointerdown', (event) => xnew$1.emit('-pointerdown', { event, position: getPosition(unit.element, event) }));
1044
- internal.on('pointermove', (event) => xnew$1.emit('-pointermove', { event, position: getPosition(unit.element, event) }));
1045
- internal.on('pointerup', (event) => xnew$1.emit('-pointerup', { event, position: getPosition(unit.element, event) }));
1046
- internal.on('wheel', (event) => xnew$1.emit('-wheel', { event, delta: { x: event.wheelDeltaX, y: event.wheelDeltaY } }));
1047
- internal.on('click', (event) => xnew$1.emit('-click', { event, position: getPosition(unit.element, event) }));
1048
- internal.on('pointerover', (event) => xnew$1.emit('-pointerover', { event, position: getPosition(unit.element, event) }));
1049
- internal.on('pointerout', (event) => xnew$1.emit('-pointerout', { event, position: getPosition(unit.element, event) }));
1050
- const pointerdownoutside = xnew$1.scope((event) => {
1051
- if (unit.element.contains(event.target) === false) {
1052
- xnew$1.emit('-pointerdown.outside', { event, position: getPosition(unit.element, event) });
1053
- }
1054
- });
1055
- const pointerupoutside = xnew$1.scope((event) => {
1056
- if (unit.element.contains(event.target) === false) {
1057
- xnew$1.emit('-pointerup.outside', { event, position: getPosition(unit.element, event) });
1058
- }
1059
- });
1060
- const clickoutside = xnew$1.scope((event) => {
1061
- if (unit.element.contains(event.target) === false) {
1062
- xnew$1.emit('-click.outside', { event, position: getPosition(unit.element, event) });
1063
- }
1064
- });
1065
- document.addEventListener('pointerdown', pointerdownoutside);
1066
- document.addEventListener('pointerup', pointerupoutside);
1067
- document.addEventListener('click', clickoutside);
1068
- unit.on('finalize', () => {
1069
- document.removeEventListener('pointerdown', pointerdownoutside);
1070
- document.removeEventListener('pointerup', pointerupoutside);
1071
- document.removeEventListener('click', clickoutside);
1072
- });
1073
- const drag = xnew$1(DragEvent);
1074
- drag.on('-dragstart', (...args) => xnew$1.emit('-dragstart', ...args));
1075
- drag.on('-dragmove', (...args) => xnew$1.emit('-dragmove', ...args));
1076
- drag.on('-dragend', (...args) => xnew$1.emit('-dragend', ...args));
1077
- drag.on('-dragcancel', (...args) => xnew$1.emit('-dragcancel', ...args));
1078
- const gesture = xnew$1(GestureEvent);
1079
- gesture.on('-gesturestart', (...args) => xnew$1.emit('-gesturestart', ...args));
1080
- gesture.on('-gesturemove', (...args) => xnew$1.emit('-gesturemove', ...args));
1081
- gesture.on('-gestureend', (...args) => xnew$1.emit('-gestureend', ...args));
1082
- gesture.on('-gesturecancel', (...args) => xnew$1.emit('-gesturecancel', ...args));
1083
- }
1084
- function DragEvent(unit) {
1085
- const pointerdown = xnew$1.scope((event) => {
1086
- const id = event.pointerId;
1087
- const position = getPosition(unit.element, event);
1088
- let previous = position;
1089
- let connect = true;
1090
- const pointermove = xnew$1.scope((event) => {
1091
- if (event.pointerId === id) {
1092
- const position = getPosition(unit.element, event);
1093
- const delta = { x: position.x - previous.x, y: position.y - previous.y };
1094
- xnew$1.emit('-dragmove', { event, position, delta });
1095
- previous = position;
1096
- }
1097
- });
1098
- const pointerup = xnew$1.scope((event) => {
1099
- if (event.pointerId === id) {
1100
- const position = getPosition(unit.element, event);
1101
- xnew$1.emit('-dragend', { event, position, });
1102
- remove();
1103
- }
1104
- });
1105
- const pointercancel = xnew$1.scope((event) => {
1106
- if (event.pointerId === id) {
1107
- const position = getPosition(unit.element, event);
1108
- xnew$1.emit('-dragcancel', { event, position, });
1109
- remove();
1110
- }
1111
- });
1112
- window.addEventListener('pointermove', pointermove);
1113
- window.addEventListener('pointerup', pointerup);
1114
- window.addEventListener('pointercancel', pointercancel);
1115
- function remove() {
1116
- if (connect === true) {
1117
- window.removeEventListener('pointermove', pointermove);
1118
- window.removeEventListener('pointerup', pointerup);
1119
- window.removeEventListener('pointercancel', pointercancel);
1120
- connect = false;
1121
- }
1122
- }
1123
- xnew$1((unit) => unit.on('-finalize', remove));
1124
- xnew$1.emit('-dragstart', { event, position });
1125
- });
1126
- unit.on('pointerdown', pointerdown);
1127
- }
1128
- function GestureEvent(unit) {
1129
- const drag = xnew$1(DragEvent);
1130
- let isActive = false;
1131
- const map = new Map();
1132
- drag.on('-dragstart', ({ event, position }) => {
1133
- map.set(event.pointerId, Object.assign({}, position));
1134
- isActive = map.size === 2 ? true : false;
1135
- if (isActive === true) {
1136
- xnew$1.emit('-gesturestart', {});
1137
- }
1138
- });
1139
- drag.on('-dragmove', ({ event, position, delta }) => {
1140
- if (map.size >= 2 && isActive === true) {
1141
- const a = map.get(event.pointerId);
1142
- const b = getOthers(event.pointerId)[0];
1143
- let scale = 0.0;
1144
- {
1145
- const v = { x: a.x - b.x, y: a.y - b.y };
1146
- const s = v.x * v.x + v.y * v.y;
1147
- scale = 1 + (s > 0.0 ? (v.x * delta.x + v.y * delta.y) / s : 0);
1148
- }
1149
- // let rotate = 0.0;
1150
- // {
1151
- // const c = { x: a.x + delta.x, y: a.y + delta.y };
1152
- // const v1 = { x: a.x - b.x, y: a.y - b.y };
1153
- // const v2 = { x: c.x - b.x, y: c.y - b.y };
1154
- // const l1 = Math.sqrt(v1.x * v1.x + v1.y * v1.y);
1155
- // const l2 = Math.sqrt(v2.x * v2.x + v2.y * v2.y);
1156
- // if (l1 > 0.0 && l2 > 0.0) {
1157
- // const angle = Math.acos((v1.x * v2.x + v1.y * v2.y) / (l1 * l2));
1158
- // const sign = v1.x * v2.y - v1.y * v2.x;
1159
- // rotate = sign > 0.0 ? +angle : -angle;
1160
- // }
1161
- // }
1162
- xnew$1.emit('-gesturemove', { event, position, delta, scale });
1163
- }
1164
- map.set(event.pointerId, position);
1165
- });
1166
- drag.on('-dragend', ({ event }) => {
1167
- if (isActive === true) {
1168
- xnew$1.emit('-gestureend', {});
1169
- }
1170
- isActive = false;
1171
- map.delete(event.pointerId);
1172
- });
1173
- drag.on('-dragcancel', ({ event }) => {
1174
- if (isActive === true) {
1175
- xnew$1.emit('-gesturecancel', { event });
1176
- }
1177
- isActive = false;
1178
- map.delete(event.pointerId);
1179
- });
1180
- function getOthers(id) {
1181
- const backup = map.get(id);
1182
- map.delete(id);
1183
- const others = [...map.values()];
1184
- map.set(id, backup);
1185
- return others;
1186
- }
1187
- }
1188
- function getPosition(element, event) {
1189
- const rect = element.getBoundingClientRect();
1190
- return { x: event.clientX - rect.left, y: event.clientY - rect.top };
1191
- }
1192
-
1193
- function Screen(screen, { width = 640, height = 480, fit = 'contain' } = {}) {
1240
+ function Screen(unit, { width = 640, height = 480, fit = 'contain' } = {}) {
1194
1241
  const size = { width, height };
1195
1242
  const wrapper = xnew$1.nest('<div style="position: relative; width: 100%; height: 100%; overflow: hidden;">');
1243
+ unit.on('resize', resize);
1196
1244
  const absolute = xnew$1.nest('<div style="position: absolute; margin: auto; container-type: size; overflow: hidden;">');
1197
1245
  const canvas = xnew$1(`<canvas width="${width}" height="${height}" style="width: 100%; height: 100%; vertical-align: bottom; user-select: none; user-drag: none; pointer-events: auto;">`);
1198
- xnew$1(wrapper, ResizeEvent).on('-resize', resize);
1199
1246
  resize();
1200
1247
  function resize() {
1201
1248
  const aspect = size.width / size.height;
@@ -1336,15 +1383,14 @@
1336
1383
  const absolute = xnew$1.nest(`<div style="position: absolute; top: ${y}px; left: ${x}px;">`);
1337
1384
  xnew$1.context('xnew.dragframe', { frame, absolute });
1338
1385
  }
1339
- function DragTarget(target, {} = {}) {
1386
+ function DragTarget(unit, {} = {}) {
1340
1387
  const { frame, absolute } = xnew$1.context('xnew.dragframe');
1341
- xnew$1.nest('<div>');
1342
- const pointer = xnew$1(absolute.parentElement, PointerEvent);
1388
+ const target = xnew$1(absolute.parentElement);
1343
1389
  const current = { x: 0, y: 0 };
1344
1390
  const offset = { x: 0, y: 0 };
1345
1391
  let dragged = false;
1346
- pointer.on('-dragstart', ({ event, position }) => {
1347
- if (target.element.contains(event.target) === false)
1392
+ target.on('dragstart', ({ event, position }) => {
1393
+ if (unit.element.contains(event.target) === false)
1348
1394
  return;
1349
1395
  dragged = true;
1350
1396
  offset.x = position.x - parseFloat(absolute.style.left || '0');
@@ -1352,7 +1398,7 @@
1352
1398
  current.x = position.x - offset.x;
1353
1399
  current.y = position.y - offset.y;
1354
1400
  });
1355
- pointer.on('-dragmove', ({ event, delta }) => {
1401
+ target.on('dragmove', ({ event, delta }) => {
1356
1402
  if (dragged !== true)
1357
1403
  return;
1358
1404
  current.x += delta.x;
@@ -1360,9 +1406,10 @@
1360
1406
  absolute.style.left = `${current.x}px`;
1361
1407
  absolute.style.top = `${current.y}px`;
1362
1408
  });
1363
- pointer.on('-dragcancel -dragend', ({ event }) => {
1409
+ target.on('dragend', ({ event }) => {
1364
1410
  dragged = false;
1365
1411
  });
1412
+ xnew$1.nest('<div>');
1366
1413
  }
1367
1414
 
1368
1415
  //----------------------------------------------------------------------------------------------------
@@ -1371,7 +1418,7 @@
1371
1418
  function SVGTemplate(self, { stroke = 'currentColor', strokeOpacity = 0.8, strokeWidth = 2, strokeLinejoin = 'round', fill = null, fillOpacity = 0.8 }) {
1372
1419
  xnew$1.nest(`<svg
1373
1420
  viewBox="0 0 100 100"
1374
- style="position: absolute; width: 100%; height: 100%; pointer-select: none;
1421
+ style="position: absolute; width: 100%; height: 100%; select: none;
1375
1422
  stroke: ${stroke}; stroke-opacity: ${strokeOpacity}; stroke-width: ${strokeWidth}; stroke-linejoin: ${strokeLinejoin};
1376
1423
  ${fill ? `fill: ${fill}; fill-opacity: ${fillOpacity};` : ''}
1377
1424
  ">`);
@@ -1381,7 +1428,7 @@
1381
1428
  const internal = xnew$1((unit) => {
1382
1429
  let newsize = Math.min(outer.clientWidth, outer.clientHeight);
1383
1430
  const inner = xnew$1.nest(`<div style="position: absolute; width: ${newsize}px; height: ${newsize}px; margin: auto; inset: 0; cursor: pointer; pointer-select: none; pointer-events: auto; overflow: hidden;">`);
1384
- xnew$1(outer, ResizeEvent).on('-resize', () => {
1431
+ xnew$1(outer).on('resize', () => {
1385
1432
  newsize = Math.min(outer.clientWidth, outer.clientHeight);
1386
1433
  inner.style.width = `${newsize}px`;
1387
1434
  inner.style.height = `${newsize}px`;
@@ -1397,22 +1444,21 @@
1397
1444
  xnew$1.extend(SVGTemplate, { fill, fillOpacity, stroke, strokeOpacity, strokeWidth, strokeLinejoin });
1398
1445
  xnew$1('<circle cx="50" cy="50" r="23">');
1399
1446
  });
1400
- const pointer = xnew$1(PointerEvent);
1401
- pointer.on('-dragstart', ({ event, position }) => {
1447
+ unit.on('dragstart', ({ event, position }) => {
1402
1448
  const vector = getVector(position);
1403
1449
  target.element.style.filter = 'brightness(90%)';
1404
1450
  target.element.style.left = vector.x * newsize / 4 + 'px';
1405
1451
  target.element.style.top = vector.y * newsize / 4 + 'px';
1406
1452
  xnew$1.emit('-down', { vector });
1407
1453
  });
1408
- pointer.on('-dragmove', ({ event, position }) => {
1454
+ unit.on('dragmove', ({ event, position }) => {
1409
1455
  const vector = getVector(position);
1410
1456
  target.element.style.filter = 'brightness(90%)';
1411
1457
  target.element.style.left = vector.x * newsize / 4 + 'px';
1412
1458
  target.element.style.top = vector.y * newsize / 4 + 'px';
1413
1459
  xnew$1.emit('-move', { vector });
1414
1460
  });
1415
- pointer.on('-dragend', ({ event }) => {
1461
+ unit.on('dragend', ({ event }) => {
1416
1462
  const vector = { x: 0, y: 0 };
1417
1463
  target.element.style.filter = '';
1418
1464
  target.element.style.left = vector.x * newsize / 4 + 'px';
@@ -1436,7 +1482,7 @@
1436
1482
  const internal = xnew$1((unit) => {
1437
1483
  let newsize = Math.min(outer.clientWidth, outer.clientHeight);
1438
1484
  const inner = xnew$1.nest(`<div style="position: absolute; width: ${newsize}px; height: ${newsize}px; margin: auto; inset: 0; cursor: pointer; pointer-select: none; pointer-events: auto; overflow: hidden;">`);
1439
- xnew$1(outer, ResizeEvent).on('-resize', () => {
1485
+ xnew$1(outer).on('resize', () => {
1440
1486
  newsize = Math.min(outer.clientWidth, outer.clientHeight);
1441
1487
  inner.style.width = `${newsize}px`;
1442
1488
  inner.style.height = `${newsize}px`;
@@ -1464,8 +1510,7 @@
1464
1510
  xnew$1('<polygon points="11 50 20 42 20 58">');
1465
1511
  xnew$1('<polygon points="89 50 80 42 80 58">');
1466
1512
  });
1467
- const pointer = xnew$1(PointerEvent);
1468
- pointer.on('-dragstart', ({ event, position }) => {
1513
+ unit.on('dragstart', ({ event, position }) => {
1469
1514
  const vector = getVector(position);
1470
1515
  targets[0].element.style.filter = (vector.y < 0) ? 'brightness(90%)' : '';
1471
1516
  targets[1].element.style.filter = (vector.y > 0) ? 'brightness(90%)' : '';
@@ -1473,7 +1518,7 @@
1473
1518
  targets[3].element.style.filter = (vector.x > 0) ? 'brightness(90%)' : '';
1474
1519
  xnew$1.emit('-down', { vector });
1475
1520
  });
1476
- pointer.on('-dragmove', ({ event, position }) => {
1521
+ unit.on('dragmove', ({ event, position }) => {
1477
1522
  const vector = getVector(position);
1478
1523
  targets[0].element.style.filter = (vector.y < 0) ? 'brightness(90%)' : '';
1479
1524
  targets[1].element.style.filter = (vector.y > 0) ? 'brightness(90%)' : '';
@@ -1481,7 +1526,7 @@
1481
1526
  targets[3].element.style.filter = (vector.x > 0) ? 'brightness(90%)' : '';
1482
1527
  xnew$1.emit('-move', { vector });
1483
1528
  });
1484
- pointer.on('-dragend', ({ event }) => {
1529
+ unit.on('dragend', ({ event }) => {
1485
1530
  const vector = { x: 0, y: 0 };
1486
1531
  targets[0].element.style.filter = '';
1487
1532
  targets[1].element.style.filter = '';
@@ -1533,249 +1578,29 @@
1533
1578
  const index = Math.floor((new Date().getTime() - start) / speed);
1534
1579
  // Display characters up to the current index (fade in)
1535
1580
  for (let i = 0; i < chars.length; i++) {
1536
- if (i <= index) {
1537
- chars[i].element.style.opacity = '1';
1538
- }
1539
- }
1540
- if (state === 0 && index >= text.length) {
1541
- action();
1542
- }
1543
- });
1544
- xnew$1.timeout(() => {
1545
- xnew$1(document.body).on('click wheel', action);
1546
- xnew$1(KeyboardEvent).on('-keydown', action);
1547
- }, 100);
1548
- function action() {
1549
- if (state === 0) {
1550
- state = 1;
1551
- for (let i = 0; i < chars.length; i++) {
1552
- chars[i].element.style.opacity = '1';
1553
- }
1554
- xnew$1.emit('-complete');
1555
- }
1556
- else if (state === 1) {
1557
- state = 2;
1558
- xnew$1.emit('-next');
1559
- }
1560
- }
1561
- }
1562
-
1563
- const context = window.AudioContext ? new window.AudioContext() : (null);
1564
- const master = context ? context.createGain() : (null);
1565
- if (context) {
1566
- master.gain.value = 0.1;
1567
- master.connect(context.destination);
1568
- }
1569
- class AudioFile {
1570
- constructor(path) {
1571
- this.promise = fetch(path)
1572
- .then((response) => response.arrayBuffer())
1573
- .then((response) => context.decodeAudioData(response))
1574
- .then((response) => { this.buffer = response; })
1575
- .catch(() => {
1576
- console.warn(`"${path}" could not be loaded.`);
1577
- });
1578
- this.amp = context.createGain();
1579
- this.amp.gain.value = 1.0;
1580
- this.amp.connect(master);
1581
- this.fade = context.createGain();
1582
- this.fade.gain.value = 1.0;
1583
- this.fade.connect(this.amp);
1584
- this.source = null;
1585
- this.played = null;
1586
- }
1587
- set volume(value) {
1588
- this.amp.gain.value = value;
1589
- }
1590
- get volume() {
1591
- return this.amp.gain.value;
1592
- }
1593
- play({ offset = 0, fade = 0, loop = false } = {}) {
1594
- if (this.buffer !== undefined && this.played === null) {
1595
- this.source = context.createBufferSource();
1596
- this.source.buffer = this.buffer;
1597
- this.source.loop = loop;
1598
- this.source.connect(this.fade);
1599
- this.played = context.currentTime;
1600
- this.source.playbackRate.value = 1;
1601
- this.source.start(context.currentTime, offset / 1000);
1602
- // Apply fade-in effect if fade duration is specified
1603
- if (fade > 0) {
1604
- this.fade.gain.setValueAtTime(0, context.currentTime);
1605
- this.fade.gain.linearRampToValueAtTime(1.0, context.currentTime + fade / 1000);
1606
- }
1607
- this.source.onended = () => {
1608
- var _a;
1609
- this.played = null;
1610
- (_a = this.source) === null || _a === void 0 ? void 0 : _a.disconnect();
1611
- this.source = null;
1612
- };
1613
- }
1614
- }
1615
- pause({ fade = 0 } = {}) {
1616
- var _a, _b;
1617
- if (this.buffer !== undefined && this.played !== null) {
1618
- const elapsed = (context.currentTime - this.played) % this.buffer.duration * 1000;
1619
- // Apply fade-out effect if fade duration is specified
1620
- if (fade > 0) {
1621
- this.fade.gain.setValueAtTime(1.0, context.currentTime);
1622
- this.fade.gain.linearRampToValueAtTime(0, context.currentTime + fade / 1000);
1623
- (_a = this.source) === null || _a === void 0 ? void 0 : _a.stop(context.currentTime + fade / 1000);
1624
- }
1625
- else {
1626
- (_b = this.source) === null || _b === void 0 ? void 0 : _b.stop(context.currentTime);
1627
- }
1628
- this.played = null;
1629
- return elapsed;
1630
- }
1631
- }
1632
- clear() {
1633
- var _a;
1634
- this.amp.disconnect();
1635
- this.fade.disconnect();
1636
- (_a = this.source) === null || _a === void 0 ? void 0 : _a.disconnect();
1637
- }
1638
- }
1639
- const keymap = {
1640
- 'A0': 27.500, 'A#0': 29.135, 'B0': 30.868,
1641
- 'C1': 32.703, 'C#1': 34.648, 'D1': 36.708, 'D#1': 38.891, 'E1': 41.203, 'F1': 43.654, 'F#1': 46.249, 'G1': 48.999, 'G#1': 51.913, 'A1': 55.000, 'A#1': 58.270, 'B1': 61.735,
1642
- 'C2': 65.406, 'C#2': 69.296, 'D2': 73.416, 'D#2': 77.782, 'E2': 82.407, 'F2': 87.307, 'F#2': 92.499, 'G2': 97.999, 'G#2': 103.826, 'A2': 110.000, 'A#2': 116.541, 'B2': 123.471,
1643
- 'C3': 130.813, 'C#3': 138.591, 'D3': 146.832, 'D#3': 155.563, 'E3': 164.814, 'F3': 174.614, 'F#3': 184.997, 'G3': 195.998, 'G#3': 207.652, 'A3': 220.000, 'A#3': 233.082, 'B3': 246.942,
1644
- 'C4': 261.626, 'C#4': 277.183, 'D4': 293.665, 'D#4': 311.127, 'E4': 329.628, 'F4': 349.228, 'F#4': 369.994, 'G4': 391.995, 'G#4': 415.305, 'A4': 440.000, 'A#4': 466.164, 'B4': 493.883,
1645
- 'C5': 523.251, 'C#5': 554.365, 'D5': 587.330, 'D#5': 622.254, 'E5': 659.255, 'F5': 698.456, 'F#5': 739.989, 'G5': 783.991, 'G#5': 830.609, 'A5': 880.000, 'A#5': 932.328, 'B5': 987.767,
1646
- 'C6': 1046.502, 'C#6': 1108.731, 'D6': 1174.659, 'D#6': 1244.508, 'E6': 1318.510, 'F6': 1396.913, 'F#6': 1479.978, 'G6': 1567.982, 'G#6': 1661.219, 'A6': 1760.000, 'A#6': 1864.655, 'B6': 1975.533,
1647
- 'C7': 2093.005, 'C#7': 2217.461, 'D7': 2349.318, 'D#7': 2489.016, 'E7': 2637.020, 'F7': 2793.826, 'F#7': 2959.955, 'G7': 3135.963, 'G#7': 3322.438, 'A7': 3520.000, 'A#7': 3729.310, 'B7': 3951.066,
1648
- 'C8': 4186.009,
1649
- };
1650
- const notemap = {
1651
- '1m': 4.000, '2n': 2.000, '4n': 1.000, '8n': 0.500, '16n': 0.250, '32n': 0.125,
1652
- };
1653
- class Synthesizer {
1654
- constructor(props) { this.props = props; }
1655
- press(frequency, duration, wait) {
1656
- var _a;
1657
- const props = this.props;
1658
- const fv = typeof frequency === 'string' ? keymap[frequency] : frequency;
1659
- const dv = typeof duration === 'string' ? (notemap[duration] * 60 / ((_a = props.bpm) !== null && _a !== void 0 ? _a : 120)) : (typeof duration === 'number' ? (duration / 1000) : 0);
1660
- const start = context.currentTime + (wait !== null && wait !== void 0 ? wait : 0) / 1000;
1661
- const nodes = {};
1662
- nodes.oscillator = context.createOscillator();
1663
- nodes.oscillator.type = props.oscillator.type;
1664
- nodes.oscillator.frequency.value = fv;
1665
- if (props.oscillator.LFO) {
1666
- nodes.oscillatorLFO = context.createOscillator();
1667
- nodes.oscillatorLFODepth = context.createGain();
1668
- nodes.oscillatorLFODepth.gain.value = fv * (Math.pow(2.0, props.oscillator.LFO.amount / 12.0) - 1.0);
1669
- nodes.oscillatorLFO.type = props.oscillator.LFO.type;
1670
- nodes.oscillatorLFO.frequency.value = props.oscillator.LFO.rate;
1671
- nodes.oscillatorLFO.start(start);
1672
- nodes.oscillatorLFO.connect(nodes.oscillatorLFODepth);
1673
- nodes.oscillatorLFODepth.connect(nodes.oscillator.frequency);
1674
- }
1675
- nodes.amp = context.createGain();
1676
- nodes.amp.gain.value = 0.0;
1677
- nodes.target = context.createGain();
1678
- nodes.target.gain.value = 1.0;
1679
- nodes.amp.connect(nodes.target);
1680
- nodes.target.connect(master);
1681
- if (props.filter) {
1682
- nodes.filter = context.createBiquadFilter();
1683
- nodes.filter.type = props.filter.type;
1684
- nodes.filter.frequency.value = props.filter.cutoff;
1685
- nodes.oscillator.connect(nodes.filter);
1686
- nodes.filter.connect(nodes.amp);
1687
- }
1688
- else {
1689
- nodes.oscillator.connect(nodes.amp);
1690
- }
1691
- if (props.reverb) {
1692
- nodes.convolver = context.createConvolver();
1693
- nodes.convolver.buffer = impulseResponse({ time: props.reverb.time });
1694
- nodes.convolverDepth = context.createGain();
1695
- nodes.convolverDepth.gain.value = 1.0;
1696
- nodes.convolverDepth.gain.value *= props.reverb.mix;
1697
- nodes.target.gain.value *= (1.0 - props.reverb.mix);
1698
- nodes.amp.connect(nodes.convolver);
1699
- nodes.convolver.connect(nodes.convolverDepth);
1700
- nodes.convolverDepth.connect(master);
1701
- }
1702
- if (props.oscillator.envelope) {
1703
- const amount = fv * (Math.pow(2.0, props.oscillator.envelope.amount / 12.0) - 1.0);
1704
- startEnvelope(nodes.oscillator.frequency, fv, amount, props.oscillator.envelope.ADSR);
1705
- }
1706
- if (props.amp.envelope) {
1707
- startEnvelope(nodes.amp.gain, 0.0, props.amp.envelope.amount, props.amp.envelope.ADSR);
1708
- }
1709
- nodes.oscillator.start(start);
1710
- if (dv > 0) {
1711
- release();
1712
- }
1713
- else {
1714
- return { release };
1715
- }
1716
- function release() {
1717
- let stop = null;
1718
- const end = dv > 0 ? dv : (context.currentTime - start);
1719
- if (props.amp.envelope) {
1720
- const ADSR = props.amp.envelope.ADSR;
1721
- const adsr = [ADSR[0] / 1000, ADSR[1] / 1000, ADSR[2], ADSR[3] / 1000];
1722
- const rate = adsr[0] === 0.0 ? 1.0 : Math.min(end / (adsr[0] + 0.001), 1.0);
1723
- stop = start + Math.max((adsr[0] + adsr[1]) * rate, end) + adsr[3];
1724
- }
1725
- else {
1726
- stop = start + end;
1727
- }
1728
- if (nodes.oscillatorLFO) {
1729
- nodes.oscillatorLFO.stop(stop);
1730
- }
1731
- if (props.oscillator.envelope) {
1732
- const amount = fv * (Math.pow(2.0, props.oscillator.envelope.amount / 12.0) - 1.0);
1733
- stopEnvelope(nodes.oscillator.frequency, fv, amount, props.oscillator.envelope.ADSR);
1734
- }
1735
- if (props.amp.envelope) {
1736
- stopEnvelope(nodes.amp.gain, 0.0, props.amp.envelope.amount, props.amp.envelope.ADSR);
1737
- }
1738
- nodes.oscillator.stop(stop);
1739
- setTimeout(() => {
1740
- var _a, _b, _c, _d, _e;
1741
- nodes.oscillator.disconnect();
1742
- nodes.amp.disconnect();
1743
- nodes.target.disconnect();
1744
- (_a = nodes.oscillatorLFO) === null || _a === void 0 ? void 0 : _a.disconnect();
1745
- (_b = nodes.oscillatorLFODepth) === null || _b === void 0 ? void 0 : _b.disconnect();
1746
- (_c = nodes.filter) === null || _c === void 0 ? void 0 : _c.disconnect();
1747
- (_d = nodes.convolver) === null || _d === void 0 ? void 0 : _d.disconnect();
1748
- (_e = nodes.convolverDepth) === null || _e === void 0 ? void 0 : _e.disconnect();
1749
- }, 2000);
1750
- }
1751
- function stopEnvelope(param, base, amount, ADSR) {
1752
- const end = dv > 0 ? dv : (context.currentTime - start);
1753
- const rate = ADSR[0] === 0.0 ? 1.0 : Math.min(end / (ADSR[0] / 1000), 1.0);
1754
- if (rate < 1.0) {
1755
- param.cancelScheduledValues(start);
1756
- param.setValueAtTime(base, start);
1757
- param.linearRampToValueAtTime(base + amount * rate, start + ADSR[0] / 1000 * rate);
1758
- param.linearRampToValueAtTime(base + amount * rate * ADSR[2], start + (ADSR[0] + ADSR[1]) / 1000 * rate);
1581
+ if (i <= index) {
1582
+ chars[i].element.style.opacity = '1';
1759
1583
  }
1760
- param.linearRampToValueAtTime(base + amount * rate * ADSR[2], start + Math.max((ADSR[0] + ADSR[1]) / 1000 * rate, dv));
1761
- param.linearRampToValueAtTime(base, start + Math.max((ADSR[0] + ADSR[1]) / 1000 * rate, end) + ADSR[3] / 1000);
1762
1584
  }
1763
- function startEnvelope(param, base, amount, ADSR) {
1764
- param.value = base;
1765
- param.setValueAtTime(base, start);
1766
- param.linearRampToValueAtTime(base + amount, start + ADSR[0] / 1000);
1767
- param.linearRampToValueAtTime(base + amount * ADSR[2], start + (ADSR[0] + ADSR[1]) / 1000);
1585
+ if (state === 0 && index >= text.length) {
1586
+ action();
1768
1587
  }
1769
- function impulseResponse({ time, decay = 2.0 }) {
1770
- const length = context.sampleRate * time / 1000;
1771
- const impulse = context.createBuffer(2, length, context.sampleRate);
1772
- const ch0 = impulse.getChannelData(0);
1773
- const ch1 = impulse.getChannelData(1);
1774
- for (let i = 0; i < length; i++) {
1775
- ch0[i] = (2 * Math.random() - 1) * Math.pow(1 - i / length, decay);
1776
- ch1[i] = (2 * Math.random() - 1) * Math.pow(1 - i / length, decay);
1588
+ });
1589
+ xnew$1.timeout(() => {
1590
+ xnew$1(document.body).on('click wheel', action);
1591
+ unit.on('keydown', action);
1592
+ }, 100);
1593
+ function action() {
1594
+ if (state === 0) {
1595
+ state = 1;
1596
+ for (let i = 0; i < chars.length; i++) {
1597
+ chars[i].element.style.opacity = '1';
1777
1598
  }
1778
- return impulse;
1599
+ xnew$1.emit('-complete');
1600
+ }
1601
+ else if (state === 1) {
1602
+ state = 2;
1603
+ xnew$1.emit('-next');
1779
1604
  }
1780
1605
  }
1781
1606
  }
@@ -3422,37 +3247,228 @@
3422
3247
  XMark(unit, props) { icon('XMark', props); },
3423
3248
  };
3424
3249
 
3425
- function VolumeController(unit, {} = {}) {
3426
- xnew$1.nest(`<div style="position: relative; width: 100%; height: 100%; display: flex; align-items: center; justify-content: flex-end; pointer-events: none; container-type: size;">`);
3427
- xnew$1.extend(PointerEvent);
3428
- unit.on('-pointerdown', ({ event }) => event.stopPropagation());
3429
- const slider = xnew$1(`<input type="range" min="0" max="100" value="${master.gain.value * 100}"
3430
- style="display: none; width: calc(96cqw - 100cqh); margin: 0 2cqw; cursor: pointer; pointer-events: auto;"
3431
- >`);
3432
- unit.on('-click:outside', () => slider.element.style.display = 'none');
3433
- const button = xnew$1((button) => {
3434
- xnew$1.nest('<div style="position: relative; width: 100cqh; height: 100cqh; cursor: pointer; pointer-events: auto;">');
3435
- let icon = xnew$1(master.gain.value > 0 ? icons.SpeakerWave : icons.SpeakerXMark);
3436
- return {
3437
- update() {
3438
- icon === null || icon === void 0 ? void 0 : icon.finalize();
3439
- icon = xnew$1(master.gain.value > 0 ? icons.SpeakerWave : icons.SpeakerXMark);
3250
+ const context = window.AudioContext ? new window.AudioContext() : (null);
3251
+ const master = context ? context.createGain() : (null);
3252
+ if (context) {
3253
+ master.gain.value = 0.1;
3254
+ master.connect(context.destination);
3255
+ }
3256
+ class AudioFile {
3257
+ constructor(path) {
3258
+ this.promise = fetch(path)
3259
+ .then((response) => response.arrayBuffer())
3260
+ .then((response) => context.decodeAudioData(response))
3261
+ .then((response) => { this.buffer = response; })
3262
+ .catch(() => {
3263
+ console.warn(`"${path}" could not be loaded.`);
3264
+ });
3265
+ this.amp = context.createGain();
3266
+ this.amp.gain.value = 1.0;
3267
+ this.amp.connect(master);
3268
+ this.fade = context.createGain();
3269
+ this.fade.gain.value = 1.0;
3270
+ this.fade.connect(this.amp);
3271
+ this.source = null;
3272
+ this.played = null;
3273
+ }
3274
+ set volume(value) {
3275
+ this.amp.gain.value = value;
3276
+ }
3277
+ get volume() {
3278
+ return this.amp.gain.value;
3279
+ }
3280
+ play({ offset = 0, fade = 0, loop = false } = {}) {
3281
+ if (this.buffer !== undefined && this.played === null) {
3282
+ this.source = context.createBufferSource();
3283
+ this.source.buffer = this.buffer;
3284
+ this.source.loop = loop;
3285
+ this.source.connect(this.fade);
3286
+ this.played = context.currentTime;
3287
+ this.source.playbackRate.value = 1;
3288
+ this.source.start(context.currentTime, offset / 1000);
3289
+ // Apply fade-in effect if fade duration is specified
3290
+ if (fade > 0) {
3291
+ this.fade.gain.setValueAtTime(0, context.currentTime);
3292
+ this.fade.gain.linearRampToValueAtTime(1.0, context.currentTime + fade / 1000);
3440
3293
  }
3441
- };
3442
- });
3443
- button.on('click', () => slider.element.style.display = slider.element.style.display !== 'none' ? 'none' : 'flex');
3444
- slider.on('input', (event) => {
3445
- master.gain.value = parseFloat(event.target.value) / 100;
3446
- button.update();
3447
- });
3294
+ this.source.onended = () => {
3295
+ var _a;
3296
+ this.played = null;
3297
+ (_a = this.source) === null || _a === void 0 ? void 0 : _a.disconnect();
3298
+ this.source = null;
3299
+ };
3300
+ }
3301
+ }
3302
+ pause({ fade = 0 } = {}) {
3303
+ var _a, _b;
3304
+ if (this.buffer !== undefined && this.played !== null) {
3305
+ const elapsed = (context.currentTime - this.played) % this.buffer.duration * 1000;
3306
+ // Apply fade-out effect if fade duration is specified
3307
+ if (fade > 0) {
3308
+ this.fade.gain.setValueAtTime(1.0, context.currentTime);
3309
+ this.fade.gain.linearRampToValueAtTime(0, context.currentTime + fade / 1000);
3310
+ (_a = this.source) === null || _a === void 0 ? void 0 : _a.stop(context.currentTime + fade / 1000);
3311
+ }
3312
+ else {
3313
+ (_b = this.source) === null || _b === void 0 ? void 0 : _b.stop(context.currentTime);
3314
+ }
3315
+ this.played = null;
3316
+ return elapsed;
3317
+ }
3318
+ }
3319
+ clear() {
3320
+ var _a;
3321
+ this.amp.disconnect();
3322
+ this.fade.disconnect();
3323
+ (_a = this.source) === null || _a === void 0 ? void 0 : _a.disconnect();
3324
+ }
3325
+ }
3326
+ const keymap = {
3327
+ 'A0': 27.500, 'A#0': 29.135, 'B0': 30.868,
3328
+ 'C1': 32.703, 'C#1': 34.648, 'D1': 36.708, 'D#1': 38.891, 'E1': 41.203, 'F1': 43.654, 'F#1': 46.249, 'G1': 48.999, 'G#1': 51.913, 'A1': 55.000, 'A#1': 58.270, 'B1': 61.735,
3329
+ 'C2': 65.406, 'C#2': 69.296, 'D2': 73.416, 'D#2': 77.782, 'E2': 82.407, 'F2': 87.307, 'F#2': 92.499, 'G2': 97.999, 'G#2': 103.826, 'A2': 110.000, 'A#2': 116.541, 'B2': 123.471,
3330
+ 'C3': 130.813, 'C#3': 138.591, 'D3': 146.832, 'D#3': 155.563, 'E3': 164.814, 'F3': 174.614, 'F#3': 184.997, 'G3': 195.998, 'G#3': 207.652, 'A3': 220.000, 'A#3': 233.082, 'B3': 246.942,
3331
+ 'C4': 261.626, 'C#4': 277.183, 'D4': 293.665, 'D#4': 311.127, 'E4': 329.628, 'F4': 349.228, 'F#4': 369.994, 'G4': 391.995, 'G#4': 415.305, 'A4': 440.000, 'A#4': 466.164, 'B4': 493.883,
3332
+ 'C5': 523.251, 'C#5': 554.365, 'D5': 587.330, 'D#5': 622.254, 'E5': 659.255, 'F5': 698.456, 'F#5': 739.989, 'G5': 783.991, 'G#5': 830.609, 'A5': 880.000, 'A#5': 932.328, 'B5': 987.767,
3333
+ 'C6': 1046.502, 'C#6': 1108.731, 'D6': 1174.659, 'D#6': 1244.508, 'E6': 1318.510, 'F6': 1396.913, 'F#6': 1479.978, 'G6': 1567.982, 'G#6': 1661.219, 'A6': 1760.000, 'A#6': 1864.655, 'B6': 1975.533,
3334
+ 'C7': 2093.005, 'C#7': 2217.461, 'D7': 2349.318, 'D#7': 2489.016, 'E7': 2637.020, 'F7': 2793.826, 'F#7': 2959.955, 'G7': 3135.963, 'G#7': 3322.438, 'A7': 3520.000, 'A#7': 3729.310, 'B7': 3951.066,
3335
+ 'C8': 4186.009,
3336
+ };
3337
+ const notemap = {
3338
+ '1m': 4.000, '2n': 2.000, '4n': 1.000, '8n': 0.500, '16n': 0.250, '32n': 0.125,
3339
+ };
3340
+ class Synthesizer {
3341
+ constructor(props) { this.props = props; }
3342
+ press(frequency, duration, wait) {
3343
+ var _a;
3344
+ const props = this.props;
3345
+ const fv = typeof frequency === 'string' ? keymap[frequency] : frequency;
3346
+ const dv = typeof duration === 'string' ? (notemap[duration] * 60 / ((_a = props.bpm) !== null && _a !== void 0 ? _a : 120)) : (typeof duration === 'number' ? (duration / 1000) : 0);
3347
+ const start = context.currentTime + (wait !== null && wait !== void 0 ? wait : 0) / 1000;
3348
+ const nodes = {};
3349
+ nodes.oscillator = context.createOscillator();
3350
+ nodes.oscillator.type = props.oscillator.type;
3351
+ nodes.oscillator.frequency.value = fv;
3352
+ if (props.oscillator.LFO) {
3353
+ nodes.oscillatorLFO = context.createOscillator();
3354
+ nodes.oscillatorLFODepth = context.createGain();
3355
+ nodes.oscillatorLFODepth.gain.value = fv * (Math.pow(2.0, props.oscillator.LFO.amount / 12.0) - 1.0);
3356
+ nodes.oscillatorLFO.type = props.oscillator.LFO.type;
3357
+ nodes.oscillatorLFO.frequency.value = props.oscillator.LFO.rate;
3358
+ nodes.oscillatorLFO.start(start);
3359
+ nodes.oscillatorLFO.connect(nodes.oscillatorLFODepth);
3360
+ nodes.oscillatorLFODepth.connect(nodes.oscillator.frequency);
3361
+ }
3362
+ nodes.amp = context.createGain();
3363
+ nodes.amp.gain.value = 0.0;
3364
+ nodes.target = context.createGain();
3365
+ nodes.target.gain.value = 1.0;
3366
+ nodes.amp.connect(nodes.target);
3367
+ nodes.target.connect(master);
3368
+ if (props.filter) {
3369
+ nodes.filter = context.createBiquadFilter();
3370
+ nodes.filter.type = props.filter.type;
3371
+ nodes.filter.frequency.value = props.filter.cutoff;
3372
+ nodes.oscillator.connect(nodes.filter);
3373
+ nodes.filter.connect(nodes.amp);
3374
+ }
3375
+ else {
3376
+ nodes.oscillator.connect(nodes.amp);
3377
+ }
3378
+ if (props.reverb) {
3379
+ nodes.convolver = context.createConvolver();
3380
+ nodes.convolver.buffer = impulseResponse({ time: props.reverb.time });
3381
+ nodes.convolverDepth = context.createGain();
3382
+ nodes.convolverDepth.gain.value = 1.0;
3383
+ nodes.convolverDepth.gain.value *= props.reverb.mix;
3384
+ nodes.target.gain.value *= (1.0 - props.reverb.mix);
3385
+ nodes.amp.connect(nodes.convolver);
3386
+ nodes.convolver.connect(nodes.convolverDepth);
3387
+ nodes.convolverDepth.connect(master);
3388
+ }
3389
+ if (props.oscillator.envelope) {
3390
+ const amount = fv * (Math.pow(2.0, props.oscillator.envelope.amount / 12.0) - 1.0);
3391
+ startEnvelope(nodes.oscillator.frequency, fv, amount, props.oscillator.envelope.ADSR);
3392
+ }
3393
+ if (props.amp.envelope) {
3394
+ startEnvelope(nodes.amp.gain, 0.0, props.amp.envelope.amount, props.amp.envelope.ADSR);
3395
+ }
3396
+ nodes.oscillator.start(start);
3397
+ if (dv > 0) {
3398
+ release();
3399
+ }
3400
+ else {
3401
+ return { release };
3402
+ }
3403
+ function release() {
3404
+ let stop = null;
3405
+ const end = dv > 0 ? dv : (context.currentTime - start);
3406
+ if (props.amp.envelope) {
3407
+ const ADSR = props.amp.envelope.ADSR;
3408
+ const adsr = [ADSR[0] / 1000, ADSR[1] / 1000, ADSR[2], ADSR[3] / 1000];
3409
+ const rate = adsr[0] === 0.0 ? 1.0 : Math.min(end / (adsr[0] + 0.001), 1.0);
3410
+ stop = start + Math.max((adsr[0] + adsr[1]) * rate, end) + adsr[3];
3411
+ }
3412
+ else {
3413
+ stop = start + end;
3414
+ }
3415
+ if (nodes.oscillatorLFO) {
3416
+ nodes.oscillatorLFO.stop(stop);
3417
+ }
3418
+ if (props.oscillator.envelope) {
3419
+ const amount = fv * (Math.pow(2.0, props.oscillator.envelope.amount / 12.0) - 1.0);
3420
+ stopEnvelope(nodes.oscillator.frequency, fv, amount, props.oscillator.envelope.ADSR);
3421
+ }
3422
+ if (props.amp.envelope) {
3423
+ stopEnvelope(nodes.amp.gain, 0.0, props.amp.envelope.amount, props.amp.envelope.ADSR);
3424
+ }
3425
+ nodes.oscillator.stop(stop);
3426
+ setTimeout(() => {
3427
+ var _a, _b, _c, _d, _e;
3428
+ nodes.oscillator.disconnect();
3429
+ nodes.amp.disconnect();
3430
+ nodes.target.disconnect();
3431
+ (_a = nodes.oscillatorLFO) === null || _a === void 0 ? void 0 : _a.disconnect();
3432
+ (_b = nodes.oscillatorLFODepth) === null || _b === void 0 ? void 0 : _b.disconnect();
3433
+ (_c = nodes.filter) === null || _c === void 0 ? void 0 : _c.disconnect();
3434
+ (_d = nodes.convolver) === null || _d === void 0 ? void 0 : _d.disconnect();
3435
+ (_e = nodes.convolverDepth) === null || _e === void 0 ? void 0 : _e.disconnect();
3436
+ }, 2000);
3437
+ }
3438
+ function stopEnvelope(param, base, amount, ADSR) {
3439
+ const end = dv > 0 ? dv : (context.currentTime - start);
3440
+ const rate = ADSR[0] === 0.0 ? 1.0 : Math.min(end / (ADSR[0] / 1000), 1.0);
3441
+ if (rate < 1.0) {
3442
+ param.cancelScheduledValues(start);
3443
+ param.setValueAtTime(base, start);
3444
+ param.linearRampToValueAtTime(base + amount * rate, start + ADSR[0] / 1000 * rate);
3445
+ param.linearRampToValueAtTime(base + amount * rate * ADSR[2], start + (ADSR[0] + ADSR[1]) / 1000 * rate);
3446
+ }
3447
+ param.linearRampToValueAtTime(base + amount * rate * ADSR[2], start + Math.max((ADSR[0] + ADSR[1]) / 1000 * rate, dv));
3448
+ param.linearRampToValueAtTime(base, start + Math.max((ADSR[0] + ADSR[1]) / 1000 * rate, end) + ADSR[3] / 1000);
3449
+ }
3450
+ function startEnvelope(param, base, amount, ADSR) {
3451
+ param.value = base;
3452
+ param.setValueAtTime(base, start);
3453
+ param.linearRampToValueAtTime(base + amount, start + ADSR[0] / 1000);
3454
+ param.linearRampToValueAtTime(base + amount * ADSR[2], start + (ADSR[0] + ADSR[1]) / 1000);
3455
+ }
3456
+ function impulseResponse({ time, decay = 2.0 }) {
3457
+ const length = context.sampleRate * time / 1000;
3458
+ const impulse = context.createBuffer(2, length, context.sampleRate);
3459
+ const ch0 = impulse.getChannelData(0);
3460
+ const ch1 = impulse.getChannelData(1);
3461
+ for (let i = 0; i < length; i++) {
3462
+ ch0[i] = (2 * Math.random() - 1) * Math.pow(1 - i / length, decay);
3463
+ ch1[i] = (2 * Math.random() - 1) * Math.pow(1 - i / length, decay);
3464
+ }
3465
+ return impulse;
3466
+ }
3467
+ }
3448
3468
  }
3449
3469
 
3450
3470
  const basics = {
3451
3471
  Screen,
3452
- PointerEvent,
3453
- DirectEvent,
3454
- ResizeEvent,
3455
- KeyboardEvent,
3456
3472
  ModalFrame,
3457
3473
  ModalContent,
3458
3474
  AccordionFrame,
@@ -3467,7 +3483,6 @@
3467
3483
  DragTarget,
3468
3484
  AnalogStick,
3469
3485
  DirectionalPad,
3470
- VolumeController
3471
3486
  };
3472
3487
  const audio = {
3473
3488
  load(path) {