JSPM

@trap_stevo/morphal

0.0.4
    • ESM via JSPM
    • ES Module Entrypoint
    • Export Map
    • Keywords
    • License
    • Repository URL
    • TypeScript Types
    • README
    • Created
    • Published
    • Downloads 13
    • Score
      100M100P100Q77441F
    • License See License in LICENSE.md

    The flagship entity framework for building scalable, reusable, and visually stunning entities.

    Package Exports

    • @trap_stevo/morphal

    Readme

    🌌 @trap_stevo/morphal

    The flagship entity framework for building scalable, reusable, and visually stunning entities.
    Compose entities from parts, drive them with behaviors, style them with flexible materials, and scale with instancing and performance primitives.


    πŸš€ Features

    • 🧩 Declarative Entities – JSON-like specs for parts, transforms, collisions, and behaviors
    • 🎨 Material Factories – Presets like basic, emissive, pbr-normal, sprite, etc., with unlimited extra options
    • 🎭 Behavior System – Lifecycle-driven behaviors (fadeIn, fadeOut, float, rotate, pulseEmissive, …)
    • πŸ“¦ Instancing Pools – Massive scenes via InstancedSpritePool and InstancedMeshPool
    • 🧭 Performance Toolkit – Distance culling, impostor swapping, and entity pooling
    • 🧰 Anchors & Metadata – Built-in anchors (tip, center, …) and collision accessors
    • 🌍 2D & 3D Unified – Mix HUD overlays (orthographic) with world-space entities (perspective)

    βš™οΈ System Requirements

    Requirement Version
    Browser Chrome β‰₯ 91, Firefox β‰₯ 90
    JavaScript ES2020+
    npm β‰₯ 9.x (recommended)
    OS Windows, macOS, Linux

    🧩 Spec Reference

    Entity Spec (Morphal.create(spec, ctx)) β€” Core Fields

    Key Type Description Default
    name string Entity name "morphal-entity"
    orient "view" | "yaw" | "none" Camera alignment mode undefined
    zOffset number Layering priority (higher draws on top) undefined
    materialProps object Props applied to all root-level materials {}
    transform object { position?, rotation?, scale? } {}
    parts array List of part specs []
    behaviors array List of behavior configs []

    transform structure:

    • position: { x, y, z }
    • rotation: { x, y, z } (radians)
    • scale: number or { x, y, z }

    Part Spec β€” Common Fields

    Key Type Description Default
    name string Unique per entity auto
    type string Registered part type required
    material string Material preset name preset-specific
    color string Base color preset-specific
    opacity number 0..1 preset-specific
    orient "view" | "yaw" | "none" Per-part camera alignment undefined
    zOffset number Layering priority for the part undefined
    transform object { position?, rotation?, scale? } {}
    behaviors array [{ type, ...options }] []
    materialProps object Extra material overrides {}
    collision object { dim:2|3, tags:[], idPrefix?, isStatic?, metadata? } undefined
    ...rest any Forwarded to the specific part factory β€”

    Behavior Config β€” Common Fields

    Key Type Description Default
    type string Behavior name required
    ...options any Behavior-specific options β€”

    Included behaviors (examples):

    • fadeIn({ duration, fromScale })
    • fadeOut({ duration, scaleTo })
    • float({ axis, speed, amplitude })
    • rotate({ axis, speed })
    • pulseEmissive({ frequency, intensity })

    πŸ“š Methods Overview

    Morphal (Core) β€” Methods

    Method Description Async
    registerPart(name, factory) Register a part factory ❌
    registerBehavior(name, factory) Register a behavior factory ❌
    registerMaterial(name, factory) Register a material factory ❌
    getRegistry() Access registries (parts, behaviors, materials) ❌
    traverseMaterials(object, cb) Visit all materials in a subtree ❌
    setMaterialProps(object, props) Assign props to all materials in a subtree ❌
    makeMaterial(name, params, ctx) Create a material from a registered factory ❌
    create(spec, ctx) Build an entity; returns { group, update, destroy, bus, findPart } ❌

    Entity β€” Methods

    Method Description Async
    group Root node β€”
    update(time, delta) Advance all behaviors ❌
    destroy() Dispose resources & detach from parent ❌
    findPart(name) Retrieve a child part by name ❌

    Collision Accessors (per-part)

    part.userData.morphal.collision (if enabled in the part spec):

    Method Description Async
    snapshotMatrix() Copy world matrix into a stable buffer ❌
    getMatrixRef() Get the stable Float32Array(16) matrix reference ❌
    getWorldOBB() Compute world OBB or small sphere ❌
    forEachWorldTriangle(consume) Stream all world-space triangles into consume(ax,ay,az,bx,by,bz,cx,cy,cz) ❌

    Performance Toolkit

    Method / Class Description Async
    Perf.culling.register({ node, maxDist, onCull?, setVisible? }) Distance-based visibility control ❌
    Perf.culling.unregister(entry) Remove from culling set ❌
    Perf.culling.update(camera) Update all culling entries ❌
    Perf.impostorSwitch.register({ node, camera, near, far, poolKey, poolTexture, scene }) Swap far meshes for billboard instances ❌
    Perf.impostorSwitch.unregister(rec) Remove impostor entry ❌
    Perf.impostorSwitch.update() Evaluate swaps ❌
    EntityPool({ create, warm }) Simple pooling of entities ❌
    EntityPool.acquire() Acquire an entity from the pool ❌
    EntityPool.release(entity) Return entity to the pool ❌

    Instancing Pools

    Class / Method Description Async
    Instancing.pools Registry of named pools β€”
    Instancing.get(key) Get a pool by key ❌
    Instancing.set(key, pool) Register a pool ❌
    Instancing.delete(key) Dispose + unregister a pool ❌
    new InstancedSpritePool({ key, capacity, texture, faceMode }) Instanced sprites billboard pool ❌
    pool.alloc({ x, y, z, sx, sy, opacity }) Allocate an instance ❌
    pool.freeId(id) Free an instance by id ❌
    pool.updateBillboards(camera) Align billboards to camera ❌
    pool.dispose() Dispose pool resources ❌
    new InstancedMeshPool({ key, capacity, geometry, material }) Instanced mesh pool ❌
    pool.alloc(matrix4) Allocate an instance ❌
    pool.update(id, matrix4) Update instance transform ❌
    pool.freeId(id) Free an instance ❌
    pool.dispose() Dispose pool resources ❌

    🧱 Part Catalog (Built-ins)

    vectorShape

    Option Type Description Default
    svg string Inline SVG markup "<svg/>"
    curveSegments number Tessellation detail 48
    common fields β€” name, material, transform, behaviors, collision β€”

    billboardPlane

    Option Type Description Default
    src / map string / Texture Base texture β€”
    normalSrc/normalMap string / Texture Normal map null
    emissiveSrc/emissiveMap string / Texture Emissive mask map
    tint string Multiply tint color "#ffffff"
    emissiveColor string Emissive color "#ffffff"
    emissiveIntensity number Emissive strength 1.0
    alphaTest number Alpha cutout threshold 0.0
    parallaxDepth number Parallax depth effect 0.0
    common fields β€” transform, behaviors, collision β€”

    tentacle

    Option Type Description Default
    segments number Number of curve subdivisions (β‰₯ 2) 12
    length number Tentacle length 1.2
    thickness number Tube radius 0.05
    curvature number Sinusoidal curvature factor 0.6
    noise number Noise factor for wavy displacement 0.0
    common β€” color, material, behaviors, collision β€”

    sprite

    Option Type Description Default
    src / map string / Texture Sprite texture β€”
    color string Tint color "#fff"
    opacity number Alpha 1.0
    size number Uniform sprite size 1.0
    common β€” transform, behaviors, collision β€”

    rippleRing

    Option Type Description Default
    radius number Ring radius 1.0
    thickness number Band thickness 0.1
    color string Base color "#ffffff"
    opacity number Alpha 0.5
    segments number Radial subdivisions 32
    common β€” transform, behaviors, collision β€”

    energyBlob

    Option Type Description Default
    radius number Blob sphere radius 0.32
    color string Blob emissive color "#b38cff"
    opacity number Alpha 0.2
    common β€” material, transform, behaviors, collision β€”

    gltf

    Option Type Description Default
    src string Path to GLTF/GLB file β€”
    scale number | {x,y,z} Scale factor(s) 1.0
    center boolean Auto-center loaded model false
    common β€” transform, behaviors, collision β€”

    🎨 Materials (Built-ins)

    basic

    Option Type Description Default
    color string Base color "#ffffff"
    emissive string Forces additive blend null
    opacity number Alpha 1.0
    transparent boolean Transparency true
    additive boolean Additive blending false

    emissive

    Option Type Description Default
    mode string "unlit" or "pbr" "unlit"
    color string Base color "#000000"
    emissive string Emissive color "#ffffff"
    intensity number Emissive intensity 1.0

    pbr-normal

    Option (subset) Type Description
    color, map β€” Base color & texture
    emissive* β€” Emissive params
    normalMap* β€” Normal mapping
    roughness*/metalness* β€” PBR surface controls
    aoMap* β€” Ambient occlusion
    displacement* β€” Height mapping
    envMap* β€” Environment reflections
    transmission*/ior/thickness β€” Glass parameters
    clearcoat*/sheen* β€” Coatings & fabric sheen

    πŸ“¦ Installation

    npm install @trap_stevo/morphal
    
    ---
    
    ## πŸ—οΈ Quick Start (HTML)
    
    ```js
    import { Morphal } from "@trap_stevo/morphal";
    
    // Renderer bootstrap
    const appEl = document.getElementById("app");
    const renderer = new WebGLRenderer({ antialias: true });
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.outputColorSpace = SRGBColorSpace;
    appEl.appendChild(renderer.domElement);
    
    // 3D scene & camera
    const scene = new Scene();
    scene.background = new Color("#0b0b12");
    const camera = new PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 500);
    camera.position.set(0, 0.8, 3);
    scene.add(camera);
    scene.add(new HemisphereLight(0xffffff, 0x334466, 0.35));
    
    // 2D HUD scene (orthographic)
    const scene2D = new Scene();
    const ortho = new OrthographicCamera();
    scene2D.add(ortho);
    function resizeOrtho() {
      const w = window.innerWidth, h = window.innerHeight;
      ortho.left = -w / 2;
      ortho.right = w / 2;
      ortho.top = h / 2;
      ortho.bottom = -h / 2;
      ortho.near = -1000;
      ortho.far = 1000;
      ortho.updateProjectionMatrix();
    }
    resizeOrtho();
    
    // Responsive resize
    window.addEventListener("resize", () => {
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();
      renderer.setSize(window.innerWidth, window.innerHeight);
      resizeOrtho();
    });
    
    // Minimal entity
    const entity = Morphal.create({
      name: "demo",
      orient: "view",
      parts: [
        { type: "billboardPlane", src: "/flare.png", scale: 2 },
        { type: "tentacle", color: "#C655FF", segments: 12 }
      ],
      behaviors: [
        { type: "fadeIn", duration: 1.5 },
        { type: "float", axis: "y", speed: 0.4 }
      ]
    }, { parent: scene, camera });
    
    // Basic loop
    let last = performance.now() / 1000;
    (function tick() {
      const now = performance.now() / 1000;
      const delta = now - last;
      last = now;
      entity.update(now, delta);
      renderer.render(scene, camera);
      requestAnimationFrame(tick);
    })();

    πŸ§ͺ Examples

    1) Vector Shapes (SVG)

    Morphal.create({
      parts: [
        {
          type: "vectorShape",
          svg: "<svg><circle cx='0' cy='0' r='0.6'/></svg>",
          material: "basic",
          color: "#a6b2ff",
          opacity: 0.9,
          transform: { scale: { x: 1.2, y: 1.2, z: 1 } },
          zOffset: -1,
          behaviors: [{ type: "pulseEmissive", frequency: 1.25, intensity: 0.25 }],
          materialProps: { transparent: true, opacity: 0.9 },
          collision: { dim: 3, tags: ["eye", "sclera"] }
        }
      ]
    }, { parent: scene, camera });

    2) Image Billboards

    Morphal.create({
      parts: [
        {
          type: "billboardPlane",
          src: "/textures/flare.png",
          scale: 1.25,
          tint: "#9f67ff",
          emissiveIntensity: 2.0,
          zOffset: 2
        }
      ]
    }, { parent: scene, camera });

    3) Procedural Mesh Part

    Morphal.registerPart("energyBlob", (cfg = {}, ctx) => {
      const geometry = new SphereGeometry(cfg.radius ?? 0.32, 48, 48);
      const material = Morphal.makeMaterial(
        cfg.material || "emissive",
        { color: cfg.color || "#b38cff", opacity: 0.2, transparent: true }
      );
      const mesh = new Mesh(geometry, material);
      mesh.userData.anchors = { center: mesh };
      return mesh;
    });

    4) 2D HUD Overlay (Orthographic)

    const hudEntity = Morphal.create(
      { name: "hud", orient: "view", parts: [ /* vector parts… */ ] },
      { parent: scene2D, camera: ortho }
    );

    5) Collision Export

    function gatherCollidable(root) {
      const out = [];
      root.traverse(o => {
        const c = o.userData?.morphal?.collision;
        if (c?.snapshotMatrix) out.push(o);
      });
      return out;
    }
    const collidables = gatherCollidable(entity.group);
    for (const part of collidables) {
      const c = part.userData.morphal.collision;
      c.snapshotMatrix();
      const matrix = new Float32Array(c.getMatrixRef());
      const obb = c.getWorldOBB();
      const tris = [];
      c.forEachWorldTriangle((ax, ay, az, bx, by, bz, cx, cy, cz) => {
        tris.push(ax, ay, az, bx, by, bz, cx, cy, cz);
      });
    }

    πŸ“œ License

    See License in LICENSE.md


    ✨ Morph, Render, Scale

    From SVG paths to billboards to procedural meshes, Morphal gives you one unified way to define, manage, and optimize entities at any scale β€” in both 2D and 3D contexts.