{
    "id": "fume-extraction-arm-ceiling-c5bd3e",
    "title": "Fume Extraction Arm (Ceiling)",
    "class": "prop",
    "triangles": 579,
    "kit": "research-lab-9b9b5d",
    "free": true,
    "plan": "free",
    "price_usd": 0,
    "price_note": "free: the /cdn links need no account and no key (an account adds the ready-to-serve zip). This field, not the triangle count, is what makes it free",
    "owned": true,
    "page": "https://polyfork.dev/asset/fume-extraction-arm-ceiling-c5bd3e",
    "thumbnail": "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/hero.png",
    "preview_glb": "https://polyfork.dev/cdn/fume-extraction-arm-ceiling-c5bd3e-preview.glb",
    "preview_triangles": 579,
    "preview_fidelity": 1,
    "has_rig": true,
    "remixable": true,
    "has_night": true,
    "has_decals": true,
    "has_ik": true,
    "ik_type": "arm",
    "has_skeleton": false,
    "size_m": {
        "x": 0.5,
        "y": 1.6,
        "z": 1.16
    },
    "origin_y": 1.404,
    "mass_kg": 10,
    "download": {
        "glb": "https://polyfork.dev/cdn/fume-extraction-arm-ceiling-c5bd3e.glb",
        "mjs": "https://polyfork.dev/cdn/fume-extraction-arm-ceiling-c5bd3e.mjs",
        "auth": "none"
    },
    "export_formats": {
        "fbx": {
            "url": "https://polyfork.dev/dl/fume-extraction-arm-ceiling-c5bd3e.fbx",
            "for": "Unity, Unreal, Maya, 3ds Max",
            "available": true
        },
        "usdz": {
            "url": "https://polyfork.dev/dl/fume-extraction-arm-ceiling-c5bd3e.usdz",
            "for": "iOS AR Quick Look, Omniverse; with UsdPhysics collision and mass",
            "available": true
        },
        "usda": {
            "url": "https://polyfork.dev/dl/fume-extraction-arm-ceiling-c5bd3e.usda",
            "for": "Isaac Sim, Omniverse, Blender, usdview; with UsdPhysics collision and mass",
            "available": true
        },
        "obj": {
            "url": "https://polyfork.dev/dl/fume-extraction-arm-ceiling-c5bd3e.obj",
            "for": "universal, geometry only, no pivots",
            "available": true
        }
    },
    "export_note": "vertex colours become NAMED MATERIALS on export, named after this asset's own colour knobs; a plain format conversion would arrive white, because only three.js reads our COLOR_0. Built on first request (about a second), cached after. These are yours: send your key as Authorization: Bearer <key>.",
    "night": {
        "display": {
            "color": "#b3e6c2",
            "intensity": 0.8,
            "describe": "the two green readout bars in the housing display window"
        }
    },
    "night_note": "each zone is found by its ALBEDO in COLOR_0: match those vertices exactly, make them emissive at the zone colour and intensity, and drop your scene lights. That is the whole night look.",
    "decals": [
        {
            "name": "flank-r",
            "size": [
                0.36,
                0.18
            ],
            "at": [
                0.19,
                2.8449999999999998,
                -0.3206948158192611
            ],
            "normal": [
                1,
                0,
                0
            ],
            "up": [
                0,
                1,
                0
            ],
            "describe": "the right flank of the ceiling housing, above the teal rear mass"
        },
        {
            "name": "flank-l",
            "size": [
                0.36,
                0.18
            ],
            "at": [
                -0.19,
                2.8449999999999998,
                -0.3206948158192611
            ],
            "normal": [
                -1,
                0,
                0
            ],
            "up": [
                0,
                1,
                0
            ],
            "describe": "the left flank of the ceiling housing, above the teal rear mass"
        }
    ],
    "decals_note": "flat areas you can print your own logo, sign, number or stencil on. `at` is the centre in model space (metres), `normal` points out of the surface, `up` is which way is up in the artwork, `size` is [width, height]. In three.js: bake art with https://polyfork.dev/cdn/sdf.mjs and place it with https://polyfork.dev/cdn/decal.mjs. In any other engine, a `plate` area takes a quad at `at` + `normal` * 0.002; a `projected` area is on a curved face `relief_mm` deep and the mark has to be projected onto the geometry. `albedo` is the colour of the surface underneath, so you can pick art that contrasts.",
    "params_url": "https://polyfork.dev/cdn/fume-extraction-arm-ceiling-c5bd3e-params.json",
    "physics": {
        "mass_kg": 10,
        "mass_source": "estimated",
        "material": "metal",
        "body": "dynamic",
        "dimensions_m": {
            "x": 0.498,
            "y": 1.596,
            "z": 1.157
        },
        "up_axis": "Y",
        "meters_per_unit": 1,
        "volume_m3": 0.211508,
        "collision": {
            "approximation": "convexDecomposition",
            "parts": 14,
            "colliders_url": "https://polyfork.dev/cdn/fume-extraction-arm-ceiling-c5bd3e-colliders.json"
        },
        "note": "For the default knob settings; a size knob changes all of it. dimensions_m and the colliders are measured from the model; mass_kg and material are an estimate of what the real object weighs. body \"static\" means fixed in place (give it a collider, no rigid body); \"dynamic\" means it moves. collision.approximation uses UsdPhysics terms: \"convexHull\" = one hull is a good fit, \"convexDecomposition\" = use the per-part hulls in colliders_url (the one hull would fill a gap, like the space under a table). Model space, metres, Y up, origin as the model ships."
    },
    "simready_metadata": {
        "simready_metadata_mass": 10,
        "simready_metadata_rigid_body_count": 1,
        "usd_dimensions": [
            0.498,
            1.157,
            1.596
        ],
        "usd_up_axis": "Z",
        "usd_meters_per_unit": 1,
        "simready_metadata_validation__profile": null
    },
    "materials": 1,
    "draw_calls": 11,
    "description": "A flexible fume extraction arm mounted from the ceiling. Low-poly, flat-shaded. Real-world scale at 0.5 x 1.6 x 1.16 m, 579 triangles on one material.",
    "palette": [
        {
            "hex": "#f6f7f6",
            "share": 0.387
        },
        {
            "hex": "#4a8d93",
            "share": 0.339
        },
        {
            "hex": "#f1f3f4",
            "share": 0.185
        },
        {
            "hex": "#404040",
            "share": 0.048
        },
        {
            "hex": "#262626",
            "share": 0.024
        },
        {
            "hex": "#e06a5c",
            "share": 0.01
        }
    ],
    "style": "low-poly, flat-shaded vertex colors, no textures, single shared material, so any set of these merges to one draw call; shares palette and scale with its kit",
    "origin": "already at installed height (minY = 1.404 m): the model is built where it belongs, so place it at y=0 and do not lift it. Fixed to the ceiling, built for a 3 m ceiling: shift it by the difference if yours is a different height",
    "mount": {
        "to": "ceiling",
        "height": 3
    },
    "rigged_parts": {
        "turntable": {
            "axis": "y",
            "range": [
                0,
                180
            ]
        },
        "boom-lower": {
            "axis": "x",
            "range": [
                0,
                30
            ]
        },
        "boom-upper": {
            "axis": "x",
            "range": [
                0,
                -50
            ]
        },
        "wrist": {
            "axis": "x",
            "range": [
                0,
                -70
            ]
        }
    },
    "detachable_parts": [],
    "animation": "rigged parts are named groups with the pivot at the hinge/axle: obj.getObjectByName(part) then rotation[axis] (rotate, degrees) or position[axis] (slide, meters)",
    "arm": {
        "slew": "turntable",
        "joints": [
            "boom-lower",
            "boom-upper"
        ],
        "upper": 0.76,
        "lower": 1.11,
        "tip": [
            0,
            -1.11,
            0
        ],
        "tip_rest": [
            0,
            1.404,
            0.317
        ],
        "base": [
            0,
            2.5,
            -0.321
        ],
        "reach": 1.87,
        "stays": [],
        "axes": {
            "slew": "y",
            "joints": "x"
        },
        "units": "metres, radians",
        "runtime": "https://polyfork.dev/cdn/walk.mjs",
        "note": "two-link chain with a slew: the same solver the legged machines use. Joint ranges in `rig` are the real limits and the tip stops at them.",
        "how": "a slew and a two-link boom: aim the tip and solve, stopping at the joint ranges in rigged_parts. three.js users import https://polyfork.dev/cdn/walk.mjs and call arm(model, { rig, detach }).reachTo(point), where rig and detach are the asset module's own exports (import { createAsset, rig, detach } from the .mjs): the arm cannot find its joints without them"
    },
    "published_at": "2026-09-15 19:52:50",
    "renders": [
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/back.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/close.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/compare.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/detail.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/front.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/hero-crop.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/hero.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/left.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/low-back.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/low.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/pose-boom-lower.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/pose-boom-upper.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/pose-turntable.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/pose-wrist.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/proofs.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/right.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/top.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/under.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/variant-colorway-clean-room.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/variant-colorway-graphite.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/variant-hood-nozzle.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/variant-hood-slot.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/variant-reach-0.75.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/variant-reach-1.2.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/variant-shift-0.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/variant-shift-1.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/variant-stem-0.3.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/variant-stem-0.6.png",
        "https://polyfork.dev/files/fume-extraction-arm-ceiling-c5bd3e/renders/views.png"
    ],
    "license": "Use in commercial projects, no attribution. No redistribution of the files themselves. https://polyfork.dev/licensing",
    "access": {
        "as": "anonymous",
        "remix_bakes_per_hour": 40,
        "remix_bakes_left_this_hour": 40,
        "remix_note": "The budget is on generating NEW geometry. Variations anyone has already baked are served to everybody and never counted, so re-fetching a variant you or anyone else has made costs nothing.",
        "remix_bakes_per_month": 100,
        "remix_bakes_left_this_month": 100,
        "remix_allowance_resets": "2026-11-01",
        "remix_allowance_note": "A free account raises this to 300 a WEEK, and costs an email address.",
        "a_free_account_adds": {
            "how": "Authorization: Bearer <key>, created at https://polyfork.dev/account. Costs an email address.",
            "remix_bakes_per_hour": 100,
            "remix_bakes_per_week": 300,
            "downloads": "every FREE asset as .glb, .mjs and a ready-to-serve zip"
        },
        "pro_adds": {
            "url": "https://polyfork.dev/pricing",
            "usd_per_year": 149,
            "module_mjs": "the createAsset() program itself \u2014 knobs evaluated in YOUR engine at runtime, no bake, no round trip, no per-variant file",
            "structured_glb": "the authored GLB: named parts, detachables, real material names, real normals. Worth most where the public preview is one joined anonymous mesh \u2014 every static asset and 186 of the 499 rigged ones. The other 313 rigged assets keep their hierarchy in the preview and can demo themselves without this; get_asset's preview_rig says which you have",
            "cdn": "a per-account /c/<token>/ path you can hotlink from a shipped build; it keeps up when an asset is rebuilt, and the token is not the API key",
            "remix_bakes_per_hour": 900,
            "remix_bakes_per_week": "uncapped \u2014 a free account gets a weekly allowance, Pro does not"
        }
    }
}
