Summary
Trail cannot produce a trail behind an object moving into the scene. Points are stored as {x, y, age} and drawn as connected screen-space quads, so under a Camera3d the ribbon stays flat — it does not narrow with distance or sit on the terrain.
This is the effect a "leave a trail behind you" prompt asks for in any 3D or 2.5D game: ski tracks, exhaust, a speed streak, a spell arc. It is also the first thing anyone reaches for, because Trail's own JSDoc carries a rainbow-gradient example.
What exists today
Two workarounds, both viable, neither the obvious one:
ParticleEmitter with referenceSpace: "world" — particles stay where they were dropped while the emitter moves on, and the emitter propagates its depth to each particle so Camera3d projects them correctly. Good for discrete puffs; visibly not a continuous ribbon.
- A procedural
Mesh built from the object's recent path, with mesh.vertexColors for the gradient. Correct result, ~60–80 lines of strip generation the user writes themselves.
Proposal
Let a trail's points carry z, and generate a camera-facing strip when the stage has a perspective camera.
addPoint(x, y, z?), points stored with z (0 keeps every existing 2D trail identical)
- accept a
Vector3d / Renderable target and sample pos.z alongside pos.x/y
- build each segment's quad from the path tangent × the vector to the camera, rather than a screen-space perpendicular — the standard billboarded-ribbon construction
minDistance becomes a world-space distance rather than px
The 2D path must stay bit-for-bit unchanged: with all-zero z and no perspective camera, the existing screen-space construction is already correct and cheaper.
Relationship to #1383
#1383 adds a texture to the ribbon; this issue changes its geometry. They are independent in value but overlap heavily in implementation — both are strip generation with per-vertex attributes, and the UV work #1383 needs is most of what a 3D strip needs anyway.
Worth deciding the point representation before either lands: if #1383 is built on {x, y} first, the texture path has to be redone when z arrives. Adding z to the point record up front costs almost nothing.
Notes
Found while checking whether melonJS could build a sledding game from a screenshot — a chase-camera 3D scene whose headline feature was a rainbow trail behind the sled. Everything else in the scene mapped onto existing features (Camera3d + followOffset, InstancedMesh, castGroundShadow, Sprite3d billboards, world-space particles, BitmapText); the trail was one of two gaps.
The skill documenting Trail now states it is 2D-only and names the two workarounds, so agents stop walking into it (da041b259).
Summary
Trailcannot produce a trail behind an object moving into the scene. Points are stored as{x, y, age}and drawn as connected screen-space quads, so under aCamera3dthe ribbon stays flat — it does not narrow with distance or sit on the terrain.This is the effect a "leave a trail behind you" prompt asks for in any 3D or 2.5D game: ski tracks, exhaust, a speed streak, a spell arc. It is also the first thing anyone reaches for, because
Trail's own JSDoc carries a rainbow-gradient example.What exists today
Two workarounds, both viable, neither the obvious one:
ParticleEmitterwithreferenceSpace: "world"— particles stay where they were dropped while the emitter moves on, and the emitter propagates its depth to each particle soCamera3dprojects them correctly. Good for discrete puffs; visibly not a continuous ribbon.Meshbuilt from the object's recent path, withmesh.vertexColorsfor the gradient. Correct result, ~60–80 lines of strip generation the user writes themselves.Proposal
Let a trail's points carry
z, and generate a camera-facing strip when the stage has a perspective camera.addPoint(x, y, z?), points stored withz(0 keeps every existing 2D trail identical)Vector3d/Renderabletarget and samplepos.zalongsidepos.x/yminDistancebecomes a world-space distance rather than pxThe 2D path must stay bit-for-bit unchanged: with all-zero
zand no perspective camera, the existing screen-space construction is already correct and cheaper.Relationship to #1383
#1383 adds a texture to the ribbon; this issue changes its geometry. They are independent in value but overlap heavily in implementation — both are strip generation with per-vertex attributes, and the UV work #1383 needs is most of what a 3D strip needs anyway.
Worth deciding the point representation before either lands: if #1383 is built on
{x, y}first, the texture path has to be redone whenzarrives. Addingzto the point record up front costs almost nothing.Notes
Found while checking whether melonJS could build a sledding game from a screenshot — a chase-camera 3D scene whose headline feature was a rainbow trail behind the sled. Everything else in the scene mapped onto existing features (
Camera3d+followOffset,InstancedMesh,castGroundShadow,Sprite3dbillboards, world-space particles,BitmapText); the trail was one of two gaps.The skill documenting
Trailnow states it is 2D-only and names the two workarounds, so agents stop walking into it (da041b259).