[{"data":1,"prerenderedAt":2243},["ShallowReactive",2],{"\u002Fblog\u002Fwhats-new-summer-2026":3,"author-alvarosabu":2218,"formatted-blog-post-\u002Fblog\u002Fwhats-new-summer-2026":2237},{"id":4,"title":5,"author":6,"body":7,"category":2201,"date":2202,"description":2203,"draft":2204,"extension":2205,"meta":2206,"navigation":222,"path":2207,"readingTime":2208,"seo":2213,"stem":2214,"thumbnail":2215,"url":2216,"__hash__":2217},"blog\u002Fblog\u002Fwhats-new-summer-2026.md","The Loop Chronicles: Summer 2026 Recap","alvarosabu",{"type":8,"value":9,"toc":2170},"minimark",[10,36,41,56,112,115,120,126,521,524,595,602,629,637,644,658,666,691,718,729,766,785,840,847,854,876,883,907,914,936,956,1036,1077,1089,1097,1101,1110,1153,1237,1265,1272,1276,1282,1313,1319,1336,1391,1404,1425,1432,1458,1547,1590,1594,1632,1636,1663,1732,1735,1800,1804,1821,1837,1848,1851,1865,1894,1898,1901,1950,1981,2019,2023,2031,2103,2107,2111,2133,2137,2151,2163,2166],[11,12,13,14,18,19,23,24,27,28,31,32,35],"p",{},"Yo! Welcome back to ",[15,16,17],"strong",{},"The Loop Chronicles",". We skipped the July and August editions because, honestly, we were too busy shipping. Rubber ducks 🐥, mostly... into the pool 🏊... with ",[20,21,22],"code",{},"\u003CRigidBody collider=\"ball\">"," on each one, because a duck that doesn't bob is a frankly a downright lie. Between cannonballs we also found time to ship some code 🚀, so this one is a double feature: everything that landed across the TresJS ecosystem between July and mid-September 2026, wrapped up in ",[20,25,26],{},"@tresjs\u002Fcore@5.9.2",", ",[20,29,30],{},"@tresjs\u002Fcientos@5.9.2"," and ",[20,33,34],{},"@tresjs\u002Frapier@1.1.2",". Grab a coffee ☕, this is a long one.",[37,38,40],"h2",{"id":39},"portals-have-entered-the-scene","Portals have entered the scene",[11,42,43,44,47,48,55],{},"The headline. TresJS can now render ",[15,45,46],{},"a scene inside another scene",", through a mesh, with proper perspective. Two new pieces make it work (",[49,50,54],"a",{"href":51,"rel":52},"https:\u002F\u002Fgithub.com\u002FTresjs\u002Ftres\u002Fpull\u002F1445",[53],"nofollow","#1445","):",[57,58,59],"prose-list",{},[60,61,62,91],"ul",{},[63,64,65,74,75,78,79,82,83,86,87,90],"li",{},[49,66,69],{"href":67,"rel":68},"https:\u002F\u002Fdocs.tresjs.org\u002Fapi\u002Fcomponents\u002Ftres-portal",[53],[15,70,71],{},[20,72,73],{},"\u003CTresPortal>"," in ",[20,76,77],{},"@tresjs\u002Fcore",": reparents its declarative children into any target ",[20,80,81],{},"Object3D"," or ",[20,84,85],{},"Scene",". It is a thin wrapper over Vue's ",[20,88,89],{},"\u003CTeleport>",", so children stay fully reactive.",[63,92,93,74,102,105,106,111],{},[49,94,97],{"href":95,"rel":96},"https:\u002F\u002Fcientos.tresjs.org\u002Fapi\u002Fmaterials\u002Fmesh-portal-material",[53],[15,98,99],{},[20,100,101],{},"\u003CMeshPortalMaterial>",[20,103,104],{},"@tresjs\u002Fcientos",": renders its children into a private scene and projects that scene onto the host mesh as a perspective-correct, geometry-masked window. A port of the beloved ",[49,107,110],{"href":108,"rel":109},"https:\u002F\u002Fdrei.docs.pmnd.rs\u002Fportals\u002Fmesh-portal-material",[53],"drei MeshPortalMaterial",".",[11,113,114],{},"Here is what that looks like when you push it: an RPG difficulty selector where each card is a portal into its own world, with its own lighting, fog and environment.",[116,117],"blog-embed-lab",{"src":118,"title":119},"https:\u002F\u002Flab.tresjs.org\u002Fexperiments\u002Fportals-rpg-difficulty\u002F","Portals RPG difficulty selector demo",[11,121,122,123,125],{},"The API is exactly what you would hope for. Put a ",[20,124,101],{}," on a mesh and declare the portal's contents as its children:",[127,128,133],"pre",{"className":129,"code":130,"language":131,"meta":132,"style":132},"language-vue shiki shiki-themes catppuccin-latte catppuccin-latte catppuccin-frappe","\u003Cscript setup lang=\"ts\">\nimport { TresCanvas } from '@tresjs\u002Fcore'\nimport { Environment, MeshPortalMaterial, OrbitControls } from '@tresjs\u002Fcientos'\n\nconst blend = ref(0)\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003CTresCanvas>\n    \u003CTresPerspectiveCamera :position=\"[0, 0, 6]\" \u002F>\n    \u003COrbitControls \u002F>\n\n    \u003CTresMesh>\n      \u003CTresPlaneGeometry :args=\"[3, 4]\" \u002F>\n      \u003CMeshPortalMaterial :blend=\"blend\">\n        \u003C!-- Everything in here renders INTO the portal, not the main scene -->\n        \u003CSuspense>\n          \u003CEnvironment preset=\"dawn\" :background=\"true\" \u002F>\n        \u003C\u002FSuspense>\n        \u003CTresMesh :position=\"[0, 0, -1]\">\n          \u003CTresTorusKnotGeometry :args=\"[0.6, 0.25, 128, 32]\" \u002F>\n          \u003CTresMeshStandardMaterial color=\"#fbb03b\" \u002F>\n        \u003C\u002FTresMesh>\n      \u003C\u002FMeshPortalMaterial>\n    \u003C\u002FTresMesh>\n  \u003C\u002FTresCanvas>\n\u003C\u002Ftemplate>\n","vue","",[20,134,135,165,189,217,224,249,259,264,274,285,305,315,320,330,349,367,374,385,412,422,438,455,473,482,492,502,512],{"__ignoreMap":132},[136,137,140,144,148,152,155,158,162],"span",{"class":138,"line":139},"line",1,[136,141,143],{"class":142},"sWdzt","\u003C",[136,145,147],{"class":146},"slJ5s","script",[136,149,151],{"class":150},"s1cdE"," setup",[136,153,154],{"class":150}," lang",[136,156,157],{"class":142},"=",[136,159,161],{"class":160},"s9Zht","\"ts\"",[136,163,164],{"class":142},">\n",[136,166,168,172,176,180,183,186],{"class":138,"line":167},2,[136,169,171],{"class":170},"sZyUJ","import",[136,173,175],{"class":174},"spKPg"," {",[136,177,179],{"class":178},"s9Av-"," TresCanvas ",[136,181,182],{"class":174},"}",[136,184,185],{"class":170}," from",[136,187,188],{"class":160}," '@tresjs\u002Fcore'\n",[136,190,192,194,196,199,202,205,207,210,212,214],{"class":138,"line":191},3,[136,193,171],{"class":170},[136,195,175],{"class":174},[136,197,198],{"class":178}," Environment",[136,200,201],{"class":174},",",[136,203,204],{"class":178}," MeshPortalMaterial",[136,206,201],{"class":174},[136,208,209],{"class":178}," OrbitControls ",[136,211,182],{"class":174},[136,213,185],{"class":170},[136,215,216],{"class":160}," '@tresjs\u002Fcientos'\n",[136,218,220],{"class":138,"line":219},4,[136,221,223],{"emptyLinePlaceholder":222},true,"\n",[136,225,227,230,233,235,239,242,246],{"class":138,"line":226},5,[136,228,229],{"class":170},"const",[136,231,232],{"class":178}," blend ",[136,234,157],{"class":142},[136,236,238],{"class":237},"s0faT"," ref",[136,240,241],{"class":178},"(",[136,243,245],{"class":244},"sREMW","0",[136,247,248],{"class":178},")\n",[136,250,252,255,257],{"class":138,"line":251},6,[136,253,254],{"class":142},"\u003C\u002F",[136,256,147],{"class":146},[136,258,164],{"class":142},[136,260,262],{"class":138,"line":261},7,[136,263,223],{"emptyLinePlaceholder":222},[136,265,267,269,272],{"class":138,"line":266},8,[136,268,143],{"class":142},[136,270,271],{"class":146},"template",[136,273,164],{"class":142},[136,275,277,280,283],{"class":138,"line":276},9,[136,278,279],{"class":142},"  \u003C",[136,281,282],{"class":146},"TresCanvas",[136,284,164],{"class":142},[136,286,288,291,294,297,299,302],{"class":138,"line":287},10,[136,289,290],{"class":142},"    \u003C",[136,292,293],{"class":146},"TresPerspectiveCamera",[136,295,296],{"class":150}," :position",[136,298,157],{"class":142},[136,300,301],{"class":160},"\"[0, 0, 6]\"",[136,303,304],{"class":142}," \u002F>\n",[136,306,308,310,313],{"class":138,"line":307},11,[136,309,290],{"class":142},[136,311,312],{"class":146},"OrbitControls",[136,314,304],{"class":142},[136,316,318],{"class":138,"line":317},12,[136,319,223],{"emptyLinePlaceholder":222},[136,321,323,325,328],{"class":138,"line":322},13,[136,324,290],{"class":142},[136,326,327],{"class":146},"TresMesh",[136,329,164],{"class":142},[136,331,333,336,339,342,344,347],{"class":138,"line":332},14,[136,334,335],{"class":142},"      \u003C",[136,337,338],{"class":146},"TresPlaneGeometry",[136,340,341],{"class":150}," :args",[136,343,157],{"class":142},[136,345,346],{"class":160},"\"[3, 4]\"",[136,348,304],{"class":142},[136,350,352,354,357,360,362,365],{"class":138,"line":351},15,[136,353,335],{"class":142},[136,355,356],{"class":146},"MeshPortalMaterial",[136,358,359],{"class":150}," :blend",[136,361,157],{"class":142},[136,363,364],{"class":160},"\"blend\"",[136,366,164],{"class":142},[136,368,370],{"class":138,"line":369},16,[136,371,373],{"class":372},"sMnCH","        \u003C!-- Everything in here renders INTO the portal, not the main scene -->\n",[136,375,377,380,383],{"class":138,"line":376},17,[136,378,379],{"class":142},"        \u003C",[136,381,382],{"class":146},"Suspense",[136,384,164],{"class":142},[136,386,388,391,394,397,399,402,405,407,410],{"class":138,"line":387},18,[136,389,390],{"class":142},"          \u003C",[136,392,393],{"class":146},"Environment",[136,395,396],{"class":150}," preset",[136,398,157],{"class":142},[136,400,401],{"class":160},"\"dawn\"",[136,403,404],{"class":150}," :background",[136,406,157],{"class":142},[136,408,409],{"class":160},"\"true\"",[136,411,304],{"class":142},[136,413,415,418,420],{"class":138,"line":414},19,[136,416,417],{"class":142},"        \u003C\u002F",[136,419,382],{"class":146},[136,421,164],{"class":142},[136,423,425,427,429,431,433,436],{"class":138,"line":424},20,[136,426,379],{"class":142},[136,428,327],{"class":146},[136,430,296],{"class":150},[136,432,157],{"class":142},[136,434,435],{"class":160},"\"[0, 0, -1]\"",[136,437,164],{"class":142},[136,439,441,443,446,448,450,453],{"class":138,"line":440},21,[136,442,390],{"class":142},[136,444,445],{"class":146},"TresTorusKnotGeometry",[136,447,341],{"class":150},[136,449,157],{"class":142},[136,451,452],{"class":160},"\"[0.6, 0.25, 128, 32]\"",[136,454,304],{"class":142},[136,456,458,460,463,466,468,471],{"class":138,"line":457},22,[136,459,390],{"class":142},[136,461,462],{"class":146},"TresMeshStandardMaterial",[136,464,465],{"class":150}," color",[136,467,157],{"class":142},[136,469,470],{"class":160},"\"#fbb03b\"",[136,472,304],{"class":142},[136,474,476,478,480],{"class":138,"line":475},23,[136,477,417],{"class":142},[136,479,327],{"class":146},[136,481,164],{"class":142},[136,483,485,488,490],{"class":138,"line":484},24,[136,486,487],{"class":142},"      \u003C\u002F",[136,489,356],{"class":146},[136,491,164],{"class":142},[136,493,495,498,500],{"class":138,"line":494},25,[136,496,497],{"class":142},"    \u003C\u002F",[136,499,327],{"class":146},[136,501,164],{"class":142},[136,503,505,508,510],{"class":138,"line":504},26,[136,506,507],{"class":142},"  \u003C\u002F",[136,509,282],{"class":146},[136,511,164],{"class":142},[136,513,515,517,519],{"class":138,"line":514},27,[136,516,254],{"class":142},[136,518,271],{"class":146},[136,520,164],{"class":142},[11,522,523],{},"A few details that make it feel like Vue rather than a shader trick:",[57,525,526],{},[60,527,528,539,555,577],{},[63,529,530,533,534,538],{},[15,531,532],{},"World-space parallax."," The portal scene is rendered to a frame buffer every frame with the active camera, so orbiting around the mesh shows different angles ",[535,536,537],"em",{},"through"," the surface. It is a window, not a sticker.",[63,540,541,544,545,547,548,31,551,554],{},[15,542,543],{},"Per-portal environments."," ",[20,546,101],{}," overrides the injected scene context for its children, so ",[20,549,550],{},"\u003CEnvironment>",[20,552,553],{},"attach=\"background\""," target the portal scene, not the world. Every portal gets its own sky.",[63,556,557,562,563,565,566,569,570,572,573,576],{},[15,558,559],{},[20,560,561],{},"blend"," cross-fades between the world (",[20,564,245],{},") and the portal (",[20,567,568],{},"1","). Animate it to ",[20,571,568],{}," and you are ",[535,574,575],{},"inside"," the portal, rendered fullscreen. That is how the \"enter the portal\" moment in the demo works.",[63,578,579,27,584,31,589,594],{},[15,580,581],{},[20,582,583],{},"resolution",[15,585,586],{},[20,587,588],{},"worldUnits",[15,590,591],{},[20,592,593],{},"renderPriority"," are there when you need to tune it.",[11,596,597,598,601],{},"And if you only need the structural half, ",[20,599,600],{},"\u003CTresPortal :to=\"scene\">"," on its own is handy for render targets, minimaps or anything that wants a mesh to live in a scene other than the one it was declared in.",[603,604,605],"prose-note",{},[11,606,607,608,611,612,615,616,618,619,624,625,111],{},"This is an ",[15,609,610],{},"MVP",". ",[20,613,614],{},"blur"," (edge fade) and pointer events forwarded into the portal scene are not implemented yet, and WebGPU is not supported for now. Also, a portal renders its scene every frame, so a mesh using ",[20,617,101],{}," opts out of ",[49,620,623],{"href":621,"rel":622},"https:\u002F\u002Fdocs.tresjs.org\u002Fapi\u002Fadvanced\u002Fperformance#mode-on-demand",[53],"on-demand rendering"," while mounted. Full details in the ",[49,626,628],{"href":95,"rel":627},[53],"docs",[37,630,632,633,636],{"id":631},"meet-the-tres-cli","Meet the ",[20,634,635],{},"tres"," CLI",[11,638,639],{},[640,641],"img",{"alt":642,"src":643},"The tres CLI","\u002Fblog\u002Fwhats-new-summer-2026\u002Ftres-cli.gif",[11,645,646,647,654,655,657],{},"TresJS has a command line now. ",[49,648,651],{"href":649,"rel":650},"https:\u002F\u002Fdocs.tresjs.org\u002Fcli",[53],[20,652,653],{},"@tresjs\u002Fcli"," exposes a single ",[20,656,635],{}," binary, and its first command is the one we have wanted for years.",[659,660,662,665],"h3",{"id":661},"tres-gltf-models-become-components",[20,663,664],{},"tres gltf",": models become components",[11,667,668,671,672,82,675,678,679,684,685,690],{},[20,669,670],{},"tres gltf \u003Cinput>"," turns a ",[20,673,674],{},".glb",[20,676,677],{},".gltf"," into a typed Vue SFC (",[49,680,683],{"href":681,"rel":682},"https:\u002F\u002Fgithub.com\u002FTresjs\u002Ftres\u002Fpull\u002F1464",[53],"#1464","). Think ",[49,686,689],{"href":687,"rel":688},"https:\u002F\u002Fgithub.com\u002Fpmndrs\u002Fgltfjsx",[53],"gltfjsx",", but for Vue and with a twist.",[127,692,696],{"className":693,"code":694,"language":695,"meta":132,"style":132},"language-bash shiki shiki-themes catppuccin-latte catppuccin-latte catppuccin-frappe","tres gltf public\u002Fmodels\u002Frobot.glb\n# ✔ src\u002Fmodels\u002FRobot.gen.vue\n#   3 slots: Head, Body, Base\n","bash",[20,697,698,708,713],{"__ignoreMap":132},[136,699,700,702,705],{"class":138,"line":139},[136,701,635],{"class":237},[136,703,704],{"class":160}," gltf",[136,706,707],{"class":160}," public\u002Fmodels\u002Frobot.glb\n",[136,709,710],{"class":138,"line":167},[136,711,712],{"class":372},"# ✔ src\u002Fmodels\u002FRobot.gen.vue\n",[136,714,715],{"class":138,"line":191},[136,716,717],{"class":372},"#   3 slots: Head, Body, Base\n",[11,719,720,721,724,725,728],{},"The twist is ",[15,722,723],{},"slots over editing generated code",". Every renderable node becomes a ",[20,726,727],{},"\u003Cslot>"," whose fallback is the generated markup. You override one node from your own file, and when the artist re-exports and you regenerate, the override survives because it never lived in the generated file:",[127,730,732],{"className":129,"code":731,"language":131,"meta":132,"style":132},"\u003CRobot>\n  \u003Ctemplate #Head=\"{ node }\">\n    \u003CTresMesh :geometry=\"node.geometry\" :material=\"hologram\" @click=\"explode\" \u002F>\n  \u003C\u002Ftemplate>\n\u003C\u002FRobot>\n",[20,733,734,743,748,753,758],{"__ignoreMap":132},[136,735,736,738,741],{"class":138,"line":139},[136,737,143],{"class":142},[136,739,740],{"class":146},"Robot",[136,742,164],{"class":142},[136,744,745],{"class":138,"line":167},[136,746,747],{"class":178},"  \u003Ctemplate #Head=\"{ node }\">\n",[136,749,750],{"class":138,"line":191},[136,751,752],{"class":178},"    \u003CTresMesh :geometry=\"node.geometry\" :material=\"hologram\" @click=\"explode\" \u002F>\n",[136,754,755],{"class":138,"line":219},[136,756,757],{"class":178},"  \u003C\u002Ftemplate>\n",[136,759,760,762,764],{"class":138,"line":226},[136,761,254],{"class":142},[136,763,740],{"class":146},[136,765,164],{"class":142},[11,767,768,769,772,773,776,777,780,781,784],{},"The generated component also declares the shape of the model it came from. ",[20,770,771],{},"node"," above is a ",[20,774,775],{},"Mesh",", not an ",[20,778,779],{},"any",". A mesh the artist renamed becomes a type error at the override that used it. Animated models get their clip names as a union, so ",[20,782,783],{},"actions.Idle"," is checked and a typo fails at compile time:",[127,786,788],{"className":129,"code":787,"language":131,"meta":132,"style":132},"\u003CRobot @ready=\"({ actions }) => actions.Idle?.play()\" \u002F>\n",[20,789,790],{"__ignoreMap":132},[136,791,792,794,796,799,802,804,807,810,814,817,820,822,824,827,830,833,836,838],{"class":138,"line":139},[136,793,143],{"class":142},[136,795,740],{"class":146},[136,797,798],{"class":174}," @",[136,800,801],{"class":150},"ready",[136,803,157],{"class":142},[136,805,806],{"class":160},"\"",[136,808,809],{"class":174},"({",[136,811,813],{"class":812},"sQnVB"," actions",[136,815,816],{"class":174}," })",[136,818,819],{"class":142}," =>",[136,821,813],{"class":178},[136,823,111],{"class":142},[136,825,826],{"class":178},"Idle",[136,828,829],{"class":142},"?.",[136,831,832],{"class":237},"play",[136,834,835],{"class":178},"()",[136,837,806],{"class":160},[136,839,304],{"class":178},[11,841,842,843,846],{},"Mixamo, KayKit and Quaternius ship clips in separate files? Pass them with ",[20,844,845],{},"-a"," and they get merged into the model, with track targets checked against the model's node names.",[659,848,850,853],{"id":849},"transform-the-asset-pipeline",[20,851,852],{},"--transform",": the asset pipeline",[11,855,856,859,860,865,866,871,872,875],{},[20,857,858],{},"tres gltf --transform"," runs the model through ",[49,861,864],{"href":862,"rel":863},"https:\u002F\u002Fgithub.com\u002Fdonmccurdy\u002FglTF-Transform",[53],"glTF-Transform"," before generating (",[49,867,870],{"href":868,"rel":869},"https:\u002F\u002Fgithub.com\u002FTresjs\u002Ftres\u002Fpull\u002F1467",[53],"#1467","): dedup, weld, texture compression to WebP (or AVIF, JPEG, PNG), Draco, optional ",[20,873,874],{},"--simplify"," with meshoptimizer. The generated component targets the optimized file.",[659,877,879,882],{"id":878},"instance-repeated-meshes-one-draw-call",[20,880,881],{},"--instance",": repeated meshes, one draw call",[11,884,885,888,889,892,893,898,899,902,903,906],{},[20,886,887],{},"tres gltf --instance"," collapses meshes that share a geometry and material into a single ",[20,890,891],{},"InstancedMesh"," (",[49,894,897],{"href":895,"rel":896},"https:\u002F\u002Fgithub.com\u002FTresjs\u002Ftres\u002Fpull\u002F1472",[53],"#1472","). Fifty screws cost the draw call of one. The output splits into a provider that owns the load and the batches, and a model component that renders ",[20,900,901],{},"\u003CInstance>"," against them. ",[20,904,905],{},"--instanceall"," batches every eligible mesh, which pays off when the whole model is on screen many times.",[659,908,910,913],{"id":909},"physics-rapier-colliders-from-blender",[20,911,912],{},"--physics rapier",": colliders from Blender",[11,915,916,917,920,921,924,925,892,930,935],{},"This is the one I am most excited about. ",[20,918,919],{},"tres gltf --physics rapier"," reads collision off ",[15,922,923],{},"node names",", using ",[49,926,929],{"href":927,"rel":928},"https:\u002F\u002Fdocs.godotengine.org\u002Fen\u002Fstable\u002Ftutorials\u002Fassets_pipeline\u002Fimporting_3d_scenes\u002Fnode_type_customization.html",[53],"Godot's suffix vocabulary",[49,931,934],{"href":932,"rel":933},"https:\u002F\u002Fgithub.com\u002FTresjs\u002Ftres\u002Fpull\u002F1474",[53],"#1474","). An artist authors physics in Blender, and nobody hand-edits the generated component:",[127,937,939],{"className":693,"code":938,"language":695,"meta":132,"style":132},"tres gltf public\u002Fmodels\u002Flevel.glb --physics rapier\n",[20,940,941],{"__ignoreMap":132},[136,942,943,945,947,950,953],{"class":138,"line":139},[136,944,635],{"class":237},[136,946,704],{"class":160},[136,948,949],{"class":160}," public\u002Fmodels\u002Flevel.glb",[136,951,952],{"class":160}," --physics",[136,954,955],{"class":160}," rapier\n",[127,957,959],{"className":129,"code":958,"language":131,"meta":132,"style":132},"\u003CRigidBody type=\"fixed\" collider=\"convexHull\">\n  \u003CTresMesh :geometry=\"nodes['Floor-convcol'].geometry\" :material=\"materials.prototype\" \u002F>\n\u003C\u002FRigidBody>\n\n\u003CRigidBody type=\"fixed\" collider=\"convexHull\">\n  \u003CTresMesh :geometry=\"nodes['Stairs_Collision-convcolonly'].geometry\" :visible=\"false\" \u002F>\n\u003C\u002FRigidBody>\n",[20,960,961,986,991,999,1003,1023,1028],{"__ignoreMap":132},[136,962,963,965,968,971,973,976,979,981,984],{"class":138,"line":139},[136,964,143],{"class":142},[136,966,967],{"class":146},"RigidBody",[136,969,970],{"class":150}," type",[136,972,157],{"class":142},[136,974,975],{"class":160},"\"fixed\"",[136,977,978],{"class":150}," collider",[136,980,157],{"class":142},[136,982,983],{"class":160},"\"convexHull\"",[136,985,164],{"class":142},[136,987,988],{"class":138,"line":167},[136,989,990],{"class":178},"  \u003CTresMesh :geometry=\"nodes['Floor-convcol'].geometry\" :material=\"materials.prototype\" \u002F>\n",[136,992,993,995,997],{"class":138,"line":191},[136,994,254],{"class":142},[136,996,967],{"class":146},[136,998,164],{"class":142},[136,1000,1001],{"class":138,"line":219},[136,1002,223],{"emptyLinePlaceholder":222},[136,1004,1005,1007,1009,1011,1013,1015,1017,1019,1021],{"class":138,"line":226},[136,1006,143],{"class":142},[136,1008,967],{"class":146},[136,1010,970],{"class":150},[136,1012,157],{"class":142},[136,1014,975],{"class":160},[136,1016,978],{"class":150},[136,1018,157],{"class":142},[136,1020,983],{"class":160},[136,1022,164],{"class":142},[136,1024,1025],{"class":138,"line":251},[136,1026,1027],{"class":178},"  \u003CTresMesh :geometry=\"nodes['Stairs_Collision-convcolonly'].geometry\" :visible=\"false\" \u002F>\n",[136,1029,1030,1032,1034],{"class":138,"line":261},[136,1031,254],{"class":142},[136,1033,967],{"class":146},[136,1035,164],{"class":142},[57,1037,1038],{},[60,1039,1040,1050,1059,1065,1071],{},[63,1041,1042,1045,1046,1049],{},[20,1043,1044],{},"-col"," \u002F ",[20,1047,1048],{},"-colonly",": fixed trimesh body, drawn or hidden",[63,1051,1052,1045,1055,1058],{},[20,1053,1054],{},"-convcol",[20,1056,1057],{},"-convcolonly",": fixed convex hull, drawn or hidden",[63,1060,1061,1064],{},[20,1062,1063],{},"-rigid",": dynamic convex hull",[63,1066,1067,1070],{},[20,1068,1069],{},"-rb-\u003Ctype>",": pick the body type yourself",[63,1072,1073,1076],{},[20,1074,1075],{},"-sensor",": a hidden trigger volume",[11,1078,1079,1080,1082,1083,1086,1087,111],{},"Nothing is sized at generate time. ",[20,1081,967],{}," derives colliders from the mesh geometry at load, so a re-export that reshapes a mesh reshapes its collider too. A suffix that ",[535,1084,1085],{},"nearly"," parses is reported instead of silently dropped, and it combines with ",[20,1088,881],{},[11,1090,1091,1092,111],{},"Everything is documented at ",[49,1093,1096],{"href":1094,"rel":1095},"https:\u002F\u002Fdocs.tresjs.org\u002Fcli\u002Fgltf",[53],"docs.tresjs.org\u002Fcli",[37,1098,1100],{"id":1099},"instances-and-merged","Instances and Merged",[11,1102,1103,1104,1109],{},"Instancing is not only for the CLI. Cientos gained two abstractions that make it declarative (",[49,1105,1108],{"href":1106,"rel":1107},"https:\u002F\u002Fgithub.com\u002FTresjs\u002Ftres\u002Fpull\u002F1468",[53],"#1468",").",[11,1111,1112,1121,1122,1124,1125,1132,1133,1136,1137,1140,1141,1144,1145,1148,1149,1152],{},[49,1113,1116],{"href":1114,"rel":1115},"https:\u002F\u002Fcientos.tresjs.org\u002Fapi\u002Fabstractions\u002Finstances",[53],[15,1117,1118],{},[20,1119,1120],{},"\u003CInstances>"," owns a single ",[20,1123,891],{}," for a shared geometry and material. Each ",[49,1126,1128],{"href":1114,"rel":1127},[53],[15,1129,1130],{},[20,1131,901],{}," inside is a normal node in the Vue tree: give it a ",[20,1134,1135],{},"position",", nest it in a group, toggle it with ",[20,1138,1139],{},"v-if",", listen to ",[20,1142,1143],{},"@click"," on one of them. A ",[20,1146,1147],{},"v-for"," of a thousand costs ",[15,1150,1151],{},"one"," draw call.",[127,1154,1156],{"className":129,"code":1155,"language":131,"meta":132,"style":132},"\u003CInstances :geometry=\"geometry\" :material=\"material\">\n  \u003CInstance\n    v-for=\"(position, i) in cubes\"\n    :key=\"i\"\n    :position=\"position\"\n    :color=\"i === selected ? '#f97316' : '#38bdf8'\"\n    @click=\"selected = i\"\n  \u002F>\n\u003C\u002FInstances>\n",[20,1157,1158,1194,1199,1204,1209,1214,1219,1224,1229],{"__ignoreMap":132},[136,1159,1160,1162,1165,1168,1171,1173,1175,1177,1179,1181,1184,1186,1188,1190,1192],{"class":138,"line":139},[136,1161,143],{"class":142},[136,1163,1164],{"class":146},"Instances",[136,1166,1167],{"class":174}," :",[136,1169,1170],{"class":150},"geometry",[136,1172,157],{"class":142},[136,1174,806],{"class":160},[136,1176,1170],{"class":178},[136,1178,806],{"class":160},[136,1180,1167],{"class":174},[136,1182,1183],{"class":150},"material",[136,1185,157],{"class":142},[136,1187,806],{"class":160},[136,1189,1183],{"class":178},[136,1191,806],{"class":160},[136,1193,164],{"class":142},[136,1195,1196],{"class":138,"line":167},[136,1197,1198],{"class":178},"  \u003CInstance\n",[136,1200,1201],{"class":138,"line":191},[136,1202,1203],{"class":178},"    v-for=\"(position, i) in cubes\"\n",[136,1205,1206],{"class":138,"line":219},[136,1207,1208],{"class":178},"    :key=\"i\"\n",[136,1210,1211],{"class":138,"line":226},[136,1212,1213],{"class":178},"    :position=\"position\"\n",[136,1215,1216],{"class":138,"line":251},[136,1217,1218],{"class":178},"    :color=\"i === selected ? '#f97316' : '#38bdf8'\"\n",[136,1220,1221],{"class":138,"line":261},[136,1222,1223],{"class":178},"    @click=\"selected = i\"\n",[136,1225,1226],{"class":138,"line":266},[136,1227,1228],{"class":178},"  \u002F>\n",[136,1230,1231,1233,1235],{"class":138,"line":276},[136,1232,254],{"class":142},[136,1234,1164],{"class":146},[136,1236,164],{"class":142},[11,1238,1239,1248,1249,1252,1253,1256,1257,1260,1261,1264],{},[49,1240,1243],{"href":1241,"rel":1242},"https:\u002F\u002Fcientos.tresjs.org\u002Fapi\u002Fabstractions\u002Fmerged",[53],[15,1244,1245],{},[20,1246,1247],{},"\u003CMerged>"," takes a ",[20,1250,1251],{},"{ name: mesh }"," map, typically the ",[20,1254,1255],{},"nodes"," off ",[20,1258,1259],{},"useGLTF",", and builds one batch per entry. Any descendant, at any depth and in any component, joins one by name with ",[20,1262,1263],{},"\u003CInstance batch=\"Body\" \u002F>",". A robot made of two meshes drawn 49 times is two draw calls, not 98.",[11,1266,1267,1268,1271],{},"Pointer events resolve per instance, the color buffer is only allocated when an instance actually asks for a color, and ",[20,1269,1270],{},"limit"," is a hint rather than a hard cap: exceed it and the batch reallocates with a warning telling you the value to set.",[37,1273,1275],{"id":1274},"more-goodies-in-cientos","More goodies in Cientos",[659,1277,1279],{"id":1278},"refractor",[20,1280,1281],{},"Refractor",[11,1283,1284,1285,611,1288,1295,1296,1299,1300,1305,1306,1309,1310,1312],{},"The sibling of ",[20,1286,1287],{},"Reflector",[49,1289,1292],{"href":1290,"rel":1291},"https:\u002F\u002Fcientos.tresjs.org\u002Fapi\u002Fobjects\u002Frefractor",[53],[20,1293,1294],{},"\u003CRefractor>"," renders what is ",[535,1297,1298],{},"behind"," it with a refractive distortion, for glass panels, water surfaces and portals of the less magical kind (",[49,1301,1304],{"href":1302,"rel":1303},"https:\u002F\u002Fgithub.com\u002FTresjs\u002Ftres\u002Fpull\u002F1422",[53],"#1422","). It takes a custom ",[20,1307,1308],{},"shader"," too, and the docs demo ships an animated ripple effect to copy from. The ",[20,1311,1287],{}," demos got a refresh in the same PR.",[659,1314,1316],{"id":1315},"roundedplane",[20,1317,1318],{},"RoundedPlane",[11,1320,1321,1322,1329,1330,1335],{},"A plane with rounded corners, ",[49,1323,1326],{"href":1324,"rel":1325},"https:\u002F\u002Fcientos.tresjs.org\u002Fapi\u002Fshapes\u002Frounded-plane",[53],[20,1327,1328],{},"\u003CRoundedPlane>",", with the geometry vendored from ",[49,1331,1334],{"href":1332,"rel":1333},"https:\u002F\u002Fgithub.com\u002Fpmndrs\u002Fmaath",[53],"pmndrs\u002Fmaath"," so it adds no dependency. Cards, UI panels and, yes, portal frames.",[127,1337,1339],{"className":129,"code":1338,"language":131,"meta":132,"style":132},"\u003CRoundedPlane :args=\"[1.5, 1, 0.2, 16]\" color=\"orange\" \u002F>\n",[20,1340,1341],{"__ignoreMap":132},[136,1342,1343,1345,1347,1349,1352,1354,1356,1359,1362,1364,1367,1369,1372,1374,1377,1380,1382,1384,1386,1389],{"class":138,"line":139},[136,1344,143],{"class":142},[136,1346,1318],{"class":146},[136,1348,1167],{"class":174},[136,1350,1351],{"class":150},"args",[136,1353,157],{"class":142},[136,1355,806],{"class":160},[136,1357,1358],{"class":178},"[",[136,1360,1361],{"class":244},"1.5",[136,1363,201],{"class":174},[136,1365,1366],{"class":244}," 1",[136,1368,201],{"class":174},[136,1370,1371],{"class":244}," 0.2",[136,1373,201],{"class":174},[136,1375,1376],{"class":244}," 16",[136,1378,1379],{"class":178},"]",[136,1381,806],{"class":160},[136,1383,465],{"class":150},[136,1385,157],{"class":142},[136,1387,1388],{"class":160},"\"orange\"",[136,1390,304],{"class":142},[659,1392,1394,1397,1398,31,1401],{"id":1393},"keyboardcontrols-gets-q-and-e",[20,1395,1396],{},"KeyboardControls"," gets ",[20,1399,1400],{},"Q",[20,1402,1403],{},"E",[11,1405,1406,1407,1409,1410,1412,1413,1418,1419,1424],{},"Fly down with ",[20,1408,1400],{},", fly up with ",[20,1411,1403],{},", the way Unreal Engine and most world editors do it (",[49,1414,1417],{"href":1415,"rel":1416},"https:\u002F\u002Fgithub.com\u002FTresjs\u002Ftres\u002Fpull\u002F1449",[53],"#1449","). Thanks ",[49,1420,1423],{"href":1421,"rel":1422},"https:\u002F\u002Fgithub.com\u002FJaimeTorrealba",[53],"Jaime","!",[659,1426,1428,1431],{"id":1427},"stage-shadows-land-where-they-should",[20,1429,1430],{},"Stage"," shadows land where they should",[11,1433,1434,1435,1440,1441,1448,1449,1452,1453,55],{},"A first-time contributor, ",[49,1436,1439],{"href":1437,"rel":1438},"https:\u002F\u002Fgithub.com\u002FSandros94",[53],"Sandros94",", noticed that ",[49,1442,1445],{"href":1443,"rel":1444},"https:\u002F\u002Fcientos.tresjs.org\u002Fapi\u002Fstaging\u002Fstage",[53],[20,1446,1447],{},"\u003CStage>"," was drawing its ground shadow at the ",[20,1450,1451],{},"\u003CAlign>"," origin instead of under the model. That was the loose thread. Pulling it fixed a whole list of things (",[49,1454,1457],{"href":1455,"rel":1456},"https:\u002F\u002Fgithub.com\u002FTresjs\u002Ftres\u002Fpull\u002F1496",[53],"#1496",[57,1459,1460],{},[60,1461,1462,1479,1510,1520,1526,1542],{},[63,1463,1464,1465,27,1468,31,1471,1474,1475,1478],{},"The shadow now follows the aligned content's bottom, ",[20,1466,1467],{},"top",[20,1469,1470],{},"bottom",[20,1472,1473],{},"disableY"," included, and ",[20,1476,1477],{},"offset"," is the full distance between content and shadow plane instead of half of it",[63,1480,1481,1482,1485,1486,27,1489,27,1492,31,1495,1498,1499,1502,1503,1506,1507],{},"The ",[20,1483,1484],{},"shadows"," object is no longer spread wholesale into ",[20,1487,1488],{},"\u003CRandomizedLights>",[20,1490,1491],{},"\u003CBounds>",[20,1493,1494],{},"\u003CContactShadows>",[20,1496,1497],{},"\u003CAccumulativeShadows>",". Before, ",[20,1500,1501],{},"size"," was overriding the lights' frustum and ",[20,1504,1505],{},"type"," was even overwriting the three.js object's ",[20,1508,1509],{},".type",[63,1511,1512,1515,1516,1519],{},[20,1513,1514],{},"bias"," defaults to ",[20,1517,1518],{},"-0.0001"," as documented, and is inverted for accumulative lights like drei does",[63,1521,1522,1525],{},[20,1523,1524],{},"shadows: null"," disables shadows instead of crashing",[63,1527,1528,1531,1532,27,1534,1537,1538,1541],{},[20,1529,1530],{},"MeshReflectionMaterial"," had the same leak: ",[20,1533,583],{},[20,1535,1536],{},"blurSize"," and friends ended up on the material. They are now stripped, the way ",[20,1539,1540],{},"MeshTransmissionMaterial"," already does",[63,1543,1544,1546],{},[20,1545,1451],{}," guards against empty bounds, which used to produce infinite dimensions",[11,1548,1549,1550,1555,1556,1559,1560,1563,1564,27,1566,27,1569,31,1572,1575,1576,1579,1580,1583,1584,1586,1587,111],{},"A follow-up (",[49,1551,1554],{"href":1552,"rel":1553},"https:\u002F\u002Fgithub.com\u002FTresjs\u002Ftres\u002Fpull\u002F1497",[53],"#1497",") went after the GPU. Changing ",[20,1557,1558],{},"count"," on ",[20,1561,1562],{},"RandomizedLights"," rebuilt every light with three.js defaults, so ",[20,1565,1501],{},[20,1567,1568],{},"mapSize",[20,1570,1571],{},"near",[20,1573,1574],{},"far"," were silently lost, and the old lights were never disposed. ",[20,1577,1578],{},"AccumulativeShadows"," never released its ",[20,1581,1582],{},"ProgressiveLightMap"," render targets either. Both leaks are closed now: texture count stays flat across ",[20,1585,1558],{}," changes and mount\u002Funmount cycles. Both fixes shipped in ",[20,1588,1589],{},"@tresjs\u002Fcientos@5.9.1",[659,1591,1593],{"id":1592},"fixes","Fixes",[57,1595,1596],{},[60,1597,1598,1604,1619],{},[63,1599,1600,1603],{},[20,1601,1602],{},"useProgress"," now resets loading progress correctly based on already loaded items",[63,1605,1606,1608,1609,1612,1613,1618],{},[20,1607,1578],{}," strips ",[20,1610,1611],{},"scene.environment"," during the bake, so your HDR no longer leaks into the shadow pass (",[49,1614,1617],{"href":1615,"rel":1616},"https:\u002F\u002Fgithub.com\u002FTresjs\u002Ftres\u002Fpull\u002F1446",[53],"#1446",")",[63,1620,1621,31,1624,1626,1627,1618],{},[20,1622,1623],{},"randomness",[20,1625,1558],{}," are reactive where they were not (",[49,1628,1631],{"href":1629,"rel":1630},"https:\u002F\u002Fgithub.com\u002FTresjs\u002Ftres\u002Fpull\u002F1448",[53],"#1448",[37,1633,1635],{"id":1634},"core-webgpu-awareness-and-a-few-fixes","Core: WebGPU awareness and a few fixes",[11,1637,1638,1641,1642,1647,1648,1651,1652,1655,1656,1045,1659,1662],{},[20,1639,1640],{},"@tresjs\u002Fcore@5.9.0"," exposes the renderer type as public API (",[49,1643,1646],{"href":1644,"rel":1645},"https:\u002F\u002Fgithub.com\u002FTresjs\u002Ftres\u002Fpull\u002F1440",[53],"#1440","). ",[20,1649,1650],{},"useTres()"," now returns a reactive ",[20,1653,1654],{},"isWebGPU"," flag, and ",[20,1657,1658],{},"isWebGPURenderer()",[20,1660,1661],{},"isWebGLRenderer()"," type guards are exported, so a component can branch on the renderer instead of guessing:",[127,1664,1668],{"className":1665,"code":1666,"language":1667,"meta":132,"style":132},"language-ts shiki shiki-themes catppuccin-latte catppuccin-latte catppuccin-frappe","const { isWebGPU } = useTres()\n\nconst material = computed(() => isWebGPU.value ? nodeMaterial : glslMaterial)\n","ts",[20,1669,1670,1690,1694],{"__ignoreMap":132},[136,1671,1672,1674,1676,1679,1681,1684,1687],{"class":138,"line":139},[136,1673,229],{"class":170},[136,1675,175],{"class":174},[136,1677,1678],{"class":178}," isWebGPU ",[136,1680,182],{"class":174},[136,1682,1683],{"class":142}," =",[136,1685,1686],{"class":237}," useTres",[136,1688,1689],{"class":178},"()\n",[136,1691,1692],{"class":138,"line":167},[136,1693,223],{"emptyLinePlaceholder":222},[136,1695,1696,1698,1701,1703,1706,1708,1710,1712,1715,1717,1720,1723,1726,1729],{"class":138,"line":191},[136,1697,229],{"class":170},[136,1699,1700],{"class":178}," material ",[136,1702,157],{"class":142},[136,1704,1705],{"class":237}," computed",[136,1707,241],{"class":178},[136,1709,835],{"class":174},[136,1711,819],{"class":142},[136,1713,1714],{"class":178}," isWebGPU",[136,1716,111],{"class":142},[136,1718,1719],{"class":178},"value ",[136,1721,1722],{"class":142},"?",[136,1724,1725],{"class":178}," nodeMaterial ",[136,1727,1728],{"class":142},":",[136,1730,1731],{"class":178}," glslMaterial)\n",[11,1733,1734],{},"Fixes worth knowing about:",[57,1736,1737],{},[60,1738,1739,1762,1780],{},[63,1740,1741,892,1749,1754,1755,1758,1759,1761],{},[15,1742,1743,1515,1746],{},[20,1744,1745],{},"shadowMapType",[20,1747,1748],{},"PCFShadowMap",[49,1750,1753],{"href":1751,"rel":1752},"https:\u002F\u002Fgithub.com\u002FTresjs\u002Ftres\u002Fpull\u002F1483",[53],"#1483","). Three deprecated ",[20,1756,1757],{},"PCFSoftShadowMap"," on WebGL and was silently replacing it anyway, logging a warning on every first render. Output is identical, the console is quieter. ",[20,1760,1757],{}," remains valid on WebGPU.",[63,1763,1764,892,1770,1775,1776,1779],{},[15,1765,1766,1769],{},[20,1767,1768],{},"customRendererOptions"," actually applies",[49,1771,1774],{"href":1772,"rel":1773},"https:\u002F\u002Fgithub.com\u002FTresjs\u002Ftres\u002Fpull\u002F1479",[53],"#1479","). The default was keyed to a prop that did not exist, so ",[20,1777,1778],{},":custom-renderer-options"," was ignored at runtime. Thanks Jungzl!",[63,1781,1782,892,1788,1793,1794,1799],{},[15,1783,1784,1787],{},[20,1785,1786],{},"useCamera"," uses a shallow ref",[49,1789,1792],{"href":1790,"rel":1791},"https:\u002F\u002Fgithub.com\u002FTresjs\u002Ftres\u002Fpull\u002F1453",[53],"#1453","), courtesy of ",[49,1795,1798],{"href":1796,"rel":1797},"https:\u002F\u002Fgithub.com\u002Fposva",[53],"Eduardo San Martin Morote"," of Vue Router and Pinia fame. Fewer deep-reactivity surprises, better performance.",[37,1801,1803],{"id":1802},"tres-leches-search-copy-for-ai-and-docs","Tres Leches: search, copy for AI, and docs",[11,1805,1806,1809,1810,1815,1816,55],{},[20,1807,1808],{},"@tresjs\u002Fleches@1.3.0"," adds two ",[49,1811,1814],{"href":1812,"rel":1813},"https:\u002F\u002Fleches.tresjs.org\u002Fguide\u002Fadvanced",[53],"panel actions"," to every expanded panel (",[49,1817,1820],{"href":1818,"rel":1819},"https:\u002F\u002Fgithub.com\u002FTresjs\u002Ftres\u002Fpull\u002F1506",[53],"#1506",[57,1822,1823],{},[60,1824,1825,1831],{},[63,1826,1827,1830],{},[15,1828,1829],{},"Search."," Filter controls by name. Folders keep their structure and their open state while you type, so a panel with forty controls stays usable.",[63,1832,1833,1836],{},[15,1834,1835],{},"Copy as JSON."," Copy the current values with stable control keys, and without display-only controls. Tune a scene by hand, then paste the values into your code or into your AI assistant of choice.",[11,1838,1839,1840,1843,1844,1847],{},"Try it on the noise shader from the new docs hero. Move the sliders, hit ",[15,1841,1842],{},"Randomize",", then search for ",[20,1845,1846],{},"warp"," or copy the values:",[1849,1850],"blog-embed-scene-leches",{},[11,1852,1853,1854,892,1859,1864],{},"Tres Leches also has its own documentation site now, at ",[49,1855,1858],{"href":1856,"rel":1857},"https:\u002F\u002Fleches.tresjs.org\u002F",[53],"leches.tresjs.org",[49,1860,1863],{"href":1861,"rel":1862},"https:\u002F\u002Fgithub.com\u002FTresjs\u002Ftres\u002Fpull\u002F1198",[53],"#1198","), with installation, controls, reactive state, folders, multiple panels and the full API. The same PR fixes dark mode.",[603,1866,1867],{},[11,1868,1869,1872,1873,1878,1879,1882,1883,1886,1887,1890,1891,111],{},[20,1870,1871],{},"@tresjs\u002Fleches@1.3.1"," changes how folder names become key prefixes (",[49,1874,1877],{"href":1875,"rel":1876},"https:\u002F\u002Fgithub.com\u002FTresjs\u002Ftres\u002Fpull\u002F1509",[53],"#1509","). Before, only some emoji were stripped, so ",[20,1880,1881],{},"useControls('⛰ Terrain', { height })"," gave you ",[20,1884,1885],{},"⛰TerrainHeight",", a key you could not destructure. Now every emoji and non-ASCII symbol is stripped, and accented and non-Latin letters stay. If you used bracket access such as ",[20,1888,1889],{},"controls['⛰TerrainHeight']",", change it to ",[20,1892,1893],{},"TerrainHeight",[37,1895,1897],{"id":1896},"everything-in-sync","Everything in sync",[11,1899,1900],{},"The whole family moved together on September 14, September 25 and again on September 29. These are the latest:",[57,1902,1903],{},[60,1904,1905,1911,1917,1923,1930,1937,1943],{},[63,1906,1907],{},[15,1908,1909],{},[20,1910,26],{},[63,1912,1913],{},[15,1914,1915],{},[20,1916,30],{},[63,1918,1919],{},[15,1920,1921],{},[20,1922,34],{},[63,1924,1925],{},[15,1926,1927],{},[20,1928,1929],{},"@tresjs\u002Fpost-processing@3.9.1",[63,1931,1932],{},[15,1933,1934],{},[20,1935,1936],{},"@tresjs\u002Fnuxt@5.7.2",[63,1938,1939],{},[15,1940,1941],{},[20,1942,1871],{},[63,1944,1945],{},[15,1946,1947],{},[20,1948,1949],{},"@tresjs\u002Fcli@0.1.1",[127,1951,1953],{"className":693,"code":1952,"language":695,"meta":132,"style":132},"pnpm up @tresjs\u002Fcore @tresjs\u002Fcientos @tresjs\u002Frapier @tresjs\u002Fpost-processing @tresjs\u002Fnuxt @tresjs\u002Fleches\n",[20,1954,1955],{"__ignoreMap":132},[136,1956,1957,1960,1963,1966,1969,1972,1975,1978],{"class":138,"line":139},[136,1958,1959],{"class":237},"pnpm",[136,1961,1962],{"class":160}," up",[136,1964,1965],{"class":160}," @tresjs\u002Fcore",[136,1967,1968],{"class":160}," @tresjs\u002Fcientos",[136,1970,1971],{"class":160}," @tresjs\u002Frapier",[136,1973,1974],{"class":160}," @tresjs\u002Fpost-processing",[136,1976,1977],{"class":160}," @tresjs\u002Fnuxt",[136,1979,1980],{"class":160}," @tresjs\u002Fleches\n",[11,1982,1983,1984,1986,1987,1990,1991,1996,1997,2000,2001,892,2004,2009,2010,2013,2014,111],{},"The September 25 round carries the ",[20,1985,1430],{}," and shadow fixes above, restores math prop types with ",[20,1988,1989],{},"@types\u002Fthree"," 0.186 (",[49,1992,1995],{"href":1993,"rel":1994},"https:\u002F\u002Fgithub.com\u002FTresjs\u002Ftres\u002Fpull\u002F1504",[53],"#1504",") and adds a ",[20,1998,1999],{},"radius"," prop to ",[20,2002,2003],{},"BloomPmndrs",[49,2005,2008],{"href":2006,"rel":2007},"https:\u002F\u002Fgithub.com\u002FTresjs\u002Ftres\u002Fpull\u002F1494",[53],"#1494","). The September 29 round brings the Tres Leches features below, and aligns every other package on ",[20,2011,2012],{},"@tresjs\u002Feslint-config@1.7.0",". Full notes for every package live on ",[49,2015,2018],{"href":2016,"rel":2017},"https:\u002F\u002Fgithub.com\u002FTresjs\u002Ftres\u002Freleases",[53],"GitHub Releases",[37,2020,2022],{"id":2021},"new-in-the-lab","New in the Lab",[11,2024,2025,2030],{},[49,2026,2029],{"href":2027,"rel":2028},"https:\u002F\u002Flab.tresjs.org",[53],"lab.tresjs.org"," got a summer batch too:",[57,2032,2033],{},[60,2034,2035,2046,2060,2073,2087],{},[63,2036,2037,2043,2044,111],{},[49,2038,2040],{"href":118,"rel":2039},[53],[15,2041,2042],{},"Portals RPG Difficulty",": the one at the top of this post. Three portals, three worlds, one ",[20,2045,356],{},[63,2047,2048,2055,2056,2059],{},[49,2049,2052],{"href":2050,"rel":2051},"https:\u002F\u002Flab.tresjs.org\u002Fexperiments\u002Fplexus-particles\u002F",[53],[15,2053,2054],{},"Plexus Particles",": WebGPU + TSL VFX. Mouse-spawned glowing particles linked to their nearest neighbours, with turbulence and bloom, ported from the three.js ",[20,2057,2058],{},"webgpu_tsl_vfx_linkedparticles"," example.",[63,2061,2062,2069,2070,2072],{},[49,2063,2066],{"href":2064,"rel":2065},"https:\u002F\u002Flab.tresjs.org\u002Fexperiments\u002Fgelatinous-cube\u002F",[53],[15,2067,2068],{},"Gelatinous Cube",": drei's classic, rebuilt with ",[20,2071,1540],{},". A skeleton and its weapons frozen inside a translucent cube.",[63,2074,2075,2082,2083,2086],{},[49,2076,2079],{"href":2077,"rel":2078},"https:\u002F\u002Flab.tresjs.org\u002Fexperiments\u002Frapier-car\u002F",[53],[15,2080,2081],{},"Rapier Vehicle",": Rapier's ray-cast vehicle controller driven from ",[20,2084,2085],{},"useRapier()",". WASD to drive, Space to brake, R to reset.",[63,2088,2089,2096,2097,2102],{},[49,2090,2093],{"href":2091,"rel":2092},"https:\u002F\u002Flab.tresjs.org\u002Fexperiments\u002Frapier-basketball\u002F",[53],[15,2094,2095],{},"Rapier Basketball",": arcade mini basketball by ",[49,2098,2101],{"href":2099,"rel":2100},"https:\u002F\u002Fgithub.com\u002FNeosoulink",[53],"Nathan Mande",". Aim with the arrow keys, adjust power, shoot for streaks.",[37,2104,2106],{"id":2105},"from-the-community","From the community",[37,2108,2110],{"id":2109},"thanks","Thanks",[11,2112,2113,2114,31,2117,2121,2122,2125,2126,2129,2130,2132],{},"This summer was a team effort. ",[49,2115,2101],{"href":2099,"rel":2116},[53],[49,2118,2120],{"href":1421,"rel":2119},[53],"Jaime Torrealba"," carried Rapier to v1 and kept Cientos growing, ",[49,2123,1798],{"href":1796,"rel":2124},[53]," and Jungzl sent core fixes, ",[49,2127,1439],{"href":1437,"rel":2128},[53]," made a first contribution that untangled ",[20,2131,1430],{}," and plugged two GPU leaks, and everyone who opened an issue against the alpha shaped what stable looks like 🙌.",[37,2134,2136],{"id":2135},"see-you-next-month","See you next month",[11,2138,2139,2140,2142,2143,2145,2146,111],{},"Portals, physics, instancing and a CLI in one summer. Next up: closing the MVP gaps on ",[20,2141,356],{}," (edge blur, pointer events, WebGPU) and growing the ",[20,2144,635],{}," CLI beyond glTF. If there is a command you would love to have, ",[49,2147,2150],{"href":2148,"rel":2149},"https:\u002F\u002Fgithub.com\u002FTresjs\u002Ftres\u002Fissues",[53],"tell us",[11,2152,2153,2154,2159,2160,111],{},"Got something cool built with Tres? Share it in our ",[49,2155,2158],{"href":2156,"rel":2157},"https:\u002F\u002Fdiscord.gg\u002FUCr96AQmWn",[53],"Discord",". It might headline the next ",[535,2161,2162],{},"Loop Chronicles",[11,2164,2165],{},"Happy crafting ✌️.",[2167,2168,2169],"style",{},"html pre.shiki code .sWdzt, html code.shiki .sWdzt{--shiki-light:#179299;--shiki-default:#179299;--shiki-dark:#81C8BE}html pre.shiki code .slJ5s, html code.shiki .slJ5s{--shiki-light:#1E66F5;--shiki-default:#1E66F5;--shiki-dark:#8CAAEE}html pre.shiki code .s1cdE, html code.shiki .s1cdE{--shiki-light:#DF8E1D;--shiki-default:#DF8E1D;--shiki-dark:#E5C890}html pre.shiki code .s9Zht, html code.shiki .s9Zht{--shiki-light:#40A02B;--shiki-default:#40A02B;--shiki-dark:#A6D189}html pre.shiki code .sZyUJ, html code.shiki .sZyUJ{--shiki-light:#8839EF;--shiki-default:#8839EF;--shiki-dark:#CA9EE6}html pre.shiki code .spKPg, html code.shiki .spKPg{--shiki-light:#7C7F93;--shiki-default:#7C7F93;--shiki-dark:#949CBB}html pre.shiki code .s9Av-, html code.shiki .s9Av-{--shiki-light:#4C4F69;--shiki-default:#4C4F69;--shiki-dark:#C6D0F5}html pre.shiki code .s0faT, html code.shiki .s0faT{--shiki-light:#1E66F5;--shiki-light-font-style:italic;--shiki-default:#1E66F5;--shiki-default-font-style:italic;--shiki-dark:#8CAAEE;--shiki-dark-font-style:italic}html pre.shiki code .sREMW, html code.shiki .sREMW{--shiki-light:#FE640B;--shiki-default:#FE640B;--shiki-dark:#EF9F76}html pre.shiki code .sMnCH, html code.shiki .sMnCH{--shiki-light:#7C7F93;--shiki-light-font-style:italic;--shiki-default:#7C7F93;--shiki-default-font-style:italic;--shiki-dark:#949CBB;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sQnVB, html code.shiki .sQnVB{--shiki-light:#E64553;--shiki-light-font-style:italic;--shiki-default:#E64553;--shiki-default-font-style:italic;--shiki-dark:#EA999C;--shiki-dark-font-style:italic}",{"title":132,"searchDepth":167,"depth":167,"links":2171},[2172,2173,2184,2185,2194,2195,2196,2197,2198,2199,2200],{"id":39,"depth":167,"text":40},{"id":631,"depth":167,"text":2174,"children":2175},"Meet the tres CLI",[2176,2178,2180,2182],{"id":661,"depth":191,"text":2177},"tres gltf: models become components",{"id":849,"depth":191,"text":2179},"--transform: the asset pipeline",{"id":878,"depth":191,"text":2181},"--instance: repeated meshes, one draw call",{"id":909,"depth":191,"text":2183},"--physics rapier: colliders from Blender",{"id":1099,"depth":167,"text":1100},{"id":1274,"depth":167,"text":1275,"children":2186},[2187,2188,2189,2191,2193],{"id":1278,"depth":191,"text":1281},{"id":1315,"depth":191,"text":1318},{"id":1393,"depth":191,"text":2190},"KeyboardControls gets Q and E",{"id":1427,"depth":191,"text":2192},"Stage shadows land where they should",{"id":1592,"depth":191,"text":1593},{"id":1634,"depth":167,"text":1635},{"id":1802,"depth":167,"text":1803},{"id":1896,"depth":167,"text":1897},{"id":2021,"depth":167,"text":2022},{"id":2105,"depth":167,"text":2106},{"id":2109,"depth":167,"text":2110},{"id":2135,"depth":167,"text":2136},"updates","2026-09-30","Portals open in TresJS! A recap of summer 2026 - MeshPortalMaterial and TresPortal, Rapier hits stable, Instances, the new tres CLI and more.",false,"md",{},"\u002Fblog\u002Fwhats-new-summer-2026",{"text":2209,"minutes":2210,"time":2211,"words":2212},"10 min read",9.94,596400,1988,{"title":5,"description":2203},"blog\u002Fwhats-new-summer-2026","\u002Fblog\u002Fwhats-new-summer-2026\u002Fthe-loop-chronicles-summer-2026.png",null,"qeXwYChlZYhn-iLP8F5hz4mfGIdpJ10fbZRS_OMeqxM",{"id":2219,"title":2220,"avatar":2221,"body":2222,"description":132,"email":2226,"extension":2205,"github":6,"meta":2227,"name":2231,"navigation":222,"path":2232,"seo":2233,"slug":6,"stem":2234,"twitter":6,"website":2235,"__hash__":2236},"authors\u002Fauthors\u002Falvarosabu.md","Alvarosabu","\u002Favatars\u002Falvarosabu.png",{"type":8,"value":2223,"toc":2224},[],{"title":132,"searchDepth":167,"depth":167,"links":2225},[],"hola@alvarosaburido.dev",{"readingTime":2228},{"text":2229,"minutes":2230,"time":2230,"words":2230},"0 min read",0,"Alvaro Saburido","\u002Fauthors\u002Falvarosabu",{"description":132},"authors\u002Falvarosabu","https:\u002F\u002Falvarosaburido.dev","CmwieKa4qc2RGTVr4mry8wF-8Mb9vtJoJrhpP_Qz5kk",{"id":4,"title":5,"author":6,"body":7,"category":2201,"date":2202,"description":2203,"draft":2204,"extension":2205,"meta":2206,"navigation":222,"path":2207,"readingTime":2208,"seo":2213,"stem":2214,"thumbnail":2215,"url":2216,"__hash__":2217,"authors":2238},[2239],{"name":2231,"description":2240,"avatar":2241,"to":2235,"target":2242},"@alvarosabu",{"src":2221},"_blank",1790760415894]