Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: CI

on:
push:
branches: [main]
pull_request:

jobs:
all:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- run: bun install --frozen-lockfile
- run: bun run all
13 changes: 13 additions & 0 deletions .oxfmtrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"$schema": "./node_modules/oxfmt/configuration_schema.json",
"printWidth": 120,
"tabWidth": 2,
"useTabs": false,
"semi": false,
"singleQuote": true,
"trailingComma": "all",
"arrowParens": "avoid",
"bracketSpacing": true,
"sortTailwindcss": true,
"ignorePatterns": ["node_modules", "dist", "out", ".next"]
}
33 changes: 33 additions & 0 deletions .oxlintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["typescript", "unicorn", "import"],
"categories": {
"correctness": "error",
"suspicious": "warn",
"pedantic": "off",
"style": "off",
"restriction": "off",
"nursery": "off"
},
"rules": {
"no-unused-vars": [
"error",
{
"ignoreRestSiblings": true,
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_"
}
],
"no-unused-expressions": [
"error",
{
"allowShortCircuit": true,
"allowTernary": true
}
],
"typescript/no-non-null-assertion": "warn",
"unicorn/no-useless-spread": "warn",
"unicorn/consistent-function-scoping": "warn"
},
"ignorePatterns": ["node_modules", "dist", "out", ".next"]
}
997 changes: 99 additions & 898 deletions bun.lock

Large diffs are not rendered by default.

21 changes: 0 additions & 21 deletions eslint.config.mjs

This file was deleted.

4 changes: 2 additions & 2 deletions next.config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
/* config options here */
reactStrictMode: true,
reactCompiler: true,
output: 'export',
webpack: (config) => {
webpack: config => {
config.module.rules.push({ test: /\.(glb)$/, type: 'asset/resource' })
return config
},
Expand Down
68 changes: 37 additions & 31 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,69 +2,75 @@
"name": "tslfx",
"version": "0.6.0",
"license": "MIT",
"files": [
"dist"
],
"type": "module",
"scripts": {
"dev": "next dev --webpack",
"build": "next build --webpack",
"start": "serve out",
"lint": "eslint .",
"tsup": "tsup --tsconfig tsup.tsconfig.json",
"pub": "bun run tsup && npm publish",
"format": "prettier --write .",
"prepare": "husky"
},
"tsup": {
"entry": [
"src/shaders/index.ts"
],
"clean": true,
"format": [
"cjs",
"esm"
],
"dts": true
},
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"require": "./dist/index.cjs"
}
},
"files": [
"dist"
],
"peerDependencies": {
"three": ">=0.182.0"
"scripts": {
"dev": "portless tslfx next dev --webpack",
"build": "next build --webpack",
"start": "serve out",
"format": "oxfmt .",
"format:check": "oxfmt --check .",
"lint": "oxlint .",
"lint:fix": "oxlint --fix .",
"typecheck": "tsc --noEmit",
"warden": "warden",
"all": "bun run format:check && bun run lint && bun run typecheck && bun run warden",
"tsup": "tsup --tsconfig tsup.tsconfig.json",
"pub": "bun run tsup && npm publish",
"prepare": "husky"
},
"devDependencies": {
"@eslint/eslintrc": "3.3.3",
"@react-three/drei": "10.7.7",
"@react-three/fiber": "9.4.2",
"@types/node": "25.0.0",
"@types/react": "19.2.7",
"@types/react-dom": "19.2.3",
"@types/three": "0.182.0",
"eslint": "9.39.1",
"eslint-config-next": "16.0.8",
"@verekia/warden": "0.0.3",
"babel-plugin-react-compiler": "1.0.0",
"husky": "9.1.7",
"leva": "0.10.1",
"next": "16.0.8",
"oxfmt": "0.48.0",
"oxlint": "1.63.0",
"portless": "0.13.0",
"postcss": "8.5.6",
"prettier": "3.7.4",
"react": "19.2.1",
"react-dom": "19.2.1",
"serve": "14.2.5",
"three": "0.182.0",
"tailwindcss": "3.4.17",
"three": "0.182.0",
"tsup": "8.5.1",
"typescript": "5.9.3",
"zustand": "5.0.9"
},
"peerDependencies": {
"three": ">=0.182.0"
},
"overrides": {
"three": "0.182.0"
},
"patchedDependencies": {
"three@0.182.0": "patches/three@0.182.0.patch"
},
"tsup": {
"entry": [
"src/shaders/index.ts"
],
"clean": true,
"format": [
"cjs",
"esm"
],
"dts": true
}
}
8 changes: 0 additions & 8 deletions prettier.config.js

