diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..3f6e4d4 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +# top-most EditorConfig file +root = true + +# Base rules +[*] +#改行コード +end_of_line = lf +#ファイルの末尾が改行文字ではない場合に補完 +insert_final_newline = false +indent_style = space +indent_size = 2 +charset = utf-8 +#行末の空白文字を削除 +trim_trailing_whitespace = true + +[*.md] +insert_final_newline = true \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a153747 --- /dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +_data \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..dbfe4b8 --- /dev/null +++ b/index.html @@ -0,0 +1,17 @@ + + + + + + sketch 265 + + + + + + +
+ Github + + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..fe114cb --- /dev/null +++ b/package.json @@ -0,0 +1,30 @@ +{ + "name": "sketch265", + "private": true, + "version": "0.0.0", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview" + }, + "devDependencies": { + "@types/events": "^3.0.0", + "@types/matter-js": "^0.17.7", + "@types/node": "^17.0.21", + "@types/three": "^0.141.0", + "autoprefixer": "^10.4.2", + "matter-js": "^0.18.0", + "postcss": "^8.4.6", + "snd-lib": "^1.0.1", + "three": "^0.141.0", + "typescript": "^4.5.4", + "vite": "^2.8.0", + "vite-plugin-glsl": "^0.0.8" + }, + "dependencies": { + "current-device": "^0.10.2", + "gsap": "^3.9.1", + "lil-gui": "^0.16.0", + "stats.js": "^0.17.0" + } +} diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..de5c67a --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,5 @@ +module.exports = { + plugins: [ + require('autoprefixer')() + ] +} \ No newline at end of file diff --git a/src/core/conf.ts b/src/core/conf.ts new file mode 100755 index 0000000..c24cb36 --- /dev/null +++ b/src/core/conf.ts @@ -0,0 +1,53 @@ +import { Util } from '../libs/util'; + +export class Conf { + private static _instance: Conf; + + // パラメータ + public FLG_PARAM: boolean = location.href.includes('p=yes'); + + // Stats + public FLG_STATS: boolean = location.href.includes('p=yes'); + + // パス + public PATH_IMG: string = './assets/img/'; + + // タッチデバイス + public USE_TOUCH: boolean = Util.instance.isTouchDevice(); + + // ブレイクポイント + public BREAKPOINT: number = 768; + + // PSDサイズ + public LG_PSD_WIDTH: number = 1600; + public XS_PSD_WIDTH: number = 750; + + // 簡易版 + public IS_SIMPLE: boolean = Util.instance.isPc() && Util.instance.isSafari(); + + // スマホ + public IS_PC: boolean = Util.instance.isPc(); + public IS_SP: boolean = Util.instance.isSp(); + public IS_AND: boolean = Util.instance.isAod(); + public IS_TAB: boolean = Util.instance.isIPad(); + public USE_ROLLOVER:boolean = Util.instance.isPc() && !Util.instance.isIPad() + + public ITEM_NUM:number = 20; + public STACK_NUM:number = 1; + public ITEM_SIZE:number = 2; + public COLOR_LIST:Array = [ + 0x051181, + 0xfb3c3c, + 0xfeb64a, + 0x128b8e + ]; + + + constructor() {} + public static get instance(): Conf { + if (!this._instance) { + this._instance = new Conf(); + } + return this._instance; + } +} diff --git a/src/core/fps.ts b/src/core/fps.ts new file mode 100755 index 0000000..cde062f --- /dev/null +++ b/src/core/fps.ts @@ -0,0 +1,7 @@ +export class FPS { + static HIGH: number = 0; + static MIDDLE: number = 1; + static LOW: number = 2; + + constructor() {} +} diff --git a/src/core/func.ts b/src/core/func.ts new file mode 100755 index 0000000..8e24fa8 --- /dev/null +++ b/src/core/func.ts @@ -0,0 +1,86 @@ +import { ScreenType } from './screenType'; +import { Conf } from './conf'; + +export class Func { + private static _instance: Func; + private _useFullScreen: boolean = false; + + constructor() {} + + public static get instance(): Func { + if (!this._instance) { + this._instance = new Func(); + } + return this._instance; + } + + public ratio(): number { + return window.devicePixelRatio || 1; + } + + public px(num: number): string { + return num + 'px'; + } + + public useScreen(): boolean { + return screen != undefined; + } + + public sw(): number { + return window.innerWidth; + } + + public sh(): number { + if (this._useFullScreen) { + return screen.height; + } else { + return window.innerHeight; + } + } + + public screenOffsetY(): number { + return (window.innerHeight - this.sh()) * 0.5; + } + + public screen(): number { + if (window.innerWidth <= Conf.instance.BREAKPOINT) { + return ScreenType.XS; + } else { + return ScreenType.LG; + } + } + + public isXS(): boolean { + return this.screen() == ScreenType.XS; + } + + public isLG(): boolean { + return this.screen() == ScreenType.LG; + } + + public val(xs: any, lg: any): any { + if (this.isXS()) { + return xs; + } else { + return lg; + } + } + + public r(val: number): number { + const base = this.val(Conf.instance.XS_PSD_WIDTH, Conf.instance.LG_PSD_WIDTH); + return (val / base) * this.sw(); + } + + public sin1(radian:number):number { + return Math.sin(radian) + Math.sin(2 * radian) + } + + public sin2(radian:number):number { + return ( + Math.sin(radian) + + Math.sin(2.2 * radian + 5.52) + + Math.sin(2.9 * radian + 0.93) + + Math.sin(4.6 * radian + 8.94) + ) / 4 + } +} diff --git a/src/core/mouse.ts b/src/core/mouse.ts new file mode 100755 index 0000000..84a4575 --- /dev/null +++ b/src/core/mouse.ts @@ -0,0 +1,179 @@ +import { Point } from "../libs/point"; +import { Update } from "../libs/update"; +import { Util } from "../libs/util"; + + +export class Mouse { + + private static _instance:Mouse; + + public x:number = window.innerWidth * 0.5 + public y:number = window.innerHeight * 0.5 + public old:Point = new Point() + public normal:Point = new Point() + public easeNormal:Point = new Point() + public start:Point = new Point() + public moveDist:Point = new Point() + public dist:number = 0; + public isDown:boolean = false + public usePreventDefault:boolean = true + + public onSwipe:any + + private _updateHandler:any + + constructor() { + + if(Util.instance.isTouchDevice()) { + const tg = document.querySelector('.matter') || window + tg.addEventListener('touchstart', (e:any = {}) => { + this._eTouchStart(e) + }, {passive:false}) + tg.addEventListener('touchend', () => { + this._eTouchEnd() + }, {passive:false}) + tg.addEventListener('touchmove', (e:any = {}) => { + this._eTouchMove(e) + }, {passive:false}) + } else { + window.addEventListener('mousedown', (e:any = {}) => { + this._eDown(e) + }) + window.addEventListener('mouseup', () => { + this._eUp() + }) + window.addEventListener('mousemove', (e:any = {}) => { + this._eMove(e) + }) + // document.addEventListener('wheel', (e) => { + // if(this.usePreventDefault) { + // e.preventDefault() + // e.stopPropagation() + // } + // const test = Math.abs(e.deltaY) + // if(test > 5 && this._useWheel) { + // if(this.onSwipe != undefined) this.onSwipe({move:e.deltaY}) + // this._useWheel = false + // setTimeout(() => { + // this._useWheel = true + // }, 1000) + // } + // }, {passive:false}) + } + + this._updateHandler = this._update.bind(this) + Update.instance.add(this._updateHandler) + } + + + public static get instance():Mouse { + if (!this._instance) { + this._instance = new Mouse(); + } + return this._instance; + } + + + private _eTouchStart(e:any = {}):void { + this.isDown = true + this._eTouchMove(e) + + const p:Point = this._getTouchPoint(e) + this.start.x = p.x + this.start.y = p.y + } + + + private _eTouchEnd():void { + this.isDown = false + + // 上下スワイプ判定 + const dx = this.old.x - this.x + const dy = this.old.y - this.y + // console.log(Math.abs(dy)) + if(Math.abs(dy) > 0 || Math.abs(dx) > 0) { + if(this.onSwipe != undefined) this.onSwipe({move:dy}) + } + + this.dist = 0; + // console.log(dy) + // Param.instance.setMemo(dx + ',' + dy) + } + + + private _eTouchMove(e:any = {}):void { + const p:Point = this._getTouchPoint(e) + this.old.x = this.x + this.old.y = this.y + this.x = p.x + this.y = p.y + + const dx = this.old.x - this.x + const dy = this.old.y - this.y + this.dist = Math.sqrt(dx * dx + dy * dy); + + if(this.usePreventDefault) { + e.preventDefault() + } + } + + + private _eDown(e:any = {}):void { + this.isDown = true + this._eMove(e) + + this.start.x = this.x + this.start.y = this.y + } + + + private _eUp():void { + this.isDown = false + } + + + private _eMove(e:any = {}):void { + this.old.x = this.x + this.old.y = this.y + + this.x = e.clientX + this.y = e.clientY + + const dx = this.old.x - this.x + const dy = this.old.y - this.y + this.dist = Math.sqrt(dx * dx + dy * dy); + } + + + private _getTouchPoint(e:TouchEvent):Point { + const p = new Point() + const touches:TouchList = e.touches + if(touches != null && touches.length > 0) { + p.x = touches[0].pageX + p.y = touches[0].pageY + } + return p + } + + + private _update():void { + if(this.isDown) { + this.moveDist.x = this.start.x - this.x + this.moveDist.y = this.start.y - this.y + } else { + this.moveDist.x += (0 - this.moveDist.x) * 0.25 + this.moveDist.y += (0 - this.moveDist.y) * 0.25 + } + + this.normal.x = Util.instance.map(this.x, -1, 1, 0, window.innerWidth) + this.normal.y = Util.instance.map(this.y, -1, 1, 0, window.innerHeight) + + const ease = 0.1 + this.easeNormal.x += (this.normal.x - this.easeNormal.x) * ease + this.easeNormal.y += (this.normal.y - this.easeNormal.y) * ease + + } + + + +} \ No newline at end of file diff --git a/src/core/myDisplay.ts b/src/core/myDisplay.ts new file mode 100755 index 0000000..803602a --- /dev/null +++ b/src/core/myDisplay.ts @@ -0,0 +1,141 @@ +import { Display } from '../libs/display'; +import { Update } from '../libs/update'; +import { Resize } from '../libs/resize'; +import { Point } from '../libs/point'; + +export class MyDisplay extends Display { + private _updateHandler: any; + private _resizeHandler: any; + + protected _c:number = 0; + protected _isEnter:boolean = false + protected _isOneEnter:boolean = false + protected _observer: any; + protected _elPos:Point = new Point(0, 9999); + protected _eRollOverHandler: any; + protected _eRollOutHandler: any; + + constructor(opt:any = {}) { + super(opt); + + if (opt.isDefEvent == undefined || opt.isDefEvent) { + this._updateHandler = this._update.bind(this); + Update.instance.add(this._updateHandler); + + this._resizeHandler = this._resize.bind(this); + Resize.instance.add(this._resizeHandler); + } + } + + init() { + super.init(); + } + + + // + protected _setHover() { + this._eRollOverHandler = this._eRollOver.bind(this); + this._eRollOutHandler = this._eRollOut.bind(this); + this.getEl().addEventListener('mouseenter', this._eRollOverHandler); + this.getEl().addEventListener('mouseleave', this._eRollOutHandler); + } + + + // + protected _disposeHover() { + if(this._eRollOverHandler != null) { + this.getEl().removeEventListener('mouseenter', this._eRollOverHandler); + this.getEl().removeEventListener('mouseleave', this._eRollOutHandler); + this._eRollOverHandler = null; + this._eRollOutHandler = null; + } + } + + + // + protected _eRollOver() { + } + + + // + protected _eRollOut() { + } + + + // + protected _setObserver() { + this._observer = new IntersectionObserver((e) => { + if(e != undefined) { + e.forEach((val) => { + if (val != undefined && val.intersectionRatio > 0) { + this._eEnter() + } else { + this._eLeave() + } + }) + } + }, + { + root: null, + } + ); + + setTimeout(() => { + if(this._observer != undefined && this._observer != null) { + const tg = this.getEl() + if (tg != undefined) this._observer.observe(tg) + } + }, 100) + } + + + // + protected _eEnter() { + this._isEnter = true + } + + + // + protected _eLeave() { + this._isEnter = false + } + + + protected _disposeObserver() { + if (this._observer != null || this._observer != undefined) { + this._observer.unobserve(this.getEl()); + this._observer = null; + } + } + + // 破棄 + public dispose() { + if(this._updateHandler != undefined) { + Update.instance.remove(this._updateHandler); + this._updateHandler = null; + } + + if(this._resizeHandler != undefined) { + Resize.instance.remove(this._resizeHandler); + this._resizeHandler = null; + } + + this._disposeHover(); + this._disposeObserver(); + + super.dispose(); + } + + css(el: any, obj: any): void { + const style = el.style; + for (var key in obj) { + style[key] = obj[key]; + } + } + + protected _update(): void { + this._c++ + } + + protected _resize(): void {} +} diff --git a/src/core/param.ts b/src/core/param.ts new file mode 100755 index 0000000..dae210b --- /dev/null +++ b/src/core/param.ts @@ -0,0 +1,77 @@ +import GUI from 'lil-gui'; +import Stats from 'three/examples/jsm/libs/stats.module'; +import { Conf } from './conf'; +import { Update } from '../libs/update'; +import { FPS } from '../core/fps'; +import { Color } from "three/src/math/Color"; + +export class Param { + private static _instance: Param; + + public fps: number = FPS.MIDDLE; + public colors:Array = []; + public debug:HTMLElement = document.querySelector('.l-debug') as HTMLElement; + + public selectedNo:Array = [0,0]; + + private _dat: any; + private _stats: any; + + + public main = { + bg:{value:0x000000, type:'color'}, + } + + constructor() { + if (Conf.instance.FLG_PARAM) { + this.makeParamGUI(); + } + + if (Conf.instance.FLG_STATS) { + this._stats = Stats(); + document.body.appendChild(this._stats.domElement); + } + + Update.instance.add(() => { + this._update(); + }); + } + + private _update(): void { + if (this._stats != undefined) { + this._stats.update(); + } + } + + public static get instance(): Param { + if (!this._instance) { + this._instance = new Param(); + } + return this._instance; + } + + public makeParamGUI(): void { + if (this._dat != undefined) return; + + this._dat = new GUI(); + this._add(this.main, 'main'); + } + + private _add(obj: any, folderName: string): void { + const folder = this._dat.addFolder(folderName); + for (var key in obj) { + const val: any = obj[key]; + if (val.use == undefined) { + if (val.type == 'color') { + folder.addColor(val, 'value').name(key); + } else { + if (val.list != undefined) { + folder.add(val, 'value', val.list).name(key); + } else { + folder.add(val, 'value', val.min, val.max).name(key); + } + } + } + } + } +} diff --git a/src/core/screenType.ts b/src/core/screenType.ts new file mode 100755 index 0000000..81818cc --- /dev/null +++ b/src/core/screenType.ts @@ -0,0 +1,6 @@ +export class ScreenType { + static LG: number = 0; + static XS: number = 1; + + constructor() {} +} diff --git a/src/core/scroller.ts b/src/core/scroller.ts new file mode 100755 index 0000000..b5601db --- /dev/null +++ b/src/core/scroller.ts @@ -0,0 +1,43 @@ +import { Point } from '../libs/point'; +import { Update } from '../libs/update'; + +export class Scroller { + private static _instance: Scroller; + + public old: Point = new Point(); + public val: Point = new Point(); + public easeVal: Point = new Point(); + public rate: Point = new Point(); + public power: Point = new Point(); + public dist: Point = new Point(); + + private _updateHandler: any; + + public static get instance(): Scroller { + if (!this._instance) { + this._instance = new Scroller(); + } + return this._instance; + } + + constructor() { + this._updateHandler = this._update.bind(this); + Update.instance.add(this._updateHandler); + } + + public set(val: number): void { + window.scrollTo(0, val); + } + + private _update(): void { + this.old.copy(this.val); + this.val.y = Math.max(0, window.pageYOffset || document.documentElement.scrollTop); + this.easeVal.y += (this.val.y - this.easeVal.y) * 0.1 + + const ease = 0.1; + let powerTg = this.old.y - this.val.y; + this.power.y += (powerTg - this.power.y) * ease; + + this.dist.y += (this.old.y - this.val.y - this.dist.y) * ease; + } +} diff --git a/src/core/tween.ts b/src/core/tween.ts new file mode 100755 index 0000000..a4a7520 --- /dev/null +++ b/src/core/tween.ts @@ -0,0 +1,72 @@ +import { Power0, gsap } from 'gsap'; + +export class Tween { + private static _instance: Tween; + + constructor() {} + + public static get instance(): Tween { + if (!this._instance) { + this._instance = new Tween(); + } + return this._instance; + } + + a( + target: any, + param: any, + duration: number = 1, + delay: number = 0, + easing: any = undefined, + onStart: any = undefined, + onUpdate: any = undefined, + onComplete: any = undefined + ): void { + gsap.killTweensOf(target); + + let from:any = {}; + let to:any = {}; + + for (var key in param) { + const val = param[key]; + if (val[0] != undefined && val[0] != null) { + from[key] = val[0]; + to[key] = val[1]; + } else { + to[key] = val; + } + } + + gsap.set(target, from); + + if (easing == undefined) { + easing = Power0.easeNone; + } + to['ease'] = easing; + + to['duration'] = duration; + to['delay'] = delay; + + if (onStart != undefined) { + to['onStart'] = onStart; + } + + if (onUpdate != undefined) { + to['onUpdate'] = onUpdate; + } + + if (onComplete != undefined) { + to['onComplete'] = onComplete; + } + + gsap.to(target, to); + } + + set(target: any, to: any): void { + gsap.set(target, to); + } + + kill(target: any): void { + gsap.killTweensOf(target); + } +} diff --git a/src/libs/display.ts b/src/libs/display.ts new file mode 100755 index 0000000..85883a3 --- /dev/null +++ b/src/libs/display.ts @@ -0,0 +1,126 @@ +export class Display { + opt: any; + el: any; + constructor(opt: any = {}) { + this.opt = opt; + this.el = this.opt.el; + } + + init() {} + + // 破棄 + public dispose() { + this.opt = null; + this.el = null; + } + + public getEl(): HTMLElement { + return this.el as HTMLElement; + } + + public hasData(name: string): boolean { + const v = this.getEl().getAttribute(name); + if (v == undefined) { + return false; + } else { + return true; + } + } + + public getData(name: string, def: any): any { + const v = this.getEl().getAttribute(name); + if (v == undefined) { + return def; + } else { + return v; + } + } + + public qs(sel: string): HTMLElement { + return this.el.querySelector(sel); + } + + public qsAll(sel: string): Array { + return this.el.querySelectorAll(sel); + } + + public hasClass(c: string): boolean { + return (this.el as HTMLElement).classList.contains(c); + } + + public addClass(c: string): void { + (this.el as HTMLElement).classList.add(c); + } + + public attachClass(el:any, c: string): void { + if(el != undefined) el.classList.add(c); + } + + public detachClass(el:any, c: string): void { + if(el != undefined) el.classList.remove(c); + } + + public removeClass(c: string): void { + (this.el as HTMLElement).classList.remove(c); + } + + getWidth(el: Element): number { + let val = document.defaultView?.getComputedStyle(el, null).width; + return Number(val?.replace('px', '')); + } + + getHeight(el: Element | null): number { + if(el == null) { + return 0 + } else { + let val = document.defaultView?.getComputedStyle(el, null).height; + return Number(val?.replace('px', '')); + } + } + + getRect(el: Element): any { + const st = document.defaultView?.getComputedStyle(el, null); + if (st != undefined) { + return { + width: Number(st.width.replace('px', '')), + height: Number(st.height.replace('px', '')), + }; + } else { + return {}; + } + } + + public getDataNumber(name: string): number { + const d = this.getEl().getAttribute(name); + if (d == undefined) { + return 0; + } else { + return Number(d); + } + } + + public getOffsetTop(el: Element): number { + const rect = el.getBoundingClientRect(); + var scrollTop = window.pageYOffset || document.documentElement.scrollTop; + return rect.top + scrollTop; + } + + public getOffset(el: Element): any { + const rect = el.getBoundingClientRect(); + var scrollTop = window.pageYOffset || document.documentElement.scrollTop; + return { + y: rect.top + scrollTop, + x: rect.left, + }; + } + + protected _call(f:any, arg:any = null):void { + if(f != undefined) { + if(arg != null) { + f(arg) + } else { + f() + } + } + } +} diff --git a/src/libs/easing.ts b/src/libs/easing.ts new file mode 100755 index 0000000..e490c11 --- /dev/null +++ b/src/libs/easing.ts @@ -0,0 +1,69 @@ +export class Easing { + private static _instance: Easing; + + private constructor() {} + + public static get instance(): Easing { + if (!this._instance) { + this._instance = new Easing(); + } + return this._instance; + } + + inExpo(t: number): number { + if(t == 0) { + return 0; + } else { + return Math.pow(2, 10 * (t - 1)); + } + } + + + outExpo(t: number): number { + if(t == 1) { + return 1; + } else { + return -Math.pow(2, -10 * t) + 1; + } + } + + + outSine(t: number): number { + return Math.sin(t * (Math.PI / 2)); + } + + + outQuad(t: number): number { + return -t * (t - 2); + } + + + inOutQuart(t: number): number { + t *= 2; + if (t < 1) return 0.5 * t * t * t * t; + t -= 2; + return -0.5 * (t * t * t * t - 2); + } + + inOutCirc(t: number): number { + t *= 2; + + if (t < 1) return -0.5 * (Math.sqrt(1 - t * t) - 1); + + t -= 2; + return 0.5 * (Math.sqrt(1 - t * t) + 1); + } + + inOutCubic(t: number): number { + t *= 2; + + if (t < 1) return 0.5 * t * t * t; + + t -= 2; + return 0.5 * (t * t * t + 2); + } + + inOutSine(t: number): number { + return -0.5 * (Math.cos(Math.PI * t) - 1); + } +} diff --git a/src/libs/hsl.ts b/src/libs/hsl.ts new file mode 100755 index 0000000..8253a70 --- /dev/null +++ b/src/libs/hsl.ts @@ -0,0 +1,10 @@ + +export class HSL { + + h:number = 0 + s:number = 0 + l:number = 0 + + constructor() { + } +} \ No newline at end of file diff --git a/src/libs/point.ts b/src/libs/point.ts new file mode 100755 index 0000000..f6b5f1a --- /dev/null +++ b/src/libs/point.ts @@ -0,0 +1,19 @@ +export class Point { + x: number = 0; + y: number = 0; + + constructor(x: number = 0, y: number = 0) { + this.x = x; + this.y = y; + } + + public set(x: number = 0, y: number = 0) { + this.x = x; + this.y = y; + } + + public copy(p: Point) { + this.x = p.x; + this.y = p.y; + } +} diff --git a/src/libs/rect.ts b/src/libs/rect.ts new file mode 100755 index 0000000..bb2c397 --- /dev/null +++ b/src/libs/rect.ts @@ -0,0 +1,13 @@ +export class Rect { + x: number = 0; + y: number = 0; + width: number = 0; + height: number = 0; + + constructor(x: number = 0, y: number = 0, width: number = 0, height: number = 0) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } +} diff --git a/src/libs/resize.ts b/src/libs/resize.ts new file mode 100755 index 0000000..c468462 --- /dev/null +++ b/src/libs/resize.ts @@ -0,0 +1,70 @@ +import { Rect } from './rect'; + +export class Resize { + private static _instance: Resize; + + // レイアウト更新時に実行させる関数を保持 + private _list: Array = []; + + private _timer: any = null; + + public size: Rect = new Rect(); + public oldSize: Rect = new Rect(); + + constructor() { + window.addEventListener( + 'resize', + () => { + this._eResize(); + }, + false + ); + } + + public static get instance(): Resize { + if (!this._instance) { + this._instance = new Resize(); + } + return this._instance; + } + + private _eResize(): void { + this._setStageSize(); + + if (this._timer === null) { + clearInterval(this._timer); + this._timer = null; + } + + this._timer = setTimeout(() => { + this._call(); + this.oldSize.width = this.size.width; + this.oldSize.height = this.size.height; + }, 300); + } + + private _setStageSize(): void { + this.size.width = window.innerWidth; + this.size.height = window.innerHeight; + } + + public add(f: Function) { + this._list.push(f); + } + + public remove(f: Function) { + const arr: Array = []; + this._list.forEach((val) => { + if (val != f) { + arr.push(val); + } + }); + this._list = arr; + } + + private _call = () => { + for (var item of this._list) { + if (item != null) item(); + } + }; +} diff --git a/src/libs/update.ts b/src/libs/update.ts new file mode 100755 index 0000000..01b4a96 --- /dev/null +++ b/src/libs/update.ts @@ -0,0 +1,46 @@ +export class Update { + private static _instance: Update; + + // 更新回数 + public cnt: number = 0; + + // 毎フレーム実行させる関数を保持 + private _updateList: Array = []; + + public play: boolean = true; + + constructor() { + window.requestAnimationFrame(this._update); + } + + public static get instance(): Update { + if (!this._instance) { + this._instance = new Update(); + } + return this._instance; + } + + public add(f: Function) { + this._updateList.push(f); + } + + public remove(f: Function) { + const arr: Array = []; + this._updateList.forEach((val) => { + if (val != f) { + arr.push(val); + } + }); + this._updateList = arr; + } + + _update = () => { + if (this.play) { + this.cnt++; + for (var item of this._updateList) { + if (item != null) item(); + } + window.requestAnimationFrame(this._update); + } + }; +} diff --git a/src/libs/util.ts b/src/libs/util.ts new file mode 100755 index 0000000..3da72d8 --- /dev/null +++ b/src/libs/util.ts @@ -0,0 +1,286 @@ +import device from 'current-device'; + +export class Util { + private static _instance: Util; + + private constructor() {} + + public static get instance(): Util { + if (!this._instance) { + this._instance = new Util(); + } + + // 生成済みのインスタンスを返す + return this._instance; + } + + // ランダムな数(float) + // ----------------------------------- + // @min : 最小値(float) + // @max : 最大値(float) + // return : min(含む)からmax(含む)までのランダムな数(float) + // ----------------------------------- + random(min: number, max: number): number { + return Math.random() * (max - min) + min; + } + + random2(min: number, max: number): number { + let r: number = Math.random() * (max - min) + min; + if (this.hit(2)) { + r *= -1; + } + return r; + } + + // ランダムな数(int) + // ----------------------------------- + // @min : 最小値(int) + // @max : 最大値(int) + // return : min(含む)からmax(含む)までのランダムな数(int) + // ----------------------------------- + randomInt(min: number, max: number): number { + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + // 1/@rangeの確率でtrueを取得 + // ----------------------------------- + // @range : 2以上の分母(int) + // return : true or false(boolean) + // ----------------------------------- + hit(range: number = 0): boolean { + if (range < 2) range = 2; + return this.randomInt(0, range - 1) == 0; + } + + // 配列内の値をランダムに取得 + // ----------------------------------- + randomArr(arr: Array): any { + return arr[this.randomInt(0, arr.length - 1)]; + } + + // -指定値から指定値までのランダムな数(float) + // ----------------------------------- + // @val : 指定値(float) + // return : -@valから@valまでのランダムな数(float) + // ----------------------------------- + range(val: number): number { + return this.random(-val, val); + } + + // 値を範囲内におさめる + // ----------------------------------- + // @val : 値 + // @min : 最小値 + // @max : 最大値 + // ----------------------------------- + clamp(val: number, min: number, max: number): number { + return Math.min(max, Math.max(val, min)); + } + + // 値のマッピング + // ----------------------------------- + // @num : マッピングする値 + // @toMin : 変換後の最小値 + // @toMax : 変換後の最大値 + // @fromMin : 変換前の最小値 + // @fromMax : 変換前の最大値 + // ----------------------------------- + map(num: number, toMin: number, toMax: number, fromMin: number, fromMax: number): number { + if (num <= fromMin) return toMin; + if (num >= fromMax) return toMax; + + const p = (toMax - toMin) / (fromMax - fromMin); + return (num - fromMin) * p + toMin; + } + + // 線形補完 + // ----------------------------------- + mix(x: number, y: number, a: number): number { + return x * (1 - a) + y * a; + } + + // ラジアンに変換 + // ----------------------------------- + radian(degree: number): number { + return (degree * Math.PI) / 180; + } + + // 角度に変換 + // ----------------------------------- + degree(radian: number): number { + return (radian * 180) / Math.PI; + } + + // 配列をランダムに並べ替え + // ----------------------------------- + shuffle(arr: Array): void { + let i = arr.length; + while (--i) { + let j = Math.floor(Math.random() * (i + 1)); + if (i == j) continue; + let k = arr[i]; + arr[i] = arr[j]; + arr[j] = k; + } + } + + // 文字列の全置換 + // ----------------------------------- + replaceAll(val: string, org: string, dest: string): string { + return val.split(org).join(dest); + } + + // 配列内のパラメータを比較してソート + // ----------------------------------- + // @arr : 配列 + // @para : パラメーター名 + // @desc : 降順かどうか(boolean) デフォルトは昇順 + // ----------------------------------- + sort(arr: Array, para: string, desc: boolean = true): void { + if (desc) { + arr.sort((a: any, b: any) => { + return b[para] - a[para]; + }); + } else { + arr.sort((a: any, b: any) => { + return a[para] - b[para]; + }); + } + } + + // 2点間の距離 + // ----------------------------------- + distance(x1: number, y1: number, x2: number, y2: number): number { + const dx = x1 - x2; + const dy = y1 - y2; + return Math.sqrt(dx * dx + dy * dy); + } + + // 数値を文字列に変換 + // ----------------------------------- + // @num : 数値 + // @keta : 桁数 + // ----------------------------------- + numStr(num: number, keta: number): string { + let str = String(num); + if (str.length >= keta) return str; + + const len = keta - str.length; + let i = 0; + while (i < len) { + str = '0' + str; + i++; + } + + return str; + } + + // IEかどうか Edge含む + // ----------------------------------- + isIE(): boolean { + const ua = window.navigator.userAgent.toLowerCase(); + return ua.indexOf('msie') != -1 || ua.indexOf('trident/7') != -1 || ua.indexOf('edge') != -1; + } + + // IEかどうか Edge含まない + // ----------------------------------- + isIE2(): boolean { + const ua = window.navigator.userAgent.toLowerCase(); + return ua.indexOf('msie') != -1 || ua.indexOf('trident/7') != -1; + } + + // WINかどうか + // ----------------------------------- + isWin(): boolean { + return window.navigator.platform.indexOf('Win') != -1; + } + + // googleChromeかどうか + // ----------------------------------- + isChrome(): boolean { + return window.navigator.userAgent.toLowerCase().indexOf('chrome') != -1; + } + + // FireFoxかどうか + // ----------------------------------- + isFF(): boolean { + return window.navigator.userAgent.toLowerCase().indexOf('firefox') != -1; + } + + // Safariかどうか + // ----------------------------------- + isSafari(): boolean { + return window.navigator.userAgent.toLowerCase().indexOf('safari') != -1 && !this.isChrome(); + } + + // ----------------------------------- + // webGL使えるか + // ----------------------------------- + useWebGL(): boolean { + try { + const c = document.createElement('canvas'); + const w: any = c.getContext('webgl') || c.getContext('experimental-webgl'); + return !!(window.WebGLRenderingContext && w && w.getShaderPrecisionFormat); + } catch (e) { + return false; + } + } + + // クエリ抜き出し + // ----------------------------------- + // @key : 抜き出すパラメータ名(String) + // ----------------------------------- + getQuery(key: string): string { + key = key.replace(/[€[]/, '€€€[').replace(/[€]]/, '€€€]'); + const regex = new RegExp('[€€?&]' + key + '=([^&//]*)'); + const qs = regex.exec(window.location.href); + if (qs == null) { + return ''; + } else { + return qs[1]; + } + } + + // ----------------------------------- + // タッチデバイスかどうか + // ----------------------------------- + isTouchDevice(): boolean { + const isTouch = !!('ontouchstart' in window || (navigator != undefined && navigator.maxTouchPoints > 0)); + return isTouch; + } + + // ----------------------------------- + // PCかどうか + // ----------------------------------- + isPc(): boolean { + return (device.mobile() == false) + } + + // ----------------------------------- + // スマホかどうか + // ----------------------------------- + isSp(): boolean { + return device.mobile() + } + + // ----------------------------------- + // Androidかどうか + // ----------------------------------- + isAod(): boolean { + return device.android(); + } + + // ----------------------------------- + // iPhoneかどうか + // ----------------------------------- + isIPhone(): boolean { + return device.iphone(); + } + + // ----------------------------------- + // iPadかどうか + // ----------------------------------- + isIPad(): boolean { + return device.tablet(); + } +} diff --git a/src/libs/val.ts b/src/libs/val.ts new file mode 100755 index 0000000..f9aa977 --- /dev/null +++ b/src/libs/val.ts @@ -0,0 +1,7 @@ +export class Val { + val: number = 0; + + constructor(val: number = 0) { + this.val = val; + } +} diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..3eacffb --- /dev/null +++ b/src/main.ts @@ -0,0 +1,8 @@ +import './style.css' +import { Contents } from './parts/contents'; + +new Contents({ + el:document.querySelector('.l-main'), +}) + + diff --git a/src/parts/contents.ts b/src/parts/contents.ts new file mode 100755 index 0000000..2dbbd6e --- /dev/null +++ b/src/parts/contents.ts @@ -0,0 +1,72 @@ + +import { Func } from "../core/func"; +import { MyDisplay } from "../core/myDisplay"; +import { Point } from "../libs/point"; +import { Util } from "../libs/util"; +import { Text } from "./text"; +import { Visual } from "./visual"; + +// ----------------------------------------- +// +// ----------------------------------------- +export class Contents extends MyDisplay { + + private _pos:Point = new Point(); + private _text:Array = []; + + private _v:Visual; + + constructor(opt:any) { + super(opt) + + this._v = new Visual({ + el:this.getEl() + }) + + const text = '水の中で見えるテキスト'; + + let txt = '

'; + let arr = Array.from(text); + for(let i = 0; i < arr.length; i++) { + txt += '' + arr[i % arr.length] + ''; + } + txt += '

'; + (document.querySelector('.l-text') as HTMLElement).innerHTML = txt; + document.querySelectorAll('.l-text span').forEach((val) => { + const t = new Text({ + el:val + }); + this._text.push(t); + }) + + this._resize(); + } + + + protected _update(): void { + super._update(); + + // モニターサイズと位置 + const displayInfo: {x:number, y:number, width:number, height:number} = { + width:window.screen.width, + height:window.screen.height, + x:window.screenX, + y:window.screenY, + } + + this._pos.y += (displayInfo.y - this._pos.y) * 0.1 + + // const sw = Func.instance.sw(); + const sh = Func.instance.sh(); + + // 波の位置 + const waveY = Util.instance.map(this._pos.y, -sh * 0.5, sh * 1, 0, displayInfo.height - sh); + this._v.baseY = waveY; + + } + + + protected _resize(): void { + super._resize(); + } +} \ No newline at end of file diff --git a/src/parts/text.ts b/src/parts/text.ts new file mode 100755 index 0000000..9b45c41 --- /dev/null +++ b/src/parts/text.ts @@ -0,0 +1,36 @@ +import { MyDisplay } from "../core/myDisplay"; +import { Tween } from "../core/tween"; +import { Util } from "../libs/util"; + +// ----------------------------------------- +// +// ----------------------------------------- +export class Text extends MyDisplay { + + // private _noise:number = Util.instance.random(0, 1) + + constructor(opt:any) { + super(opt) + + this._c = Util.instance.random(0, 10000) + + this._resize(); + } + + + protected _update(): void { + super._update(); + + const radian = Util.instance.radian(this._c * 1); + Tween.instance.set(this.getEl(), { + rotationZ:Math.sin(radian) * 10, + y:Math.cos(radian * 1.2) * 10, + x:Math.sin(radian * -0.95) * 2, + }) + } + + + protected _resize(): void { + super._resize(); + } +} \ No newline at end of file diff --git a/src/parts/visual.ts b/src/parts/visual.ts new file mode 100755 index 0000000..5291103 --- /dev/null +++ b/src/parts/visual.ts @@ -0,0 +1,126 @@ +import { Func } from '../core/func'; +import { Canvas } from '../webgl/canvas'; +import { Object3D } from 'three/src/core/Object3D'; +import { MeshBasicMaterial } from "three/src/materials/MeshBasicMaterial"; +import { Mesh } from 'three/src/objects/Mesh'; +import { Color } from 'three/src/math/Color'; +import { Vector3 } from 'three/src/math/Vector3'; +import { CatmullRomCurve3 } from 'three/src/extras/curves/CatmullRomCurve3'; +import { Util } from "../libs/util"; +import { ShapeGeometry } from 'three/src/geometries/ShapeGeometry'; +import { Shape } from 'three/src/extras/core/Shape'; + +export class Visual extends Canvas { + + private _con:Object3D; + private _mesh:Mesh; + + public baseY:number = 0; + + constructor(opt: any) { + super(opt); + + this._con = new Object3D(); + this.mainScene.add(this._con); + + this._mesh = new Mesh( + this._makeGeo(), + new MeshBasicMaterial({ + color:0x0000ff, + }), + ); + this._con.add(this._mesh); + + this._resize(); + } + + + protected _update(): void { + super._update(); + + this._mesh.geometry.dispose(); + this._mesh.geometry = this._makeGeo(); + + if (this.isNowRenderFrame()) { + this._render() + } + } + + + private _render(): void { + const bgColor = new Color(0xffffff) + this.renderer.setClearColor(bgColor, 1) + this.renderer.render(this.mainScene, this.camera) + } + + + public isNowRenderFrame(): boolean { + return this.isRender + } + + + _resize(isRender: boolean = true): void { + super._resize(); + + const w = Func.instance.sw(); + const h = Func.instance.sh(); + + this.renderSize.width = w; + this.renderSize.height = h; + + this.updateCamera(this.camera, w, h); + + let pixelRatio: number = window.devicePixelRatio || 1; + + this.renderer.setPixelRatio(pixelRatio); + this.renderer.setSize(w, h); + this.renderer.clear(); + + if (isRender) { + this._render(); + } + } + + + // --------------------------------- + // + // --------------------------------- + private _makeGeo():ShapeGeometry { + const arr:Array = [] + + const sw = Func.instance.sw(); + const sh = Func.instance.sh(); + const radius = sh * 0.1; + + let startX = sw * -0.6; + let endX = sw * 0.6; + let startY = this.baseY; + + let ang = 0; + let i = startX; + const interval = sw * 0.05; + while(i < endX) { + const radian = Util.instance.radian(this._c + ang); + arr.push(new Vector3(i, startY + Math.sin(radian) * radius, 0)); + i += interval; + ang += 10; + } + + arr.push(new Vector3(endX, -sh, 0)); + arr.push(new Vector3(startX, -sh, 0)); + + const curve = new CatmullRomCurve3(arr, true); + const points = curve.getPoints(50); + + const shape = new Shape() + points.forEach((val,i) => { + if(i == 0) { + shape.moveTo(val.x, val.y); + } else { + shape.lineTo(val.x, val.y) + } + }); + + return new ShapeGeometry(shape); + } +} diff --git a/src/style.css b/src/style.css new file mode 100644 index 0000000..df27f29 --- /dev/null +++ b/src/style.css @@ -0,0 +1,50 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + background-color: #000; + font-family: 'Noto Serif JP', serif; +} + +.l-main { + position: absolute; + top: 0; + left: 0; +} + +.l-text { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: 48px; + color: #FFF; + letter-spacing: 0.5em; +} + +.l-text span { + display: inline-block; +} + + + +.link { + position: fixed; + right: 0; + bottom: 0; + padding: 10px; + font-size: 18px; + color: inherit; + text-decoration: none; + color: #FFF; + background-color: #000; + z-index: 9999; +} \ No newline at end of file diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/src/webgl/canvas.ts b/src/webgl/canvas.ts new file mode 100755 index 0000000..afbba38 --- /dev/null +++ b/src/webgl/canvas.ts @@ -0,0 +1,83 @@ +import { MyDisplay } from "../core/myDisplay"; +import { WebGLRenderer } from 'three/src/renderers/WebGLRenderer'; +import { Scene } from 'three/src/scenes/Scene'; +import { Rect } from "../libs/rect"; +import { OrthographicCamera } from 'three/src/cameras/OrthographicCamera'; +// import { PerspectiveCamera } from 'three/src/cameras/PerspectiveCamera'; +import { Camera } from 'three/src/cameras/Camera'; +import { Mesh } from 'three/src/objects/Mesh'; +import { Points } from 'three/src/objects/Points'; +import { Vector3 } from 'three/src/math/Vector3'; + +export class Canvas extends MyDisplay { + + public camera:Camera + public renderer:WebGLRenderer + public mainScene:Scene + + public isRender:boolean = true + public renderSize:Rect = new Rect() + + constructor(opt:any = {}) { + super(opt) + + let renderParam:any = { + canvas : this.el, + antialias: false, + preserveDrawingBuffer : true, + powerPreference : 'low-power', + } + this.renderer = new WebGLRenderer(renderParam) + this.renderer.autoClear = true + this.renderer.setClearColor(0xffffff, 1) + + this.mainScene = new Scene() + + this.camera = this._makeCamera() + this.updateCamera(this.camera, 10, 10) + } + + init() { + super.init() + } + + protected _makeCamera():Camera { + return new OrthographicCamera(1, 1, 1, 1) + // return new PerspectiveCamera(50, 1, 0.0000001, 50000) + } + + public updateCamera(camera:Camera, w:number = 10, h:number = 10) { + this._updateOrthCamera(camera as OrthographicCamera, w, h) + // this._updateOrthCamera(camera as PerspectiveCamera, w, h) + } + + protected _updateOrthCamera(camera:OrthographicCamera, w:number = 10, h:number = 10) { + // protected _updateOrthCamera(camera:PerspectiveCamera, w:number = 10, h:number = 10) { + camera.left = -w * 0.5 + camera.right = w * 0.5 + camera.top = h * 0.5 + camera.bottom = -h * 0.5 + camera.near = -10000 + camera.far = 100000 + camera.updateProjectionMatrix() + camera.position.set(0, 0, 0) + camera.lookAt(new Vector3(0, 0, 0)) + + // camera.aspect = w / h + // camera.updateProjectionMatrix() + // camera.position.z = h / Math.tan(camera.fov * Math.PI / 360) / 2 + } + + protected _update():void { + super._update() + } + + protected _setUni(m:Mesh | Points, name:string, val:any):void { + const uni = this._getUni(m) + uni[name].value = val + } + + protected _getUni(mesh:any):any { + return mesh.material.uniforms + } +} \ No newline at end of file diff --git a/src/webgl/ieTexture.ts b/src/webgl/ieTexture.ts new file mode 100755 index 0000000..7f1b72a --- /dev/null +++ b/src/webgl/ieTexture.ts @@ -0,0 +1,25 @@ +import { Texture } from 'three/src/textures/Texture'; +// import { RGBAFormat,RGBAFOr } from 'three/src/constants'; + +export class IETexture { + + constructor() { + } + + // ----------------------------------- + // + // ----------------------------------- + public load(src:string, onLoaded:any):Texture { + const t = new Texture() + const img = new Image() + img.onload = () => { + t.image = img + // const isJPEG = (src.indexOf('.jpg') > 0) + // t.format = isJPEG ? RGBFormat : RGBAFormat + t.needsUpdate = true + if(onLoaded != undefined) onLoaded() + } + img.src = src + return t + } +} diff --git a/src/webgl/myObject3D.ts b/src/webgl/myObject3D.ts new file mode 100755 index 0000000..2507d36 --- /dev/null +++ b/src/webgl/myObject3D.ts @@ -0,0 +1,59 @@ +import { Update } from "../libs/update"; +import { Resize } from "../libs/resize"; +import { Object3D } from 'three/src/core/Object3D'; +import { Mesh } from 'three/src/objects/Mesh'; + +export class MyObject3D extends Object3D { + + private _updateHandler:any + private _layoutHandler:any + + protected _c:number = 0 + + constructor() { + super() + + this._updateHandler = this._update.bind(this) + Update.instance.add(this._updateHandler) + + this._layoutHandler = this._resize.bind(this) + Resize.instance.add(this._layoutHandler) + } + + init() { + } + + // 破棄 + public dispose() { + Update.instance.remove(this._updateHandler) + this._updateHandler = null + + Resize.instance.remove(this._layoutHandler) + this._layoutHandler = null + } + + + protected _update():void { + this._c++ + } + + + protected _resize():void { + } + + + protected _getUni(mesh:any):any { + return mesh.material.uniforms + } + + + protected _setUni(m:Mesh, name:string, val:any):void { + const uni = this._getUni(m) + uni[name].value = val + } + + + protected _call(f:any):void { + if(f != undefined) f() + } +} \ No newline at end of file diff --git a/src/webgl/texLoader.ts b/src/webgl/texLoader.ts new file mode 100755 index 0000000..de7c103 --- /dev/null +++ b/src/webgl/texLoader.ts @@ -0,0 +1,151 @@ +import { TextureLoader } from 'three/src/loaders/TextureLoader'; +import { Texture } from 'three/src/textures/Texture'; +import { Util } from '../libs/util'; +import { IETexture } from './ieTexture'; + +export class TexLoader { + + private static _instance:TexLoader; + + private _list:Array = [] + private _tex:Array = [] + // private _num:number = 0 + private _loadedNum:number = 0 + private _isIE:boolean = Util.instance.isIE() + + public onComplete?:Function + public onProgress?:Function + + constructor() { + } + + public static get instance():TexLoader { + if (!this._instance) { + this._instance = new TexLoader(); + } + return this._instance; + } + + + // ----------------------------------- + // + // ----------------------------------- + public load(opt:any):void { + this.onComplete = opt.onComplete + this.onProgress = opt.onProgress + + if(opt.list.length == 0) { + if(this.onComplete != undefined) { + this.onComplete() + } + return + } + + this._list = opt.list + this._loadedNum = 0 + + this._load() + } + + + // ----------------------------------- + // + // ----------------------------------- + private _load():void { + const data = this._list[this._loadedNum] + + if(this.check(data.src)) { + this._loadedImg() + return + } + + let texloader,tex + if(this._isIE) { + texloader = new IETexture() + tex = texloader.load(data.src, () => { + this._loadedImg() + }) + } else { + texloader = new TextureLoader() + texloader.crossOrigin = '*' + tex = texloader.load(data.src, () => { + this._loadedImg() + }) + } + + this._tex.push({ + tex:tex, + src:data.src + }) + } + + + // ----------------------------------- + // + // ----------------------------------- + private _loadedImg():void { + this._loadedNum++ + + if(this.onProgress != undefined) { + this.onProgress(this._loadedNum / this._list.length) + } + + if(this._loadedNum >= this._list.length) { + if(this.onComplete != undefined) { + this.onComplete() + } + return + } + + this._load() + } + + + // ----------------------------------- + // + // ----------------------------------- + public get(src:string):Texture { + + let preTex:any = null; + this._tex.forEach((item) => { + if(item.src == src) { + preTex = item.tex + } + }) + if(preTex != null) { + return preTex + } + + let t:any + if(!this._isIE) { + t = new TextureLoader() + t.crossOrigin = 'anonymous' + } else { + t = new IETexture() + } + + const tex = t.load(src) + + this._tex.push({ + tex:tex, + src:src + }) + + return tex + } + + + // ----------------------------------- + // + // ----------------------------------- + public check(src:string):boolean { + let flg = false + this._tex.forEach((item) => { + if(item.src == src) { + flg = true + } + }) + return flg + } + +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..1885c8f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ESNext", "DOM"], + "moduleResolution": "Node", + "strict": true, + "sourceMap": true, + "resolveJsonModule": true, + "esModuleInterop": true, + "noEmit": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true + }, + "include": ["src"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..ff36c62 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,11 @@ +import glsl from 'vite-plugin-glsl' +import { defineConfig } from 'vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [glsl()], + base: './', + server: { + host: true + } +}) \ No newline at end of file