{"id":32868532,"url":"https://github.com/jonathan-j8/joeat-utils","last_synced_at":"2026-05-06T01:31:27.168Z","repository":{"id":318322399,"uuid":"1070796000","full_name":"Jonathan-J8/joeat-utils","owner":"Jonathan-J8","description":"TypeScript library providing utility functions and Three.js wrappers for every day work.","archived":false,"fork":false,"pushed_at":"2025-11-03T09:44:22.000Z","size":390,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-11-03T10:19:40.352Z","etag":null,"topics":["emitter","spring","threejs"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Jonathan-J8.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-06T13:00:19.000Z","updated_at":"2025-11-03T09:43:18.000Z","dependencies_parsed_at":"2025-10-06T15:20:47.658Z","dependency_job_id":null,"html_url":"https://github.com/Jonathan-J8/joeat-utils","commit_stats":null,"previous_names":["jonathan-j8/joeat-utils"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Jonathan-J8/joeat-utils","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jonathan-J8%2Fjoeat-utils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jonathan-J8%2Fjoeat-utils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jonathan-J8%2Fjoeat-utils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jonathan-J8%2Fjoeat-utils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Jonathan-J8","download_url":"https://codeload.github.com/Jonathan-J8/joeat-utils/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jonathan-J8%2Fjoeat-utils/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":283475140,"owners_count":26841941,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-11-09T02:00:05.828Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["emitter","spring","threejs"],"created_at":"2025-11-09T08:01:25.415Z","updated_at":"2025-11-09T08:03:00.630Z","avatar_url":"https://github.com/Jonathan-J8.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Joeat - Utils\n\nTypeScript library providing modular wrappers and utilities for Three.js and other utility function for every day work. Built with type safety, dependency injection pattern, and testing.\n\n## Features\n\n- 🎯 **Modular Architecture**: Clean, reusable components for common Three.js patterns\n- 🔧 **Dependency Injection**: Accept Three.js classes as parameters for optimal tree-shaking\n- 📝 **Full TypeScript Support**: Strict typing with comprehensive type definitions\n- 🎨 **Shader Integration**: Built-in uniforms system for seamless GLSL integration\n- 🧪 **Thoroughly Tested**: 184+ unit tests with 95%+ coverage across all modules\n- 📦 **Multiple Formats**: ES modules, CommonJS, and UMD builds available\n\n## Installation\n\n### Latest Version\n\n```bash\nnpm install github:Jonathan-J8/joeat-utils#dist-only\n# or\nnpx degit github:Jonathan-J8/joeat-utils#dist-only ./joeat-utils\n```\n\n### Specific Version\n\n```bash\n# Install specific version (recommended for production)\nnpm install github:Jonathan-J8/joeat-utils#v1.2.2\n\n# Using degit\nnpx degit github:Jonathan-J8/joeat-utils#v1.2.2 ./joeat-utils\n```\n\n### In package.json\n\n```json\n{\n\t\"dependencies\": {\n\t\t\"joeat-utils\": \"github:Jonathan-J8/joeat-utils#v1.2.2\"\n\t}\n}\n```\n\n## Example\n\nFind the example [here](/example)\n\n### Run the example\n\n```bash\nnpm run dev\n```\n\n## Quick Start\n\n### Common Module Pattern\n\nMost modules follow a consistent API pattern for predictable usage:\n\n#### 🏗️ **Constructor Pattern**\n\n```typescript\nconst module = new ModuleName({\n\tinstance: threeJsObject, // Three.js object to wrap\n\t...dependencies, // Required Three.js classes for tree-shaking\n});\n```\n\n#### 🔧 **Core Methods**\n\n- **`resize({ width, height, pixelRatio })`** - Handle responsive updates\n- **`update({ time, deltaTime, deltaMs })`** - Animation loop integration\n- **`debug(gui: GUI)`** - Runtime debugging with lil-gui controls\n- **`clear()`** - Clean disposal and garbage collection\n\n#### 📊 **Properties**\n\n- **`module.instance`** - Access to the wrapped Three.js object\n- **`module.uniforms`** - Shader uniforms for GLSL integration\n\n#### 🎯 **Event Integration**\n\n```typescript\nconst myEmitter = new MonoEventEmitter\u003c[{ someNumber: number }]\u003e();\nconst foo = ({ someNumber }) =\u003e {\n\t// your logic\n};\nmyEmitter.addListener(foo);\nmyEmitter.fire({ someNumber: 10 });\nmyEmitter.removeListener(foo);\nmyEmitter.clear();\n```\n\n```typescript\nimport { Animator, RendererWrapper, PointerTracker, CameraWrapper } from '../../src';\nimport * as THREE from 'three';\nimport { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';\n\n// Create renderer with post-processing support\nconst renderer = new THREE.WebGLRenderer();\nconst rendererWrapper = new RendererWrapper({\n\tinstance: renderer,\n\tVector2: THREE.Vector2,\n});\n\n// Set up cameras with controls\nconst perspectiveCamera = new THREE.PerspectiveCamera(75, 2, 0.1, 1000);\nconst orthographicCamera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0.1, 1000);\nconst controls = new OrbitControls(perspectiveCamera, renderer.domElement);\n\nconst cameraWrapper = new CameraWrapper({\n\tperspective: perspectiveCamera,\n\torthographic: orthographicCamera,\n\tcontrols: controls,\n\tVector3: THREE.Vector3,\n\tQuaternion: THREE.Quaternion,\n});\n\n// Set up animation loop\nconst animator = new Animator();\nanimator.addListener(({ time, deltaTime }) =\u003e {\n\tcameraWrapper.update({ deltaTime });\n\trendererWrapper.update(scene, cameraWrapper.instance, deltaTime);\n});\n\n// Add mouse interaction\nconst pointerTracker = new PointerTracker({\n\tcamera: cameraWrapper.instance,\n\tVector2: THREE.Vector2,\n\tVector3: THREE.Vector3,\n\tPlane: THREE.Plane,\n\tRaycaster: THREE.Raycaster,\n});\npointerTracker.init(renderer.domElement);\n\n// Handle resize\nwindow.addEventListener('resize', () =\u003e {\n\tconst width = window.innerWidth;\n\tconst height = window.innerHeight;\n\n\tcameraWrapper.resize({ width, height });\n\trendererWrapper.resize({ width, height, pixelRatio: window.devicePixelRatio });\n});\n\nanimator.play();\n```\n\n## Core Modules\n\n### Animator\n\nCentral animation loop with renderer integration support.\n\n```typescript\nconst animator = new Animator();\n\n// Basic animation loop\nanimator.addListener(({ time, deltaTime }) =\u003e {\n\t// Update your scene\n});\n\n// Value interpolation\nanimator.interpolate({\n\tfrom: 0,\n\tto: 100,\n\tduration: 2000,\n\tonUpdate: ({ value }) =\u003e {\n\t\tmesh.position.x = value;\n\t},\n});\n\n// Animation\nanimator.animate({\n\tsteps: 0,\n\tduration: 400,\n\tdelay: 100,\n\titerations: 1,\n\tonUpdate: () =\u003e {\n\t\t// your animation logic\n\t},\n});\n\nanimator.play();\n```\n\n### RendererWrapper\n\nWebGL renderer abstraction with post-processing effects support.\n\n```typescript\nconst rendererWrapper = new RendererWrapper({\n\tinstance: new THREE.WebGLRenderer(),\n\tVector2: THREE.Vector2,\n\tEffectComposer: EffectComposer, // Optional for post-processing\n});\n\n// Access uniforms for shaders\nconst uniforms = {\n\tuTime: animator.uniforms.uTime,\n\tuResolution: rendererWrapper.uniforms.uResolution,\n};\n\n// Add post-processing effects\nrendererWrapper.addEffect(bloomPass, fxaaPass);\n\n// Handle resize\nrendererWrapper.resize({\n\twidth: window.innerWidth,\n\theight: window.innerHeight,\n\tpixelRatio: window.devicePixelRatio,\n});\n```\n\n### PointerTracker\n\nMouse/pointer interaction handling with coordinate normalization.\n\n```typescript\nconst camera = new THREE.PerspectiveCamera();\nconst pointerTracker = new PointerTracker({\n\tcamera: camera,\n\tVector2: THREE.Vector2,\n\tVector3: THREE.Vector3,\n\tPlane: THREE.Plane,\n\tRaycaster: THREE.Raycaster,\n});\n\n// Initialize with element\npointerTracker.init(canvas);\n\n// Access normalized coordinates and world position\nconst uniforms = {\n\tuPointerPosition: pointerTracker.uniforms.uPointerPosition, // [-1, 1]\n\tuPointerWorldPosition: pointerTracker.uniforms.uPointerWorldPosition, // World coordinates\n\tuPointerPositionVelocity: pointerTracker.uniforms.uPointerPositionVelocity,\n\tuPointerPress: pointerTracker.uniforms.uPointerPress, // Pointer pressure\n\tuPointerScroll: pointerTracker.uniforms.uPointerScroll,\n\tuPointerScrollVelocity: pointerTracker.uniforms.uPointerScrollVelocity,\n};\n```\n\n### Resizer\n\nResponsive behavior with ResizeObserver integration.\n\n```typescript\nconst resizer = new Resizer(canvas);\n\nresizer.addListener(({ width, height, pixelRatio }) =\u003e {\n\trenderer.setSize(width, height, false);\n\trenderer.setPixelRatio(pixelRatio);\n\tcamera.aspect = width / height;\n\tcamera.updateProjectionMatrix();\n});\n\n// Configure quality settings\nresizer.resolutionFactor = 0.8; // Reduce resolution for performance\nresizer.maxSize = 2048; // Limit maximum dimensions\n```\n\n### CameraWrapper\n\nAdvanced camera management with dual-camera system, controls integration, and comprehensive shader uniforms.\n\n```typescript\nconst perspectiveCamera = new THREE.PerspectiveCamera(75, 2, 0.1, 1000);\nconst orthographicCamera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0.1, 1000);\nconst controls = new OrbitControls(perspectiveCamera, canvas);\n\nconst cameraWrapper = new CameraWrapper({\n\tperspective: perspectiveCamera,\n\torthographic: orthographicCamera,\n\tcontrols: controls, // OrbitControls, FlyControls, ArcballControls, or DragControls\n\tVector3: THREE.Vector3,\n\tQuaternion: THREE.Quaternion,\n});\n\n// Access comprehensive uniforms for shaders\nconst uniforms = {\n\tuCameraDirection: cameraWrapper.uniforms.cameraDirection, // Camera world direction\n\tuCameraScale: cameraWrapper.uniforms.cameraScale, // Camera world scale\n\tuCameraQuaternion: cameraWrapper.uniforms.cameraQuaternion, // Camera world rotation\n};\n\n// Switch between camera types at runtime\n// default cameraWrapper.instance === controls.object\ncameraWrapper.instance = 'OrthographicCamera'; // Switch to orthographic\ncameraWrapper.instance = 'PerspectiveCamera'; // Switch back to perspective\n\n// Handle resize (updates both cameras)\ncameraWrapper.resize({\n\twidth: window.innerWidth,\n\theight: window.innerHeight,\n});\n\n// Update camera uniforms and controls\ncameraWrapper.update({ deltaTime: 0.016 });\n\n// Debug camera in lil-gui\ncameraWrapper.debug(gui); // Adds camera position, type toggle, and controls settings\n\n// Clean up resources\ncameraWrapper.clear(); // Disposes controls and clears cameras\n```\n\n#### Camera Features\n\n- **Dual Camera System**: Seamlessly switch between perspective and orthographic cameras\n- **Controls Integration**: Support for OrbitControls, FlyControls, ArcballControls, and DragControls\n- **Smart Initialization**: Automatically detects initial camera type from controls object\n- **Comprehensive Uniforms**: Direction, scale, and quaternion vectors for advanced shader effects\n- **Responsive Design**: Handles both perspective aspect ratio and orthographic bounds calculation\n- **Debug Interface**: Runtime camera controls with position tracking and controls configuration\n- **Conditional Updates**: Controls only update when enabled, optimizing performance\n\n### TaskQueue\n\nSequential task execution with async support.\n\n```typescript\nconst taskQueue = new TaskQueue();\n\ntaskQueue.add(\n\t() =\u003e console.log('First task'),\n\tasync () =\u003e {\n\t\tawait fetch('/api/data');\n\t\tconsole.log('Async task completed');\n\t},\n\t() =\u003e console.log('Final task'),\n);\n\nawait taskQueue.play(); // Executes all tasks in sequence\n```\n\n### Spring\n\nPhysics-based animation system.\n\n```typescript\nconst spring = new Spring(0, {\n\tonUpdate: ({ value }) =\u003e {\n\t\t// animate any value\n\t},\n});\n\nspring.to(1);\nspring.update(); // Call in your animation loop\n```\n\n### SceneWrapper\n\nScene resource management with automatic disposal.\n\n```typescript\nconst sceneWrapper = new SceneWrapper({\n\tscene: new THREE.Scene(),\n});\n\n// Automatic cleanup of materials, geometries, textures\nsceneWrapper.clear();\n```\n\n### MonoEventEmitter\n\nType-safe single-event emitter base class.\n\n```typescript\nclass MyAnimator extends MonoEventEmitter\u003c[{ progress: number }]\u003e {\n\tupdate() {\n\t\tthis.fire({ progress: 0.5 });\n\t}\n}\n\nconst animator = new MyAnimator();\nanimator.addListener(({ progress }) =\u003e {\n\tconsole.log(`Progress: ${progress * 100}%`);\n});\n```\n\n## Shader Integration\n\nAll wrapper classes provide uniforms for seamless GLSL integration:\n\n```glsl\n// Time and rendering uniforms\nuniform float uTime;\nuniform float uDeltaTime;\nuniform vec2 uResolution;\n\n// Pointer interaction uniforms\nuniform vec2 uMouse;\nuniform vec2 uPointerPositionVelocity;\nuniform float uPointerPress;\nuniform vec2 uPointerScroll;\n\n// Camera uniforms (from CameraWrapper)\nuniform vec3 uCameraDirection;\nuniform vec3 uCameraScale;\nuniform vec4 uCameraQuaternion;\n\nvoid main() {\n  vec2 uv = gl_FragCoord.xy / uResolution.xy;\n\n  // Animated effect using time\n  float wave = sin(uv.x * 10.0 + uTime * 2.0);\n\n  // Mouse interaction\n  float mouse = length(uv - uMouse * 0.5 + 0.5);\n\n  // Camera-based effects\n  float cameraInfluence = dot(uCameraDirection, vec3(0.0, 1.0, 0.0));\n\n  // Combine effects\n  vec3 color = vec3(wave, mouse, cameraInfluence);\n\n  gl_FragColor = vec4(color, 1.0);\n}\n```\n\n## Development\n\n```bash\n# Install dependencies\nnpm install\n\n# Build library\nnpm run build\n\n# Run tests\nnpm test\n\n# Lint and format\nnpm run lint\nnpm run format\n```\n\n## Contributing\n\n1. Fork the repository\n2. Create your feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\nAll commits are validated with ESLint + Prettier code quality checks and unit tests\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonathan-j8%2Fjoeat-utils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjonathan-j8%2Fjoeat-utils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonathan-j8%2Fjoeat-utils/lists"}