diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 8ef7ca6..e19771f 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,12 +1,11 @@ /* eslint-env node */ -module.exports = -{ +module.exports = { root: true, env: { browser: true, es2020: true }, extends: [ 'eslint:recommended', + 'standard-with-typescript', 'plugin:@typescript-eslint/recommended', - 'plugin:@typescript-eslint/recommended-requiring-type-checking', 'plugin:react-hooks/recommended', 'plugin:react/recommended', 'prettier', @@ -48,5 +47,5 @@ module.exports = }, ], }, -} +}; diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml new file mode 100644 index 0000000..0a47103 --- /dev/null +++ b/.github/workflows/eslint.yml @@ -0,0 +1,60 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. +# ESLint is a tool for identifying and reporting on patterns +# found in ECMAScript/JavaScript code. +# More details at https://github.com/eslint/eslint +# and https://eslint.org + +name: ESLint + +on: + push: + branches: ['main'] + pull_request: + # The branches below must be a subset of the branches above + branches: ['main'] + schedule: + - cron: '16 20 * * 0' + +jobs: + eslint: + name: Run eslint scanning + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: setup Node.js + uses: actions/setup-node@v3 + with: + node-version: 18 + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Install ESLint formatter + run: | + npm install @microsoft/eslint-formatter-sarif@2.1.7 + + - name: Run ESLint + run: npx eslint src + --report-unused-disable-directives + --max-warnings 0 + --config .eslintrc.cjs + --ext .js,.jsx,.ts,.tsx + --format @microsoft/eslint-formatter-sarif + --output-file eslint-results.sarif + continue-on-error: true + + - name: Upload analysis results to GitHub + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: eslint-results.sarif + wait-for-processing: true diff --git a/modelverify.html b/modelverify.html deleted file mode 100644 index 12566e7..0000000 --- a/modelverify.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - CFlowSim: Physics in the Browser for the People - - - - - -
- - - diff --git a/src/App.tsx b/src/App.tsx index aa38b74..a1a55a8 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,3 +1,4 @@ +import type React from 'react'; import { useEffect, useState } from 'react'; import NavBar from './components/NavBar'; import styled, { ThemeProvider } from 'styled-components'; @@ -6,7 +7,7 @@ import './App.css'; import Home from './pages'; import AboutPage from './pages/about'; import { SimulationParams } from './components/Simulation'; -import { IncomingMessage } from './workers/modelWorkerMessage'; +import { type IncomingMessage } from './workers/modelWorkerMessage'; const Main = styled.main` position: absolute; @@ -14,7 +15,7 @@ const Main = styled.main` top: 0; width: 100vw; height: 100vh; - background: ${(props) => (props.theme.light ? '#ffffff' : '#707070')}; + background: ${(props) => ((props.theme.light as boolean) ? '#ffffff' : '#707070')}; z-index: 0; `; @@ -25,7 +26,7 @@ const NavBarContainer = styled.div` font-family: 'Titillium Web', sans-serif; `; -function App() { +function App(): React.ReactElement { // save the current page in state // 0 = home(index,simulation) 1 = about const [page, setPage] = useState(0); @@ -35,7 +36,6 @@ function App() { const [lightTheme, setlightTheme] = useState(false); // TODO: implement auto theme ui switch - // eslint-disable-next-line @typescript-eslint/no-unused-vars const [curThemeMode, setCurThemeMode] = useState('auto'); // 'dark' or 'light' or 'auto' useEffect(() => { @@ -62,9 +62,10 @@ function App() { }, ); setSimWorker(worker); - worker.postMessage({ + const message: IncomingMessage = { func: 'init', - } as IncomingMessage); + }; + worker.postMessage(message); }, []); let mainPageComponent; diff --git a/src/components/NavBar.tsx b/src/components/NavBar.tsx index e109e6b..0c7ec85 100644 --- a/src/components/NavBar.tsx +++ b/src/components/NavBar.tsx @@ -13,8 +13,8 @@ const Header = styled.header` display: flex; align-items: center; height: 5rem; - background-color: ${(props) => (props.theme.light ? '#004b87' : '#142c3f')}; - color: ${(props) => (props.theme.light ? '#f5f5f5' : '#9faee5')}; + background-color: ${(props) => (props.theme.light as boolean ? '#004b87' : '#142c3f')}; + color: ${(props) => (props.theme.light as boolean ? '#f5f5f5' : '#9faee5')}; `; const LogoAnchor = styled.a` @@ -132,10 +132,10 @@ export default function NavBar(props: NavBarProps): React.ReactElement { - setPage(0)}> + { setPage(0); }}> Simulations - setPage(1)}> + { setPage(1); }}> About {isShowExtend ? ( - setPage(0)}> + { setPage(0); }}> Simulations - setPage(1)}> + { setPage(1); }}> About { - void (() => { + (() => { worker.onmessage = (e) => { const data = e.data as OutgoingMessage; @@ -141,7 +141,6 @@ function DiffusionPlane( })(); // SUBSCRIPTIONS - // update the density uniforms every time // output is received function output(data: Float32Array): void { diff --git a/src/pages/about.tsx b/src/pages/about.tsx index c3fbbca..cf1daa7 100644 --- a/src/pages/about.tsx +++ b/src/pages/about.tsx @@ -8,7 +8,7 @@ const Content = styled.div` margin-top: 4%; margin-bottom: 8%; font-family: 'Roboto', sans-serif; - color: ${(props) => (props.theme.light ? '#333333' : '#c9c9c9' )}; + color: ${(props) => (props.theme.light as boolean ? '#333333' : '#c9c9c9' )}; a:link { text-decoration: none; } diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 6426f2a..2a1ef39 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,6 +1,6 @@ import ParBar from '../components/ParametersBar'; import ControlBar from '../components/ControlBar'; -import { DiffusionPlane, SimulationParams } from '../components/Simulation'; +import { DiffusionPlane, type SimulationParams } from '../components/Simulation'; import { Canvas } from '@react-three/fiber'; import styled from 'styled-components'; diff --git a/src/pages/modelverify.tsx b/src/pages/modelverify.tsx deleted file mode 100644 index ad75b64..0000000 --- a/src/pages/modelverify.tsx +++ /dev/null @@ -1,88 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -/* eslint-disable @typescript-eslint/no-unsafe-call */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -import { useEffect, useState } from 'react'; - -export default function Home(): React.ReactElement { - const [paused, setPaused] = useState(true); - const [worker, setWorker] = useState(null); - useEffect(() => { - void (() => { - const worker = new Worker( - new URL('../workers/modelWorker', import.meta.url), - { - type: 'module', - }, - ); - console.log('worker created', worker); - worker.postMessage({ func: 'init' }); - worker.onmessage = (e: MessageEvent) => { - if (e.data.type === 'output') { - const density = e.data.density; - // log the array 64x64 - // chunk the array into 64x64 - const chunked = []; - for (let i = 0; i < density.length; i += 64) { - chunked.push(density.slice(i, i + 64)); - } - console.log(chunked); - // log some values - console.log( - 'average density', - density.reduce((a: any, b: any) => a + b) / density.length, - ); - console.log('max density', Math.max(...density)); - console.log('min density', Math.min(...density)); - console.log( - 'density std dev', - Math.sqrt( - density.reduce((a: any, b: any) => a + b * b) / density.length - - Math.pow( - density.reduce((a: any, b: any) => a + b) / density.length, - 2, - ), - ), - ); - } else console.log(e.data); - }; - worker.onerror = (e) => { - console.log(e); - }; - setWorker(worker); - console.log('worker created'); - })(); - }, []); - - return ( - // write a simple article to guide user to console - <> - - Model Verification - - - - -
-

Model Verification

-

This page is used to verify the model. See console for output.

- -
- - ); -} diff --git a/src/pages/wip-simDraft b/src/pages/wip-simDraft deleted file mode 100644 index f59c6f8..0000000 --- a/src/pages/wip-simDraft +++ /dev/null @@ -1,51 +0,0 @@ -import css from '../styles/Home.module.css'; -import { Canvas } from '@react-three/fiber'; -import { MapControls, Stats } from '@react-three/drei'; -import { DiffusionPlane, SimulationParams } from '../components/Simulation'; -import { Color } from 'three'; -import { useEffect, useState } from 'react'; - -export default function Home(): React.ReactElement { - const [enableMapControls, setEnableMapControls] = useState(false); - useEffect(() => { - (window as any).testMapControlsToggle = setEnableMapControls; - }, []); - - const params: SimulationParams = new SimulationParams(); - params.densityLowColour = new Color('green'); - - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const [worker, setWorker] = useState(null!); - - useEffect(() => { - const worker = new Worker( - new URL('../workers/modelWorker', import.meta.url), - { - type: 'module', - }, - ); - setWorker(worker); - }, []); - - return ( -
- - - - - - -
- ); -} diff --git a/src/services/model/ONNXService.ts b/src/services/model/ONNXService.ts index d5c26a3..e70744b 100644 --- a/src/services/model/ONNXService.ts +++ b/src/services/model/ONNXService.ts @@ -375,6 +375,7 @@ export default class ONNXService implements ModelService { private roundFloat(value: number, decimal = 4): number { return Math.round(value * 10 ** decimal) / 10 ** decimal; } + getInputTensor(): Float32Array { return this.matrixArray; } diff --git a/src/services/model/TfjsService.ts b/src/services/model/TfjsService.ts index 12bbb0d..cb5c333 100644 --- a/src/services/model/TfjsService.ts +++ b/src/services/model/TfjsService.ts @@ -136,12 +136,14 @@ export class TfjsService implements ModelService { } }, 1000); } + getInput(): tf.Tensor { const pressure = this.pressure.toTensor(); const input = tf.concat([this.density, this.velocity, pressure], 3); pressure.dispose(); return input; } + private iterate(): void { if (this.isPaused) { return; @@ -204,12 +206,14 @@ export class TfjsService implements ModelService { 4, ); } + getInputTensor(): Float32Array { const input = this.getInput(); const data = input.dataSync(); input.dispose(); return data as Float32Array; } + dispose(): void { this.density.dispose(); this.velocity.dispose(); diff --git a/src/services/model/modelService.ts b/src/services/model/modelService.ts index 8da185a..35e75e6 100644 --- a/src/services/model/modelService.ts +++ b/src/services/model/modelService.ts @@ -25,7 +25,7 @@ export async function createModelService( const modelType = modelPath.split('.').pop(); switch (modelType) { case 'json': - return TfjsService.createService( + return await TfjsService.createService( modelPath, gridSize, batchSize, @@ -34,7 +34,7 @@ export async function createModelService( fpsLimit, ); case 'onnx': - return ONNXService.createService( + return await ONNXService.createService( modelPath, gridSize, batchSize, diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index 11f02fe..e578524 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -1 +1,2 @@ +// eslint-disable-next-line @typescript-eslint/triple-slash-reference /// diff --git a/src/workers/modelWorker.ts b/src/workers/modelWorker.ts index 9daf10c..d75e437 100644 --- a/src/workers/modelWorker.ts +++ b/src/workers/modelWorker.ts @@ -1,11 +1,11 @@ // a worker that can control the modelService via messages -import { Vector2 } from 'three'; +import { type Vector2 } from 'three'; import { - ModelService, + type ModelService, createModelService, } from '../services/model/modelService'; -import { IncomingMessage } from './modelWorkerMessage'; +import { type IncomingMessage } from './modelWorkerMessage'; let modelService: ModelService | null = null; @@ -67,7 +67,7 @@ export function onmessage( throw new Error(`unknown func ${data.func}`); } } -function updateForce(args: UpdateForceArgs) { +function updateForce(args: UpdateForceArgs): void { if (modelService == null) { throw new Error('modelService is null'); } @@ -94,8 +94,8 @@ async function initModelService( const modelService = await createModelService(modelPath, [64, 64], 1); modelService.bindOutput(outputCallback); // fetch the data - const data = (await fetch(dataPath).then((res) => - res.json(), + const data = (await fetch(dataPath).then(async (res) => + await res.json(), )) as number[][][][]; modelService.loadDataArray(data); return modelService;