Skip to content

Releases

Crucible 0.20.0

Choose a tag to compare

@github-actions github-actions released this 14 Nov 18:31
382c3c7
  • 67js is now Crucible: the package is @codepawlhq/crucible (addons @codepawlhq/crucible-*), the commands are crucible-mcp and crucible-addon-check, the renderer class is CrucibleRenderer and the skills are build-crucible-scene and render-crucible-media. 67js-mcp, 67js-addon-check and Renderer67 keep working for one release and print a rename notice, and recipes, assets and packs saved with the old 67js.scene, 67js.asset, 67js.pack and 67js-pack.json names still load. (#1183)
  • The Cook native renderer gives the same image for the same scene, seed and settings whatever the dispatch split, so two renders no longer differ in a few bytes (#1006)
  • A mirrored copy (negative determinant matrix) in a flattened path trace now keeps its triangles facing outward, so the native cycles kernel renders it like the instanced scene (#1014)
  • A render job films a recipe whose only motion is physics, cloth or particles with motion: { start: 0 }, no bake-motion first and no 32 node cap (#1017)
  • A native render job without Open Image Denoise now filters with the GPU a-trous filter of the native tracer instead of the slow CPU wavelet filter, and the report says denoiser: "atrous" (#1018)
  • Native render jobs and the Cook comparison keep one OIDN device and filter loaded in the render-native addon, so a denoise after the first skips the tool start, device creation and PFM files, and createOidnDenoiser and findOidnLibrary in the denoise package expose it (#1025)
  • The cycles kernel now matches Cycles on textured cutouts and emitters: a light sample on an emission map reads the map at its point, and a shadow ray no longer lets light through the solid texels of a cutout whose alpha is below 1 (#1030)
  • The Cycles kernel decodes an 8-bit sRGB colour map after filtering it, as Blender Cycles does, so textured surfaces no longer render 2 to 5 percent brighter than Cycles (#1030)
  • Native render jobs on the cycles kernel send each material whole, so blend opacity, sheen, specular tint, anisotropy, iridescence, attenuation and the layer textures reach the kernel instead of rendering opaque or without the layer (#1036)
  • The Cycles reference script renders point and spot lights with a radius as spheres (Soft Falloff off, which Cook models) instead of Blender's default oriented disk, so Cook and Cycles agree on sphere lights again, and render-cycles.py --soft-falloff default|on|off picks the other behaviour (#1040).
  • A scene built for the native path tracer can take more than 400,000 triangles: buildTraceScene accepts maximumTriangles (up to 4,000,000 unique triangles, and four times that with every copy counted), native render jobs on the cycles kernel use it, and the CPU and WebGL path tracers keep the 400,000 limit and its error text (#1041)
  • The README and the site changelog lead with renders, led by the Blender Classroom demo scene (Christophe Seux, CC0) drawn by 67js, and the README states what 67js is for before the install steps (#1043)
    A sunlit classroom with wooden desks and chairs, a green chalkboard and tall windows, rendered by 67js
  • Change notes can carry a picture or clip with a media: <url> <alt text> line, shown on the site changelog and in the GitHub release notes (#1043)
  • A grid volume takes frames (a list of .67vg files) with fps and loop and plays at the scene time in the rasterizer and the CPU path tracer; scripts/vdb-to-grid.py --sequence converts a numbered VDB sequence in one run (#1045)
  • Local volumes take shape: "grid": a 3D texture of density, temperature and flame from an OpenVDB frame (scripts/vdb-to-grid.py), drawn by the rasterizer and the CPU path tracer with Blender-style density, blackbody and anisotropy inputs (#1045)
  • Post steps distortion (an expanding shock ring and heat haze that bend the picture by depth) and flash (a timed brightness lift that feeds bloom) can be placed at a point or on a node and follow the scene clock and motion tracks (#1049)
    A street before and after a shock ring and heat haze
  • A native render job packs its maps straight into the FORMAT-v2 texture pool, so a scene with more than the 4096 by 16384 texels of the old atlas renders instead of failing with "The material textures do not fit the GPU atlas" (#1053)
  • A part takes rayVisibility: { camera, diffuse, glossy, transmission, shadow, volumeScatter } to hide itself from ray kinds in the native path tracer, so a glazed window can stop blocking the sun and sky (#1054)
  • A scene built for the native path tracer can hold up to 500,000 instances of shared geometry instead of 65,536: buildTraceScene accepts maximumInstances, native render jobs on the cycles kernel use it, and the CPU and WebGL path tracers keep 65,536 (#1055)
  • The native cycles kernel draws thin sheets that let light through, such as curtains, leaves and lampshades, from the material fields diffuseTransmission and diffuseTransmissionColor, checked against Blender Cycles (#1058)
  • Added packCameraParams(kernelParams, camera, { seed }) and session.render({ camera, seed }) to the native render package, so a film with a static scene sends only the camera per frame instead of packing the scene again; a frame seed is now written into the frame (it was ignored before) and an invalid seed throws.
  • The cycles native kernel draws a point or spot light with softFalloff: true as the oriented disk of Blender's Soft Falloff (sampling, hits of a path, light tree), carried by the light record flag 32, the recipe light field and buildTraceScene; a light without the field stays a sphere, and render-cycles.py follows each light's softFalloff unless --soft-falloff is given (#1060).
  • Fix render jobs of a fractured wall tripping the browser heap guard: the guard collects garbage before it judges the heap, so only live memory counts.
  • The MCP asset catalog now loads a GLB whose textures sit next to it, such as a Kenney kit's Textures/colormap.png, and embeds them, so a CC0 download works as it is (#1062)
  • scene_apply can place the first instance of a catalog asset, so an agent builds a scene step by step and adds a model in any step (#1063)
  • A sun below 14 degrees now gives a warm golden hour from the sun alone (orange horizon, dimmer blue zenith, stronger warm key, fitted to Blender's sky at 2, 6 and 15 degrees; a sun at 14 degrees and above is unchanged), and environment.sky.preset accepts golden-hour, sunset and blue-hour (#1072).
  • --scene file renders staged showcase scenes: each glbRest part loads with the shared textures and joins in the showcase page's rank order, so the airport and datacenter scenes film with every part (#1085)
  • A render job holds a recipe camera locked for the whole physics, cloth or particle film, and a regression test now checks it (#1089)
  • A render job or a look at a time keeps the automatic floor and horizon fixed by the pose at time 0, so physics shards flying or falling no longer resize the floor or move the horizon of a fixed camera (#1089)
  • Parts of a native path-traced scene whose materials are equal now share one material record, so a copy of a mesh costs 160 bytes in the input instead of 416 and a native render job takes up to 1,000,000 instances (#1100)
  • Agents now read the cylinder and sphere radius right: the geometry notes say node scale is the radius and give the flat and corner widths of a 6-segment cylinder, so hex parts stop coming out twice too wide (#1116)
  • Cook's cycles kernel supports light portals: a rect area light with portal: true emits nothing and the sky is sampled through it, so a room lit only through a window converges; the other tracers ignore it and say so (#1118).
  • A native path traced video blends each denoised frame into the ones before it, reprojected with the first-hit distance and the camera, so denoised frames stop shimmering under a moving camera; JS67_NATIVE_TEMPORAL=off turns it off (#1120)
  • Added environment.cameraIntensity to the native cycles kernel: the strength of the sky for camera rays, also through glass and cutouts, apart from the strength that lights the scene, so a window view can be drawn at 0.2 in one pass (#1121).
  • Cook's cycles kernel writes the distance to the first surface as the depth guide for a sample that scatters in fog before it (it held the scatter distance, so a pixel in light fog came out short), and the README now explains the unit of clampDirect and clampIndirect (Cycles' unit, sent to the kernel times 3) (#1122)
  • Cook native: dispatchBudgetMs cuts each frame into dispatches that cover a tile of pixels and a number of samples, sized from the measured time of the earlier ones, so no dispatch holds the GPU longer than the budget and a display on the same GPU can draw between them; the picture is byte-identical to the one without it, and the result reports dispatchCount and the tile size range (#1124).
  • A process that rendered with the Cook native renderer no longer crashes with SIGSEGV when it exits on Linux with an NVIDIA GPU: the addon now closes its GPU device during Node shutdown, so node --test stops failing files whose tests all passed and a CLI render exits 0 (#1136)
  • Renderer67 takes a background option and a setBackground() method for the clear colour behind the scene, with alpha for transparent canvases (#1141).
  • A render job store lock left by a killed MCP server is taken over by the next start when its owner process is gone, instead of asking for a manual repair; a live owner or an unrecognized lock file is still refused (#1147).
  • Import glTF files with KHR_materials_specular colours above 4, normal maps on TEXCOORD_1, base color maps on TEXCOORD_1 and textures on primitives without their UV set: they load instead of failing, and warnings name the material...
Read more

67js 0.19.0

Choose a tag to compare

@github-actions github-actions released this 12 Nov 03:51
6d83ae4

67js is now Crucible. This release shipped as @codepawlhq/67js, which is deprecated and gets no more updates. Install @codepawlhq/crucible instead and see crucible.codepawl.com and the v0.20.0 notes for the move (bins crucible-mcp, class CrucibleRenderer, skills build-crucible-scene and render-crucible-media).

  • scene_review, scene_render_status and scene_render_result return only what an agent acts on by default; response_format: "detailed" keeps the full diagnostics, digests and metrics, and scene_capabilities takes concise to drop the field notes of a topic (#656).
  • scene_capabilities topic examples (and examples.<tool>) serves one valid call each for scene_create, scene_apply, scene_create_asset and scene_render_submit, with no growth of any tool schema (#657)
  • MCP: one server holds up to 4 open scenes under a 96 MiB geometry cap; the least recently used scene is evicted with a clear error. sessionId (returned by scene_create) picks the scene on every tool, and a call without it uses the last used scene. Each scene keeps 16 checkpoints, oldest evicted first (evictedCheckpointIds), and a render job stays tied to its scene (#658).
  • Motion drivers read custom properties on nodes and bones (motion.properties), distance and rotation difference variables, and can drive lights and shape keys (#694)
  • Mesh particle emitters take from: "edges", with an optional group and sharpAngle, so sparks spread along a rim by edge length (#695)
  • Mesh particle emitters take a vertex group (emitter.group) that weights surface and vertex emission, so sparks come off a painted rim (#695)
  • A cloth sheet with selfCollision: true now reads its own thickness as the contact radius (never past half the shortest edge), so a flag dropped to the floor lies as a thin crumpled layer. Behaviour change: a sheet that sets both selfCollision: true and thickness used to ignore the thickness (radius 0.9 of half the shortest edge) and now keeps layers 2 x thickness apart, so its baked frames differ; pass selfCollision: { radius } to keep a fixed radius. Sheets that set no thickness keep the old radius (#696)
  • A cloth sheet takes softBody (shape matching and pressure on a closed mesh), selfCollision and a stiffnessGroup vertex group, all baked and seekable (#696)
  • Field expressions read face area, edge angle, island index and neighbour counts, and accumulate, statistic, blur, sample index and rank over a whole mesh domain (#699)
  • A recipe curve takes grow, morph targets of the curve grown step by step, so a motion morph track grows a vine and seeking equals playing (#701)
  • mesh_edit gains unsubdivide and circularize, and poke, dual, tris to quads and symmetrize now have Blender golden cases (#703).
  • effects.composite keys a green screen (chroma) or a luma range out of the frame and draws it over a colour or gradient background, with the same mask as the other post steps (part of #707)
  • Post steps take a mask by part names or a depth range, and effects.stylize adds sharpen, kuwahara, posterize and pixelate filters (part of #707)
  • Mesh edits gain geometry masks: vertex_group measure curvature, edge or occlusion, and vertex_color gradients along a group, so a mesh with no UVs can carry edge wear and dirt (#708)
  • Materials gain wear: a vertex group blends the material from paint to bare metal per pixel and a second group adds dirt, so a mesh with no UVs shows metal on its edges and dirt in its cavities (#708)
  • Material graphs get brick, whiteNoise, coord and mapping nodes, so a procedural material works on a mesh without UVs (#708)
  • Blended and transmissive parts cast sun shadows weighted by opacity and tinted by colour, so stained glass, curtains and leaf canopies throw coloured and partial shadows; castShadow: false turns it off (#709)
  • environment.localVolumes adds up to 8 box or sphere volumes that absorb and emit light, in the rasterizer and the CPU path tracer (#710)
  • A mesh boolean cutter can be { "geometry": "<id>" }, another recipe geometry, so cuts form a bounded DAG with cycle and missing-ID errors (#730)
  • Render jobs take a wireframe pass that draws polygon edges over the shaded surface and colours boundary, non-manifold, flipped and degenerate edges for visual review (#732)
  • exportObj (OBJ with MTL text) and exportStl (binary STL) in the new addons/export-mesh entry write the same parts as exportGlb, in world space, with deterministic bytes (#747)
  • The jolt adapter builds convexHull colliders from the flat xyz point array and frees its world when setup throws.
  • 67js/addons/physics-jolt adds joltAdapter, a second engine for the live physics runtime built on the optional jolt-physics package: the same contact and sensor events as Rapier on the same scene, queries, kinematic control and force fields, with recorded 500-box step times for both engines (part of #771)
  • 67js/addons/physics-runtime adds createPhysicsSystem, live physics as a runtime system over an engine adapter (Rapier first): stepped in fixedUpdate, contact and sensor events, kinematic control, ray, shape-cast and overlap queries, and interpolated part matrices (part of #771)
  • createCameraClip treats a ground function that returns a non-finite height as ground height 0, so the camera still stays above the floor instead of clipping being switched off (#772).
  • 67js/addons/player adds vehicle and free-flight controllers, orbit, chase and side-scroller camera rigs, createCameraClip (camera pull-in against walls and ground), and a registry (registerController, registerCameraRig, replaceController, replaceCameraRig) for custom kinds and runtime swaps (#772)
  • Fix: the vehicle and flight controllers ignore a zero-length step, so the runtime's first variable-mode tick no longer turns their speed and velocity into NaN.
  • 67js/addons/player adds a character controller (walk, run, jump, kinematic collide-and-slide on a ground plane, heightfield or boxes, with a mover seam for physics) and swappable follow, first-person and top-down camera rigs as runtime systems (#772)
  • 67js/addons/input adds touchSource (virtual sticks, tap, swipe, pinch), deviceMotionSource, axis smoothing, and recordInput with replaySource so one demo runs from keyboard, gamepad, touch or a replay (#773)
  • 67js/addons/input adds createInput, an open input layer: sources register, named actions and axes with rebinding and dead zones, keyboard, mouse and gamepad sources, and per-fixed-step sampling as a runtime system (#773)
  • Animation graph: blended clips now end with their own shares in poseLayers() (the chain of lerp factors ran in the wrong order, so a walk to run blend played as full run); planted feet no longer slide in a blend space (#774)
  • Breaking for tuned graphs: a layer with two or more active slots (blend space or crossfade) now gives a different pose than before, because the old mix was wrong. Graphs tuned around the old output need a fresh look (#774)
  • createPathFollower walks an NPC along a navmesh route through the animation graph, blending idle, walk and run by speed and moving by root motion (#774)
  • 67js/addons/animation-graph adds createAnimationGraph, a live animation state graph: states with clips or 1D and 2D blend spaces, parameter transitions with crossfades, masked layers, deterministic fixed steps, a runtime system and pose layers for createSkeletonPose (#774)
  • 67js/addons/animation-graph adds root motion (rootMotion option, graph.rootMotion, extractRootMotion; the player controller takes it through a new rootMotion option and state.intentSpeed), interruptible transitions (interrupt: true) and the IK hooks createFootPlacement and createLookAt (#774)
  • 67js/addons/audio adds createAudio, spatial audio for live games on Web Audio: sounds on nodes with a listener on the camera, distance falloff and optional occlusion, triggers from input actions, physics contacts and animation markers, buses with a limiter, and a swappable backend (#775)
  • 67js/addons/streaming evicts lowest asset priority first (new evictionOrder: "distance" opts in to farthest-first within a priority; the default stays least recently used) and adds createWorkerLoader to decode assets in a worker (part of #776)
  • 67js/addons/streaming adds createStreaming, a runtime system that loads assets on demand by distance from a focus point or by game request, with a loader plugin registry (GLB first), a byte budget with least-recently-used eviction, level of detail switching with hysteresis and a loading state game code can read (part of #776)
  • MCP can attach a playable game to a scene (set-game, topic game in scene_capabilities) and scene_export_web writes it as a static web build; 67js/addons/game plays it in a page (#777)
  • 67js/addons/game-rules adds createGameRules, a runtime system that plays a bounded JSON rule document of variables, zone, contact, input, timer and variable triggers and actions, with a deterministic event log (#777)
  • Make the reference netcode relay survive an oversize frame or a socket error instead of crashing, so one bad client cannot drop every player (#778)
  • Add createBroadcastChannelTransport to 67js/addons/netcode, so tabs of one browser play together with no server, with a two-player sample page, a reference WebSocket relay (scripts/netcode-relay.mjs) and a headless Chrome test that plays two pages over both transports with 50 ms injected latency (#778)
  • Cut the netcode sample's lag with 50 ms of injected latency to about 95 ms each way (a snapshot every tick, a 40 ms interpolation delay), keep withInjectedLatency stats live, close the transport on pagehide, and make createBroadcastChannelTransport forget peers silent for `peerTimeoutMilliseconds...
Read more

67js 0.18.0

Choose a tag to compare

@github-actions github-actions released this 10 Nov 12:04
95946a2

67js is now Crucible. This release shipped as @codepawlhq/67js, which is deprecated and gets no more updates. Install @codepawlhq/crucible instead and see crucible.codepawl.com and the v0.20.0 notes for the move (bins crucible-mcp, class CrucibleRenderer, skills build-crucible-scene and render-crucible-media).

  • Clip layers on an imported asset take a strip with start, scale, repeat, blend in and out, extend and blend mode, so a walk repeated three times can crossfade into an idle (#693)
  • Particle emitters take points from a mesh surface (weighted by area), its vertices or its closed volume, push them along the normal, and draw each particle as one of up to 8 listed nodes with a random or surface-aligned rotation (#695)
  • scene_apply takes bake-motion: it samples nodes over a range into keyframe tracks (tracks, IK, constraints, drivers, ragdoll and rigid bodies), optionally drops keys within a position and angle tolerance, and removes the sources it replaced, so the motion exports as a clip (#697)
  • sdf geometry meshes a tree of sphere, box, round box, capsule, cylinder and torus shapes with union, subtract, intersect, smooth blends and offset by surface nets, so blobby bodies and rounded joins need no hand modeling (#700)
  • curve geometry takes kind poly or nurbs, several splines, arc, spiral and star shapes and a trim, so rails, ropes and a growing vine need no hand-placed points (#701)
  • uv_project (cube, cylinder, sphere) and uv_pack mesh edits write and pack UVs with one texel density (#702)
  • mesh_edit gains poke, dual, tris_to_quads, symmetrize, scale_elements and extrude_edges (#703)
  • Add a build mesh modifier that reveals faces over start and length frames in index, seeded random or axis order, with reverse (#704).
  • scene_restore takes revision to undo the last few scene_apply edits in one call, with no checkpoint made first (#744)
  • Docs: add an FAQ page for the questions from the launch: three.js, size and speed, tokens, what the agent sees, undo and diffs (#745).
  • Set SIXTYSEVENJS_MCP_LOG=<file> to log each MCP tool call (tool, duration, ok, result size, never arguments), and run scripts/summarize-mcp-log.mjs for calls, error rate and median duration per tool (#746)
  • Depth precision by default (#751, phase 1 of 2): the colour pass draws with reversed-Z and a 32-bit float depth buffer wherever EXT_clip_control exists, at any far / near ratio, from the first frame; the 16-bit depth buffer is gone; without the extension the depth buffer is 24-bit and the near plane fits the visible bounds when the camera left near unset; reversedDepth: false opts out; installDepthPrecision, hasFarOverlap and requestReversedDepth are removed (use installCoplanarDiagnostics for the warning); bench/flicker/index.html is a viewer with a flicker probe
  • Flush faces stop flickering by default (#751, phase 2, step 1 of 2): faces that lie on one plane or a few millimetres apart, inside one mesh or across parts, are ranked per triangle and drawn with a small view-space depth bias, so the face in front wins at every distance and on every depth format; agent scenes do it unless environment.resolveCoplanar is false, a renderer does it with resolveCoplanar: resolveFlushParts; decal and depthLayer use the same bias; what cannot be ranked (more than 15 faces stacked on one plane, double-sided faces a gap apart) comes back as a coplanar-overlap warning with a reason; coplanarLayers, resolveCoplanarParts and EXACT_FLUSH_DISTANCE are removed; bench/flicker has trap scenes (?trap=, probe.mjs --traps)
  • Hidden flush faces are cut away (#751, phase 2, step 2 of 2): where an opaque face covers another on exactly the same plane (1 cm2 or more), the covered part is cut out of the copy the hidden face draws with, every vertex array interpolated, so a stack of any depth on one plane stops flickering and no longer reports rank-overflow; parts and their geometry stay as they are (flushOrderOf(part).geometry holds the cut copy), instances of one geometry share a cut, and the path tracer traces the cut geometry; a face under a blended or masked face, or a double-sided face under a one-sided one, is still ranked; bench/flicker gains the plaque-closeup-0.5m trap with an open-pixel count
  • Near-flush faces are cut too (#751): an opaque face in front of another by at most a thousandth of the side of their shared area (from 1 mm to 1 cm) cuts the face behind it, as a flush face does, instead of taking a rank; the Melbourne city model, whose stacked blocks nest facades 5 to 17 mm apart up to 17 deep, now reports no rank-overflow
  • scene_inspect and scene_capabilities take the inputs Haiku sent in the bench: short mesh edit branch names (meshEdit.inset), dotted fields (environment.spotLights), near topic names (uvs, scene.terrain), source nodes without a mesh of their own, includeBounds with kind hierarchy; an unwalkable path start names the nearest walkable point (#761)
  • scene_inspect with a node ID lists the parts below it and tags each with fromNode; a node with no part below it, such as a skeleton joint, returns its transform (parent, joint flag, local translation, rotation and scale, rest world position) instead of an error (#761)
  • 67js/addons/runtime adds createRuntime, a live game loop with fixed, variable or interpolated steps, ordered pluggable systems, pause on a hidden tab and a frame-time readout (#770)

Install: npm install @codepawlhq/67js@0.18.0

67js 0.17.0

Choose a tag to compare

@github-actions github-actions released this 09 Nov 20:43
76510af

67js is now Crucible. This release shipped as @codepawlhq/67js, which is deprecated and gets no more updates. Install @codepawlhq/crucible instead and see crucible.codepawl.com and the v0.20.0 notes for the move (bins crucible-mcp, class CrucibleRenderer, skills build-crucible-scene and render-crucible-media).

  • bake.gridFog: the sun the fog scatters is dimmed by the fog between it and the sun (#543)
  • bake.gridFog: true (with irradianceGrid) lets the irradiance grid scatter in the scene's volume fog, off by default, for sunlit closed rooms with fog (#543)
  • An irradiance grid bake runs on the kernel worker with its 90 s limit instead of the page's 20 s, so 8 grid bounces fit a hall like temple-hall (#543)
  • Volume fog: opt-in scatterOctaves, multiScatter, multiExtinction, multiAnisotropy, keyTransmittance and surfaceTransmittance approximate multiple scattering of the sun in the haze and dim the sun by the haze between it and a point or surface. Off by default; the scenes without them render the same (#543)
  • The publish workflow waits up to five minutes for the registry to serve a new version instead of two. The 0.16.0 publish succeeded, but the registry took longer than two minutes, so the check failed and skipped the release page.
  • applyAnimation(time, clip, { checks: false }) and renderer.updateParts(parts, { checks: false }) skip the per-frame pose checks for clips you trust, and frames on the same clip no longer reset and snapshot every node. Eight animated characters: update CPU 1.6 ms to 1.3 ms with checks, 0.9 ms without.
  • Skinned character frames cost less CPU: palette math reads joint matrices in place and a normal pose allocates nothing, so eight animated characters update about 0.1 ms faster (#572)
  • Animating an imported glTF character costs about a third of the CPU it did: applyAnimation prepares the pose once instead of twice, reuses its rollback snapshot, and skin validation checks each distinct set of joint weights once instead of every vertex. Eight RobotExpressive characters went from 4.5 ms to about 1.5 ms per frame.
  • Add a per-frame density and velocity field to volume fog (also renderer.setFogField), flow-advected noise (flowStrength, flowPeriod), a profile choice, and scattering from up to 8 point and spot lights in the fog (issue #573). A fog without a field or lights draws exactly as before.
  • Breaking: a renderer that draws environment.volumeFog needs import '@codepawlhq/67js/addons/fog-shader' first (recipes, the film and the MCP server load it on their own), which takes about 2.5 KB gzip out of the core (#577)
  • Motion blur and bloom no longer leave a ghost of the previous frame after a seek (#578)
  • A few mirrored skin vertices (a finger pinched between two joints) no longer fail the frame. They draw pinched, and renderer.diagnostics lists skin-reflected-vertices with the count and the joints and weights of the first one (#581)
  • Materials accept alphaMode: 'add' for additive glow, and the opacity of blend and add parts changes each frame through updateParts without a new batch. (#586)
  • Volume fog takes detailOctaves, detailAmount, warp and contrast for wispier mist, profileSoftness for where a layer top starts to fade, and keyScattering to scale only the key light shafts (#586)
  • Metal with detailed normal and roughness maps no longer sparkles from frame to frame at grazing angles; environment.specularAntiAliasing sets the strength (#588)
  • resolveCoplanar: resolveFlushParts no longer layers pairs that lie on one plane to within a micrometre (the depth buffer already settles them) and settles chains of equal-sized parts, so it stops adding flicker on dense scenes (#593)
  • A film with a very long lens (far / near over 10,000, such as near 0.08 and far 9000) now switches to reversed-Z float depth on its own: Renderer67 loads reversed-depth.js as a separate chunk on the first such frame and every frame after it draws with it (await renderer.reversedDepthReady to have it from frame one; reversedDepth: false keeps the 24-bit buffer). On the metro film, 24-bit depth could not tell surfaces 2 micrometres apart at 2.6 m, and stairs, canopy panels, handrails and steel flickered between frames; those pairs went from thousands of flipping pixels to under 60 (#593)
  • resolveCoplanar is now a function, resolveFlushParts from 67js/addons/coplanar-overlap, so the plane-keyed search stays out of the core bundle. Its depth layers also work under reversed depth: the slope part of the offset is 16 times larger there, because the constant part moves a surface by under a micrometre in a float depth buffer (#593)
  • motion.constraints: adds copy_transforms, limit_distance, limit_scale, stretch_to, locked_track, transformation and action, each one scene_motion call (#595)
  • Recipes gain cone, icoSphere, circle (filled or ring) and line geometries, and plane is accepted as an alias of grid (#596)
  • Fields can read other surfaces: nearest (distance, point or normal of the closest point on a surface) and raycast (hit, distance, point or normal along a direction, with a miss value), plus attr: group to read a vertex group back. In instances the surface is a geometry id, so a scatter can avoid a path mesh and follow terrain; in set_position, displace, vertex_group and vertex_color it is a geometry record, and vertex_group stores the result by name (#597)
  • Force fields: a fields list on the recipe particles and cloth sections accelerates particles, hair and cloth through one shared evaluation, with wind, turbulence, vortex, drag and magnet types, strength, falloff, radius and seed. The same seed gives the same frames (#598).
  • Ocean modifier: the ocean mesh edit and stack node turn a flat grid into a seeded sea (Phillips spectrum for the wind, choppiness, size, seed, time) and write the vertex group foam where the surface folds. The same seed and time give identical vertices. Part of #599.
  • Per-object motion blur: effects.motionBlur.objects (0 to 1, off by default) smears each part that moves during the shutter along its own screen path, while the still background stays sharp; it replaces camera motion blur on that frame and loads on demand (#600)
  • render jobs: passes now include diffuse, glossy, shadow, ao and mist next to albedo, normal, emission, depth and objectId; diffuse + glossy + emission add back to the lit image, and exr keeps values above 1 (#601)
  • Three named post steps join defocus (effects.depthOfField) in the look: effects.colorBalance (lift, gamma, gain, each three numbers), effects.glare (streaks, count, angle, fogGlow, threshold, size) and effects.lensDistortion (distortion, dispersion). Each is off until a recipe names it and draws nothing at its neutral values, so a recipe without them renders the same pixels as before. Their code is a lazy module that loads only for a recipe that names one; installPostSteps(renderer) from src/post-steps.js adds the stages (#602)
  • scene_inspect reports a bake-stale warning when motion has moved a light, the sun or a part off the pose a light bake was traced at; a scene without motion or without a bake pays nothing. bake.rebake: true bakes each pose a render or seek samples (the last 4 are kept, about 0.7 s each on a small room), so the baked light matches the frame and the warning does not apply. Material animation is not checked, see docs/light-bake.md (#603)
  • MCP scene_create and set-environment now accept the 16 point, 8 spot and 7 area lights the engine renders, read from one limits file, not 8 point and 4 area (#604)
  • Motion tracks animate lights, the sun, sky and fog, exposure and focus distance, so a sunset, a lamp flicker or a rack focus plays from a recipe (#605)
  • Nodes take visible (keyable in a motion track), castShadow, receiveShadow, holdout and shadowCatcher, so films hide parts without parking them and renders composite over footage (#606)
  • Scene cameras take projection orthographic with orthoScale, focalLength with sensorWidth (instead of fov), shift [x, y] and fStop for depth of field, in recipes and set-camera (#607)
  • environment.hdri and a .cube environment.look: shipped HDRIs (sky-clouds, studio-softbox) and looks (teal-orange, noir), or catalog files by ID, work from recipes and MCP (#608)
  • Material graphs: new outputs opacity (base texture alpha), clearcoat and transmission (per-pixel masks), and mixing nodes layer (mask-blended layers such as paint over rust), hue and curve. The rasterizer reads opacity and clearcoat, the CPU path tracer all three. Graphs without them bake the same (#609)
  • A recipe mesh takes shapeKeys (named offsets or move-only edits), animated by the existing morph tracks and written as morph targets in a GLB (#610)
  • Render jobs gain four optional output settings, all off by default so a plain job writes the same bytes: transparent: true (PNG with alpha, for image and stills), format: "png16" or "exr" (16-bit PNG and OpenEXR from a half-float frame, passes included: depth in metres as float32 Z, object IDs as float32 id), region: { x, y, width, height } (a crop of the whole frame, for image, stills and video) and fps up to 60. The encoders are small hand-written Node code with no new dependency. docs/agent-render-jobs.md has the details.
  • Area lights can cast soft shadows: castShadow: true on an areaLights entry takes one tile of the local shadow atlas, and the penumbra widens with the rectangle and with the gap between blocker and receiver. Cost is 16 blocker taps and 32 filter taps per lit pixel, only for a shadowed area light.
  • environment.sunAngularRadius (radians, 0.0005 to 0.2) softens the sun shadow in the raster through the cascades (at least one sli...
Read more

67js 0.16.0

Choose a tag to compare

@anxuanng anxuanng released this 08 Nov 06:18
bce0a97

67js is now Crucible. This release shipped as @codepawlhq/67js, which is deprecated and gets no more updates. Install @codepawlhq/crucible instead and see crucible.codepawl.com and the v0.20.0 notes for the move (bins crucible-mcp, class CrucibleRenderer, skills build-crucible-scene and render-crucible-media).

Highlights

  • GPU path tracer: backend: 'gpu' renders the 1080p demo room in about 40 s, against 586 s on the CPU. The light bake can use it too (#302)
  • Outlines and toon shading with environment.lines (#285)
  • Subsurface scattering for skin, wax and leaves with the material subsurface block (#283)
  • 3D Gaussian splats from a standard PLY file, as an addon (#288)
  • environment.viewTransform picks ACES, AgX or neutral, and AgX now matches Blender 5.2 (#282)
  • Easing curves and cubic-bezier on keyframes, within 1e-4 of Blender (#286)

Agents and MCP

  • Recipes place catalog GLB assets next to terrain and procedural meshes, and render jobs draw them (#320)
  • A vegetation node plants one tree or a seeded forest over terrain, with seasons and wind (#321)
  • motion.drive drives a car model along a path with real steering, reverse and brake lights (#322)
  • Crowds of up to 1,000 walkers draw in one batch per material (#323)
  • Clips retarget between characters, feet stay planted, and morph targets key by name (#325)
  • Materials can play an image sequence as their colour map (#339)
  • The new scene_walkmap tool finds where a character can walk (#553)
  • The MCP schema now accepts every environment and node field the engine reads (#490)

Rendering

  • Up to 16 point, 8 spot and 7 area lights, from 8, 8 and 4 (#261)
  • Water got depth fade, soft shadows on the bed, refraction, and a reflection that survives rough water and costs less (#349)
  • Default fog fits the scene size, so the far side of a big world no longer fades out (#263)
  • volumeFog takes heightFalloff for valley mist that thins with height
  • Sunlit rooms get softer bounced light by default, and bake.irradianceGrid adds Cycles-like multi-bounce light (#506)
  • Far trees no longer pop darker when they switch level, and big forests can use impostor cards (#432)
  • Reversed-Z depth and a z-fighting warning that names both parts and the fix (#310)
  • Mesh blend softens the seam where a rock or a trunk meets the ground (#478)
  • Your own post passes and a GLSL hook on materials (#405)
  • Plain scenes draw faster, and far shadow cascades redraw less often (#388)

glTF

  • Many more real-world files load: meshopt, WebP, spec-gloss, optional extensions, skeleton-only clips and common Sketchfab defects (#496)
  • KTX2 textures stay GPU-compressed, about a quarter of the memory (#304)
  • Large texture sets scale down instead of throwing, and the default limits are higher (#260)

Animation and physics

  • Cloth follows moving characters, and steps live with pins and tearing (#326)
  • renderer.updateParts is about 6 times faster for matrix and colour updates (#299)

Tools, docs and site

  • Video export encodes in the browser: a 4,488-frame film took 21 s instead of 140 s (#301)
  • Path traced jobs can use Intel Open Image Denoise (#303)
  • The docs are now interactive learn pages with live examples, plus an API reference (#508)
  • The showcase worlds show their first frame sooner and stream the rest in (#445)
  • Agent benchmarks against three.js code and the Blender MCP on the same tasks (#31)

Breaking changes

  • Skin, morph, water, foliage, terrain, liquid and splat shaders moved into addons. A renderer that draws those parts without the import throws and names it. Recipes and loaders import them on their own (#281)
  • glTF limit errors are one RangeError that names every limit the file goes over. Match on the option name, not the old message (#458)
  • material.lightMask defaults to -1, every light (#261)
  • normalizeAgentLook returns fogDensity: null for fog that fits the scene (#263)

Install: npm install @codepawlhq/67js@0.16.0

67js 0.15.0

Choose a tag to compare

@anxuanng anxuanng released this 05 Nov 11:03

67js is now Crucible. This release shipped as @codepawlhq/67js, which is deprecated and gets no more updates. Install @codepawlhq/crucible instead and see crucible.codepawl.com and the v0.20.0 notes for the move (bins crucible-mcp, class CrucibleRenderer, skills build-crucible-scene and render-crucible-media).

  • Add fog-valley and fog-room to the reference suite (part of issue #165, which stays open). Against Cycles fog-room scores 0.1953 (EEVEE 0.3730) and fog-valley 0.1967 (EEVEE 0.1952), so the fog constants of #161 hold on both. Scaling the fog ambient by the share of the sky the volume sees was measured and not kept: it worsened the region of temple-hall (0.2305 to 0.2513), so #164 is not fixed. See bench/reference/README.md.

  • Fix a thin bright line at the corners of baked rooms (issue #165). The texel just outside a lightmap chart took the average of the neighbouring chart, so the wall of dark-shaft read 128 of 255 sky visibility at its bottom edge where the interior reads 1. rasterizeTexels in src/light-bake.js now gives that texel to the nearest triangle. Baked dark-shaft goes from 0.0653 to 0.0607 and temple-hall from 0.0578 to 0.0559 against Cycles.

  • Add three options for each grand reference scene, to pick from (part of issue #168, which stays open until An picks). bench/reference/grand-scenes.js holds mountain-valley, temple-hall and megacity-dusk as -a, -b and -c, each with its own composition, light and time of day, drawn by npm run reference -- --grand into grand.json and images/grand-<id>.jpg (baseline.json and the existing images are unchanged). The Blender side gained a gradient world, written as the same equirectangular image 67js draws. bench/reference/grand-sheets.py makes one comparison sheet per scene.

  • Hide sky light where the scene blocks it: inside tree crowns and on a valley floor (issue #191, part of it). createTree bakes a sky visibility into each foliage vertex from the leaf density above it, and createTerrain bakes one into each terrain vertex from the horizon in 16 directions. The shader multiplies it into the environment light only, and meshes without it read 1. On bench/reference, the foliage crown went from 0.298 to 0.200 (Cycles 0.175) and the score from 0.1173 to 0.1023 (EEVEE 0.0888); mountain-valley went from 0.3483 to 0.2623 (EEVEE 0.1879), and its floor from 0.417 to 0.360 (Cycles 0.272). No other scene changed to four digits. The agent scene geometry bound allows 4 more bytes for each terrain vertex.

  • Compare trees like with like (issue #166, part of it). The Blender side of bench/reference now rebuilds the 67js leaf model for foliage materials (back-face normal, colour and normal variation, sky reflection 0.3, and light from behind as a Translucent BSDF with weight 0.3 * pi / (3.7, 3.4, 2.9)), and the 67js back light is now shadowed by the sun shadow. foliage goes from 0.1290 to 0.1173 against Cycles (EEVEE 0.0864 to 0.0888) and mountain-valley from 0.3473 to 0.3483 (EEVEE 0.1828 to 0.1879); no other scene moved. The remaining gap is canopy and valley sky occlusion, recorded in bench/reference/README.md.

  • Make the recipe bake presets bake large rooms (issue #189). A preset that does not fit the 5 million path step budget at 16 samples and 1 texel per unit now gives up bounces one at a time instead of refusing, and bake.reduction tells the agent what it asked for, what ran and that explicit samples, bounces and texelsPerUnit (up to 24 million path steps, 20 s inline) buy more. temple-hall at standard now bakes (16 samples, 1 bounce, 1.37 texels per unit, 0.0705 against 0.1504 unbaked with a probe). fine is now the same as standard: five samples and density mixes within the 20 s limit scored no better on the room scenes. Table in bench/reference/README.md.

  • Score the recipe bake presets against Cycles (part of issue #170, open for the frame costs). standard scores 0.127 to 0.159 on the three rooms (no bake 0.51), fine is no better, and standard and fine refuse temple-hall. Table in bench/reference/README.md.

  • No test asserts real elapsed time any more (issue #179): work counts and a fake clock replace stopwatches. smoke:agent-review-close and smoke:film-physics are wired; the second starts its own server.

  • Show the floor and the other parts in smooth metal (part of issue #167, which stays open). traceObjectProbes in src/probe-trace.js gives each part with metallic of at least 0.5 and roughness of at most 0.6 a reflection probe of its own, traced from the middle of the part without it (up to 8 parts, lit by direct light and the environment's diffuse light), and placeProbes assigns it. metal scores 0.1294 to 0.1036 against Cycles (EEVEE 0.0916), brushed-film 0.1149 to 0.1029, car-paint 0.1059 to 0.1038, material-spheres 0.1312 to 0.1293; every scene without a reflective part is unchanged to four digits and draws the same frame (metal 1.51 ms plain, 1.58 ms with four probes). npm run reference -- --object-probes places them (opt in; the committed baseline is unchanged); recipes do not yet.

  • Make every test file pass on its own, and check it in CI (issue #172). node --test tests/agent-bake.test.js failed 16 of 19 because npm test preloaded every on-demand module into each test process, so 28 files only passed through that preload. The loading path agents use was fine (tests/agent-scene-on-demand.test.js runs it in clean processes). Each of those files now imports tests/support/load-agent-scene-modules.mjs itself, npm test no longer preloads, and npm run test:isolated (scripts/test-each-file.mjs) runs each file in its own process, 4 at a time at below-normal priority, rerunning a failure alone once so a busy machine does not count. It runs in the Test workflow.

  • Fix links in the npm package that pointed at docs it does not ship (issue #178). docs/guide.md, docs/material-maps.md, README.md and ROADMAP.md now link the 20 unshipped docs, CONTRIBUTING.md, the texture credits and the changelog by absolute GitHub URL; shipping those docs would add 64 KB gzip. npm run check:links:package packs the archive, unpacks it and checks every link inside (26 files, 0 broken), and the Test workflow runs it.

  • Take 34 KB of headroom under the npm archive budget without raising it (issue #177). CHANGELOG.md no longer ships in the package, because GitHub serves it; the archive went from 740,972 to 705,961 bytes against the 740,000 budget. bench/size/README.md now says how the budget is set and what it protects.

  • Add a test that fails when the MCP tool count in docs/guide.md, docs/mcp.md, index.html or scripts/smoke-mcp.mjs differs from the tools/list result (issue #180). The server registers 22 tools; the 23rd register( in the file is the function definition, so the documented count was right.

  • Remove the AGPL-3.0 @codepawlhq/orglet-ui package, React and react-dom from the website (issue #176). The site now uses its own tokens and button in src/site-tokens.css and src/site-controls.js, and screenshots of the pages match before and after. The site JavaScript drops from 1,778,425 to 1,531,367 bytes. The published package was never affected.

  • A renderer no longer draws its shadow map a second time on the first frame when the frame has no assembly; the constructor already drew it. On mountain-valley that removes 9.72 million shadow triangles from the first frame, with identical pictures (issue #171). node bench/reference/profile-scene.mjs <scene> prints where a scene's time goes, and frame-time.mjs --plain measures scenes that are too large for the light bake.

  • The shadow pass skips instances outside the light and draws each shadow caster at a level chosen from the world size of one shadow texel (issue #171). A part can carry shadowLods, in the format of lods, and the renderer uses the coarsest level whose error is within one texel of an orthographic shadow map; tree bark carries a trunk-only level. On mountain-valley the shadow pass fell from 9.72 to 2.34 million triangles; the score against Cycles moved from 0.3473 to 0.3478 and the other scenes kept theirs.

  • Tell an agent when its scene is a closed room with no bake (issue #163). scene_inspect now returns a closed-room-without-bake diagnostic when 90 percent or more of 48 rays from the middle of the scene hit a front face, and names bake; measured against Cycles a closed room goes from 0.1430 and 0.1436 (dark-shaft, temple-hall) to 0.0609 and 0.0560 once baked. No frame cost and no schema change; agent scene entry grows 884 bytes gzip. bakeSkyVisibility in light-bake writes only the occlusion map (0.1021 and 0.0856 in under a second) and is not applied automatically. A closed room without a bake now shows a warning in scene_inspect.

  • Clean up docs, media and scripts. Remove stale logs, six unreferenced PNG previews (about 6.1 MB) with their render sidecars, the OpenAI skill metadata and ten scripts that aimed at harness pages that no longer exist. Update the roadmap, the mesh and verification docs and the contributing guide, point the links to unshipped docs at GitHub, and add npm run check:links, smoke:modeling, smoke:material-maps and benchmark:mesh-query.

  • The GitHub repository is anxuanng/67.js, public since 2026-11-02. Links and repository.url point there, which npm provenance needs to match.

  • Follow 3 bounces by default in a light bake, up from 2 (part of issue #159, which stays open). Baked rooms scored worse after the sky visibility change (lit-interior 0.1444 to 0.1915, brick-room 0.1515 to 0.2048 against Cycles) because the occlusion map removed the world light that had been filling the light a 2 bounce path cuts off. With 3 bounces they score 0.1341 and 0.1412, dark-shaft 0.0609 and...

Read more

67js 0.14.0

Choose a tag to compare

@anxuanng anxuanng released this 05 Nov 11:03

67js is now Crucible. This release shipped as @codepawlhq/67js, which is deprecated and gets no more updates. Install @codepawlhq/crucible instead and see crucible.codepawl.com and the v0.20.0 notes for the move (bins crucible-mcp, class CrucibleRenderer, skills build-crucible-scene and render-crucible-media).

  • Add motion.ik to imported assets: IK runs over the selected clip and overrides, moves every skin and rigid part, and takes worldForward, so agents can pose imported characters through MCP without writing quaternions
  • Add npm run smoke:character, which takes a real CC0 character through the MCP server along the path an agent uses

Install: npm install @codepawlhq/67js@0.14.0

67js 0.13.1

Choose a tag to compare

@anxuanng anxuanng released this 05 Nov 11:03

67js is now Crucible. This release shipped as @codepawlhq/67js, which is deprecated and gets no more updates. Install @codepawlhq/crucible instead and see crucible.codepawl.com and the v0.20.0 notes for the move (bins crucible-mcp, class CrucibleRenderer, skills build-crucible-scene and render-crucible-media).

  • Add createAssetPose, which poses a loaded glTF asset's whole hierarchy so every skin and rigid part moves, and clipFromGltfAnimation, which converts its clips for layers and retargetClip
  • Add worldForward to aim IK, because bone axes differ between real rigs
  • Accept skin weights one unit of Float32 rounding above 1, which exporters write and which made such files fail to load

Install: npm install @codepawlhq/67js@0.13.1

67js 0.13.0

Choose a tag to compare

@anxuanng anxuanng released this 05 Nov 11:03

67js is now Crucible. This release shipped as @codepawlhq/67js, which is deprecated and gets no more updates. Install @codepawlhq/crucible instead and see crucible.codepawl.com and the v0.20.0 notes for the move (bins crucible-mcp, class CrucibleRenderer, skills build-crucible-scene and render-crucible-media).

  • Add motion.ik to procedural recipes: two-bone and aim solvers on node hierarchies, with fixed, keyframed or node-following targets, so agents can animate jointed models without writing quaternions; scene_inspect reports whether each solver reaches its target across the clip
  • Add 67js/addons/skeleton-pose: clip layers for skinned rigs with joint masks and additive blending, two-bone IK with poles and aim IK with angle limits and shared chains, all seekable, with joints named by rig name or humanoid bone

Install: npm install @codepawlhq/67js@0.13.0

67js 0.12.0

Choose a tag to compare

@anxuanng anxuanng released this 05 Nov 11:03

67js is now Crucible. This release shipped as @codepawlhq/67js, which is deprecated and gets no more updates. Install @codepawlhq/crucible instead and see crucible.codepawl.com and the v0.20.0 notes for the move (bins crucible-mcp, class CrucibleRenderer, skills build-crucible-scene and render-crucible-media).

  • Add the recipe material field pattern: eleven seeded, tileable procedural surfaces (wood, planks, bricks, tiles, marble, stone, concrete, metal, rust, fabric, noise) that need no UVs, keep their real size under node scale, and can change while a scene is open
  • Add periodic gradient, ridged and cellular noise for those patterns
  • Close extrude solids whose holes have aligned edges: their caps left T-junctions, so the mesh was open and booleans refused it
  • Let mesh_inspect take geometry as well as geometries, matching mesh_edit and mesh_stack
  • Say in the MCP schema that box and cylinder are bevelled by default, and how to get exact sizes

Install: npm install @codepawlhq/67js@0.12.0