This file was deleted.

2 changes: 1 addition & 1 deletion src/components/Canvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const MyCanvas = ({ children }: { children: React.ReactNode }) => {
return (
<Canvas
style={{ height: '100vh' }}
gl={async (glProps) => {
gl={async glProps => {
// @ts-expect-error
const renderer = new WebGPURenderer(glProps)
await renderer.init()
Expand Down
8 changes: 4 additions & 4 deletions src/components/Page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ import { setStore, useStoreValue } from '@/lib/store'
import PlaneScene from './PlaneScene'

const Item = ({ href, children }: { href: string; children: ReactNode }) => (
<div className="relative group">
<div className="group relative">
<Link href={href} className="text-sm">
<li className="pl-2">{children}</li>
</Link>
<Link
href={`https://github.com/verekia/tslfx/blob/main/src/pages${href}.tsx`}
className="absolute top-0 right-0 text-xs opacity-0 group-hover:opacity-100 transition-opacity duration-300"
className="absolute right-0 top-0 text-xs opacity-0 transition-opacity duration-300 group-hover:opacity-100"
target="_blank"
>
<div className="flex items-center gap-1">
Expand Down Expand Up @@ -58,7 +58,7 @@ const Page = ({
<title>{title ? `${title} | TSLFX` : 'TSLFX | TSL VFX Library'}</title>
</Head>
<div className={`h-screen ${dark ? 'bg-[#333]' : 'bg-[#f0f0f0]'}`}>
<div className="fixed top-3 left-3 z-50 flex flex-col gap-2 p-2 px-3 py-2 text-white rounded-md bg-black/50">
<div className="fixed left-3 top-3 z-50 flex flex-col gap-2 rounded-md bg-black/50 p-2 px-3 py-2 text-white">
<header className="flex items-center gap-1">
<Link href="/">
<h1 className="text-2xl font-bold">✨ TSLFX ✨</h1>
Expand Down Expand Up @@ -122,7 +122,7 @@ const Page = ({
<Leva titleBar={{ title, filter: false }} {...levaProps} />
</>
)}
<div className="fixed bottom-0 left-0 z-50 flex gap-3 p-2 [&>*]:bg-black [&>*]:rounded-md [&>*]:px-2 [&>*]:py-1 text-white">
<div className="fixed bottom-0 left-0 z-50 flex gap-3 p-2 text-white [&>*]:rounded-md [&>*]:bg-black [&>*]:px-2 [&>*]:py-1">
<button onClick={() => setStore('dark', !dark)}>{dark ? 'Dark' : 'Light'} mode</button>
{is2D && (
<button onClick={() => setStore('boundsPlane', !boundsPlane)}>
Expand Down
2 changes: 1 addition & 1 deletion src/lib/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type State = typeof defaultState
type Key = keyof State

const useStore = create<State>(() => structuredClone(defaultState))
export const useStoreValue = <K extends Key>(key: K) => useStore((state) => state[key])
export const useStoreValue = <K extends Key>(key: K) => useStore(state => state[key])
export const getStore = useStore.getState
export const setStoreMulti = useStore.setState
export const setStore = <K extends Key>(key: K, value: State[K]) => setStoreMulti({ [key]: value })
Expand Down
4 changes: 2 additions & 2 deletions src/pages/composition/impact.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ const ImpactMaterial = () => {
setControls,
] = useControls(() => {
const presets: Record<string, ButtonInput> = Object.fromEntries(
impactPresets.map((preset) => [
impactPresets.map(preset => [
preset.name,
button(() => {
const { seed, aspect, ...rest } = preset.uniforms
Expand All @@ -102,7 +102,7 @@ const ImpactMaterial = () => {
time: 0,
})
}),
])
]),
)

return {
Expand Down
6 changes: 3 additions & 3 deletions src/pages/composition/new-impact.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const NewImpactMaterial = () => {

const [controls, setControls] = useControls(() => {
const presets: Record<string, ButtonInput> = Object.fromEntries(
newImpactPresets.map((preset) => [
newImpactPresets.map(preset => [
preset.name,
button(() => {
const { seed, aspect, ...rest } = preset.uniforms
Expand All @@ -71,7 +71,7 @@ const NewImpactMaterial = () => {
time: 0,
})
}),
])
]),
)

return {
Expand Down Expand Up @@ -107,7 +107,7 @@ const NewImpactMaterial = () => {

const combinedColorNode = useMemo(
() => pipe(blendAlpha, shapeShader.nodes.colorNode, scatterShader.nodes.colorNode),
[shapeShader, scatterShader]
[shapeShader, scatterShader],
)

useFrame((_, delta) => {
Expand Down
8 changes: 4 additions & 4 deletions src/pages/composition/particles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,21 @@ const ParticlesMaterial = () => {
vesicaColor: new Vector4(0, 0.7, 1, 1),
vesicaCount: 2,
},
{ instanceIndex, instanceCount }
{ instanceIndex, instanceCount },
)

const basePosition = vec3(
cos(instanceIndex.toFloat()).mul(2),
range(-0.3, 0.3),
sin(instanceIndex.toFloat()).mul(2)
sin(instanceIndex.toFloat()).mul(2),
)
const rotationSpeed = basePosition.y.mul(1.1)
const rotationAngle = time.mul(rotationSpeed)

const rotatedPosition = vec3(
basePosition.x.mul(cos(rotationAngle)).sub(basePosition.z.mul(sin(rotationAngle))),
basePosition.y,
basePosition.x.mul(sin(rotationAngle)).add(basePosition.z.mul(cos(rotationAngle)))
basePosition.x.mul(sin(rotationAngle)).add(basePosition.z.mul(cos(rotationAngle))),
)

const positionNode = rotatedPosition.add(vec3(range(-0.1, 0.1), range(-0.1, 0.1), range(-0.1, 0.1)))
Expand All @@ -44,7 +44,7 @@ const ParticlesMaterial = () => {
})

return (
<instancedMesh args={[, , instanceCount]}>
<instancedMesh args={[undefined, undefined, instanceCount]}>
<planeGeometry />
<spriteNodeMaterial {...nodes} transparent blending={AdditiveBlending} depthWrite={false} />
</instancedMesh>
Expand Down
14 changes: 7 additions & 7 deletions src/pages/composition/timing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ const timings = {
}

const updateShape = (
shape: {
target: {
uniforms: { time: UniformNode<number>; visible: UniformNode<number> }
},
timing: { startAt: number; duration: number },
totalTime: number
totalTime: number,
) => {
shape.uniforms.time.value = clamp((totalTime - timing.startAt) / timing.duration, 0, 1)
shape.uniforms.visible.value = Number(shape.uniforms.time.value !== 0 && shape.uniforms.time.value !== 1) as 0 | 1
target.uniforms.time.value = clamp((totalTime - timing.startAt) / timing.duration, 0, 1)
target.uniforms.visible.value = Number(target.uniforms.time.value !== 0 && target.uniforms.time.value !== 1) as 0 | 1
}

const TripleExplosionMaterial = () => {
Expand Down Expand Up @@ -162,7 +162,7 @@ const TripleExplosionMaterial = () => {
endOffset: new Vector2(0, -0.4),
}),
],
[]
[],
)

const combined = useMemo(
Expand All @@ -177,9 +177,9 @@ const TripleExplosionMaterial = () => {
explosion1.nodes.colorNode,
drop1.nodes.colorNode,
drop2.nodes.colorNode,
drop3.nodes.colorNode
drop3.nodes.colorNode,
),
[drop1, drop2, drop3, explosion1, blow1, explosion2, blow2, explosion3, blow3]
[drop1, drop2, drop3, explosion1, blow1, explosion2, blow2, explosion3, blow3],
)

useFrame((_, delta) => {
Expand Down
2 changes: 1 addition & 1 deletion src/pages/grass.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const Content = () => {
// baseDarkness: 0.3,
// clusterRadius: 0.4,
}),
[grassGrid.geometry]
[grassGrid.geometry],
)

return (
Expand Down
Loading
Loading