oriverse-engine 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
 
2
2
  >>>>>>>>>>>>
3
3
  Weave World Description Language Documentation
4
- Version:17Aug26-23:47-10536
4
+ Version:21Aug26-00:56-09502
5
5
  >>>>>>>>>>>>
6
6
 
7
7
  <weave_language>
@@ -49,11 +49,11 @@ Weave World Description Language Documentation
49
49
 
50
50
  <asset_word_library>
51
51
  - Established library words per alias namespace, plus `flipbook.<word>` particle textures. PREFER an existing word when one matches the need — it binds instantly with no generation wait or spend. Other words still work: misses show a placeholder and auto-generate in the background (flipbook words are minted deliberately via the flipbook_gen tool instead).
52
- model: abandoned_car alchemist alien_bug alien_hive alley_monster amphora anchor aqua_penguin assembler athlete auntie axe ball banana banana_peel bandage bandit barn barracks barrel barrel_2 base_core baseball_bat battle_car bed bee beehive belt bench bench_2 berry_bush billboard blacksmith boar boat boat_parts bomb bone book boomerang boulder boulder_2 box bread_slice bread_slice_2 brick bridge buddhist_temple bush bush_2 bush_a butter cabbage camp_tent camp_tent_2 campfire canvas_tent cargo_truck carrot cart carved_owl_statue cash_bundle cat cat_blacksmith cat_cart_keeper cat_chef cat_engineer cat_factory_worker cat_merchant cat_rickshaw chair chair_2 checkpoint cheese cheese_2 chest chicken chicken_coop chime_lantern chunk_floor circular_saw clay_buddy cleric cloud clue_item clue_item_2 coin command_center cottage cow crate crate_2 crop crop_plot crossbow crystal crystal_cluster crystal_shard cup customer customer_2 cyclops dog dragon drill druid dual_blades durian elegant_woman ember_fox enemy_spawn energy_drink evidence_item exp_gem fan farmhouse farmhouse_floor fence finish_arch fish fish_2 fishing_rod flag flag_2 flamethrower flashlight flat_rock_slab flower food_crate forager_hut foundation fountain fox fridge frog fuel_pump furniture_bookshelf furniture_table furniture_table_2 furniture_wardrobe gargoyle gate ghoul ghoul_2 gilded_hourglass glimmer_crate goblin golden_beak_shaman golden_coin grandma grandpa grape grape_2 grass_rock_cliff great_sword green_maple_tree greenhouse grocery_box ground_item guard guard_tower hammer hamster harpy hay_bale hay_bale_2 heal_pickup held_item horned_beast horse hospital_assistant house hungry_mouse hunter_bow hunting_hammer hut ice_shard idle_character invoker_mage iron_node item_crate jam_jar kid killer knife knight ladder lamp lamp_2 lane lantern lantern_2 light_pole log_pile log_pile_2 lumber_camp machine_gun mage magnet market_stall mecha_chameleon medic medicine_crate miner minotaur moss_boar mushroom night_watchman ninja_runner nurse oak_tree officer owl paddle palm_tree patient pebble person pickaxe pickup_orb pig pine_tree pistol plate plate_2 player_char police_car pond poop projectile pumpkin rabbit rabbit_runner ragdoll_fighter rain_mill rain_totem ranger requiem_gun resident revolver rifle road_sign robot_runner rock rocket rocket_launcher rocksample rope rope_bundle runic_obelisk sea_mine sedan sentinel_drone shark shield shipping_container shop_counter shop_floor shopkeeper shotgun shuriken signpost signpost_2 signpost_3 skull slime small_rock smg smoke_bomb snail sniper_rifle soil_tile soldier spider sports_car stair star star_core statue stilt_house stone_pile stonecutter_lodge storehouse storm_hearth storm_shrine surgeon survivor sword table tank_hull tent timber_bundle toaster toaster_2 tool_chest torch torch_2 tower training_dummy training_dummy_2 travel_pack tree tribal_cat_elder tribal_cat_villager trophy trunk turret villager volleyball wagon wall warehouse watchtower water_barrel water_well watercan watering_can weapon_rack weapon_rack_2 weapon_shop_sign well wheat wheelbarrow white_tribal_cat_player wizard_staff wood_fence wood_fence_2 wooden_stool worker_robot zebrite_totem zombie
53
- image: alien_bug angled_player_banner axe_icon bean_icon bean_seeds_icon berries_icon book_icon boss_skull bullet_icon cabbage_icon campfire_icon carrot_icon clock_icon coin_icon crop_icon crossed_swords crossed_swords_2 cute_paw_cursor dash_icon deck_icon deck_icon_2 energy_icon fish_icon fishing_rod_icon flint_icon fluffy_sheep_party_portrait forest_ancient_tree_spirit_wide_splash forest_ent gold_coin_icon gold_icon gold_icon_2 hand_icon health_icon health_icon_2 hoe_icon horse_party_portrait hunger_icon inverse_trapezoid_top_bar iron_ore_icon knight_helmet loading_splash log_icon monster_head moon_icon orange_cat_party_portrait panel_frame parsnip_icon parsnip_seeds_icon pickaxe_icon poison_icon potato_icon potato_seeds_icon purple_hive_mind_insect_warrior_wide_splash qa_probe_gem radish_icon revolver_icon rifle_icon robot_face robot_vending_mech_champion_wide_splash round_table_knight_wide_splash ruby_gem_icon sanity_icon scythe_icon seed_bag_icon seed_icon skill_dagger_icon skill_fireaura_icon skill_hammer_icon skill_shield_icon skill_stealth_icon snowflake_spin stone_icon sun_icon tft_alien_portrait_black tft_boss_skull_black tft_clock_black tft_crossed_swords_black tft_forest_portrait_black tft_monster_head_black tft_robot_portrait_black tft_yokai_portrait_black torch_icon twigs_icon undead_death_knight_wide_splash undead_skull water_drop_icon watering_can_icon white_chicken_party_portrait wood_icon yokai_mask yokai_samurai_oni_wide_splash
54
- sound: ambient_horror apartment_ambience arena_warning baby_raptor_step banana_boomerang baton_hit baton_swing bear_shotgun bite blast body_thump body_thump_2 boost boost_burst bow_hit branch_snap brass_gong cannon_blast cannon_fire car_horn card_draw card_play cash_pickup cash_pickup_2 character_select checkpoint chomp coin_pickup coin_pickup_2 corn_burst countdown countdown_beep countdown_tick crab_blaster crab_hit crab_skill crash_burst critical_impact critical_impact_2 crow_call crowd_cheer dash_burst dodge dodge_dust dodge_dust_2 dog_bark dog_pistol door_close door_open door_open_2 door_unlock dual_hit earthquake_rumble earthquake_rumble_2 electric_burst eliminated energy_empty engine_acceleration engine_idle exit_unlock explosion finish finish_chime fish_caught fishing_cast fishing_reel flamethrower_burst food_complete food_complete_2 front_weapon_activation game_check game_end game_start gameplay_music gameplay_music_2 glimmer_bell gold_pickup golf_cup golf_swing grenade_launcher hammer_hit hammer_hit_2 heartbeat hit hook_impact hook_throw item_pickup item_pickup_2 laser_shot laser_shot_2 lasgun_shot level_up level_up_2 level_up_3 level_up_4 level_up_5 line_clear machine_gun machine_gun_reload machine_gun_shot magic_blast medkit_pickup medkit_use menu_music metal_hit metal_hit_2 mine missile_launch mole_sniper monster_attack monster_attack_2 monster_roar monster_roar_2 owl_hoot pickup piece_capture piece_lock piece_move pistol_reload pistol_shot place player_hit player_hurt player_hurt_2 police_siren punch rain_ambience raptor_step ready_up rear_ability_activation repair resource_pickup respawn revive rifle_shot ring_out ringout robot_beam robot_blast robot_charge robot_laser rock_riff rocket_shot rot_loop royal_capture score_boost shield shield_block ship_destroyed shotgun_shot slap slap_hit survivor_step sword_clang sword_clang_2 sword_hit sword_hit_2 tire_skid toast_pop toy_pop trex_step turn_alert ui_click ui_click_2 ui_click_3 ui_click_4 ui_click_5 vehicle_damaged vehicle_destroyed victory victory_fanfare victory_fanfare_2 victory_sting victory_sting_2 vortex_hum wall_deploy wall_pickup warning_siren water_splash wave_crash weapon_switch whistle wind_gust wind_gust_2 wolf_howl wood_impact zebrite_chime zombie_attack zombie_growl zombie_roar
55
- effect: acid_splash arrow_hit bite_splash blood_hit blood_splash boost_burst cannon_blast capture_burst cartoon_impact cash_sparkle cash_sparkle_2 coin_sparkle collapse_dust crash_burst critical_smoke damage_smoke damage_sparks damage_sparks_2 damage_sparks_3 dash_trail dash_trail_2 dismember dodge_dust dust_puff dust_puff_2 dust_puff_3 electric_burst eliminated_burst explosion explosion_burst finish_confetti fire_burst fireball fireball_burst gold_rush golf_cup golf_hit grenade_blast hammer_impact heal_glow healing_glow hit_burst hook_hit impact_flash_critical impact_flash_small impact_shockwave impact_shockwave_2 impact_shockwave_3 impact_sparks ink_cloud item_glow magic_blast magic_sparkle magic_vortex metal_hit meteor_fire mine_burst muzzle_flash objective_pickup player_hit rage_burst rainbow_burst rainbow_burst_2 rapid_slash respawn_burst revive_burst revive_glow rickshaw_burn ringout_explosion rocket_explosion rot_pulse rune_pickup shield_burst shield_pop slap_hit slash_burst slash_burst_2 slash_burst_3 smoke_puff smoke_puff_2 sonar_pulse sparkle_burst sparkle_burst_2 sparkle_burst_3 sparkler speed_burst stun_stars stun_stars_2 stun_stars_3 sword_slash tank_burning tank_explosion terrain_blast top_collision_impact water_burst water_splash wind_leaves
56
- flipbook: blue_flame bubble_float dust_puff electric_spark ember_glow explosion_burst gray_smoke heart_pulse leaf_flutter magic_sparkle orange_flame poison_cloud smoke_puff snowflake_spin star_twinkle water_splash white_smoke
52
+ model: abandoned_car alchemist alien_bug alien_hive alley_monster ammo_crate amphora anchor aqua_penguin assembler athlete aunt auntie axe ball banana banana_peel bandage bandit barn barracks barrel barrel_2 base_core baseball_bat battle_car bed bee beehive belt bench bench_2 berry_bush billboard blacksmith blk_probe_box boar boat boat_parts bomb bone book boomerang boulder boulder_2 box bread_slice bread_slice_2 brick bridge buddhist_temple bush bush_2 bush_a butter cabbage camp_tent camp_tent_2 campfire canvas_tent car_wheel cargo_truck carrot cart carved_owl_statue cash_bundle cat cat_blacksmith cat_cart_keeper cat_chef cat_engineer cat_factory_worker cat_merchant cat_rickshaw chair chair_2 checkpoint cheese cheese_2 chest chicken chicken_coop chime_lantern chunk_floor circular_saw clay_buddy cleric cloud clue_item clue_item_2 coin command_center container_04 cottage cousin cow crate crate_2 crate_a crop crop_plot crossbow crowbar crystal crystal_cluster crystal_shard cup customer customer_2 cutting_board cutting_board_2 cyclops dog dragon drill druid dual_blades durian elegant_woman ember_fox enemy_spawn energy_drink evidence_item exp_gem fan farm_boy farmhouse farmhouse_floor fence finish_arch fish fish_2 fishing_rod flag flag_2 flamethrower flashlight flat_rock_slab flower food_crate forager_hut forge forklift foundation fountain fox fridge fridge_2 frog frying_pan frying_pan_2 fuel_pump furniture_bookshelf furniture_table furniture_table_2 furniture_wardrobe gargoyle gate ghoul ghoul_2 gilded_hourglass glimmer_crate goblin godfather golden_beak_shaman golden_coin grandma grandpa grape grape_2 grass_rock grass_rock_cliff great_sword green_maple_tree greenhouse grocery_box ground_item guard guard_tower hammer hamster harpy hay_bale hay_bale_2 heal_pickup held_item horned_beast horse hospital_assistant house hungry_mouse hunter hunter_bow hunting_hammer hut ice_shard idle_character invoker_mage iron_node item_crate jam_jar kid killer knife knight lab_crate_a ladder ladder_a lamp lamp_2 lane lantern lantern_2 light_pole log_pile log_pile_2 lumber_camp machine_gun mage magnet market_stall mecha_chameleon medic medicine_crate mil_supply_set mine miner minotaur moss_boar mushroom nephew niece night_watchman ninja_runner npc nurse oak_tree officer oil_drum owl paddle palm_tree patient pearl_bush pebble person pickaxe pickup_orb pig pine_tree pistol plate plate_2 player_char police_car pond poop projectile pumpkin pyramid rabbit rabbit_runner ragdoll_fighter rain_mill rain_totem ranger requiem_gun resident revolver rifle road_sign robot_grunt robot_runner rock rocket rocket_launcher rocksample rope rope_bundle runic_obelisk sandbag sawmill school scifi_mil_crate sea_mine sedan sentinel_drone shark shield shipping_container shop_counter shop_floor shopkeeper shotgun shower shuriken signpost signpost_2 signpost_3 skull slime small_rock smg smoke_bomb snail sniper_rifle sofa soil_tile soldier spider sports_car squid stair star star_core statue stepmother stilt_house stone_pile stonecutter_lodge storehouse storm_hearth storm_shrine surgeon survivor sword table tank_hull tannery telephone television tent timber_bundle toaster toaster_2 tool_chest torch torch_2 tower training_dummy training_dummy_2 travel_pack tree tribal_cat_elder tribal_cat_villager trophy trunk turret uncle villager volleyball wagon wall warehouse watchtower water_barrel water_well watercan watering_can weapon_rack weapon_rack_2 weapon_shop_sign well wheat wheelbarrow white_tribal_cat_player wizard_staff wood_fence wood_fence_2 wooden_stool worker_robot zebrite_totem zombie
53
+ image: airtank_icon ak_rifle_icon alien_bug angled_player_banner axe_icon banana_weapon_icon bandage_icon baseball_bat_icon bean_icon bean_seeds_icon berries_icon book_icon boss_skull bread_icon bullet_icon cabbage_icon campfire_icon canned_food_icon carrot_icon cheese_icon clock_icon coin_icon crop_icon crossed_swords crossed_swords_2 crosshair crowbar_icon cute_paw_cursor dash_icon deck_icon deck_icon_2 energy_icon fish_icon fishing_rod_icon flamethrower_icon flint_icon fluffy_sheep_party_portrait forest_ancient_tree_spirit_wide_splash forest_ent gold_coin_icon gold_icon gold_icon_2 grenade_launcher_icon hand_icon health_icon health_icon_2 hoe_icon horse_party_portrait hu_armor hu_headshot hu_hit hu_hitcrit hu_mortar hu_recon hu_reload hu_rifle hu_sentry hud_armor_plate_shield hud_assault_rifle_side hud_crit_hitmarker_x_red hud_headshot_skull hud_hitmarker_x_ticks hud_mortar_strike_shell hud_reload_circular_arrow hud_sentry_turret hud_uav_recon_drone hud2_drone_wing hud2_reload_arrow hud2_rifle_flat hud2_shell_burst hud2_turret_gun hud2_x_marker hud2_x_marker_red hud3_drone_stencil hud3_rifle_stencil hud3_shell_stencil hud3_skull_stencil hunger_icon inverse_trapezoid_top_bar iron_ore_icon knife_icon knight_helmet laser_gun_icon loading_splash log_icon machine_gun_icon mackerel_icon monster_head moon_icon orange_cat_party_portrait panel_frame parsnip_icon parsnip_seeds_icon pickaxe_icon pill_bottle_icon pistol_icon poison_icon potato_icon potato_seeds_icon purple_hive_mind_insect_warrior_wide_splash qa_probe_gem radish_icon revolver_icon rifle_icon road_tiles_icon road_tiles_icon_2 robot_face robot_vending_mech_champion_wide_splash rocket_launcher_icon round_table_knight_wide_splash roundabout_icon roundabout_icon_2 roundabout_ring_icon_transparent_no_background ruby_gem_icon salvage_icon sanity_icon sardine_icon scythe_icon seed_bag_icon seed_icon shotgun_icon skill_dagger_icon skill_fireaura_icon skill_hammer_icon skill_shield_icon skill_stealth_icon snapper_icon sniper_rifle_icon snowflake_spin soda_can_icon squid_icon steak_icon stone_icon straight_road_icon_transparent_no_background submachine_gun_icon sun_icon syringe_gun_icon tft_alien_portrait_black tft_boss_skull_black tft_clock_black tft_crossed_swords_black tft_forest_portrait_black tft_monster_head_black tft_robot_portrait_black tft_yokai_portrait_black torch_icon traffic_light_icon traffic_light_icon_2 traffic_light_icon_transparent_no_background tuna_icon twigs_icon undead_death_knight_wide_splash undead_skull water_bottle_icon water_drop_icon watering_can_icon white_chicken_party_portrait wood_icon yokai_mask yokai_samurai_oni_wide_splash
54
+ sound: ambient_horror apartment_ambience arena_warning baby_raptor_step banana_boomerang baton_hit baton_swing bear_shotgun bite blast body_thump body_thump_2 boost boost_burst bow_hit branch_snap brass_gong cannon_blast cannon_fire car_horn card_draw card_play cash_pickup cash_pickup_2 character_select checkpoint chomp coin_pickup coin_pickup_2 corn_burst correct_chime countdown countdown_beep countdown_tick crab_blaster crab_hit crab_skill crash crash_burst critical_impact critical_impact_2 croc_machinegun crow_call crowd_cheer crystal_pickup dash_burst dodge dodge_dust dodge_dust_2 dog_bark dog_pistol door_close door_creak door_open door_open_2 door_unlock dual_hit earthquake_rumble earthquake_rumble_2 electric_burst electric_shock eliminated eliminated_2 energy_empty engine_acceleration engine_idle exit_unlock explosion finish finish_chime fish_caught fishing_cast fishing_reel flamethrower_burst food_complete food_complete_2 front_weapon_activation game_check game_end game_start gameplay_music gameplay_music_2 glimmer_bell gold_pickup golf_cup golf_swing grenade_launcher gunshot hammer_hit hammer_hit_2 heartbeat hit hook_impact hook_impact_2 hook_throw hook_throw_2 item_drop item_pickup item_pickup_2 laser_shot laser_shot_2 lasgun_shot level_up level_up_2 level_up_3 level_up_4 level_up_5 line_clear machine_gun machine_gun_reload machine_gun_shot magic_blast medkit_pickup medkit_use menu_music metal_hit metal_hit_2 mine missile_launch mole_sniper monster_attack monster_attack_2 monster_roar monster_roar_2 owl_hoot pickup piece_capture piece_lock piece_move pistol_reload pistol_shot place player_hit player_hurt player_hurt_2 police_siren punch rain_ambience raptor_step ready_up rear_ability_activation reload repair resource_pickup respawn revive rifle_reload rifle_shot rifle_shot_2 ring_out ringout robot_beam robot_blast robot_charge robot_laser rock_riff rocket_shot rot_loop round_start royal_capture score_boost shield shield_block ship_destroyed shotgun_shot signal_ping siren slab_turn slap slap_hit speed_burst stone_rotate survivor_step sword_clang sword_clang_2 sword_hit sword_hit_2 tire_skid toast_pop toy_pop trex_step turn_alert ui_click ui_click_2 ui_click_3 ui_click_4 ui_click_5 vehicle_damaged vehicle_destroyed victory victory_fanfare victory_fanfare_2 victory_sting victory_sting_2 vortex_hum wall_deploy wall_pickup warning_siren water_splash wave_crash weapon_switch whistle wind_gust wind_gust_2 wolf_howl wood_impact wrong_buzz zebrite_chime zombie_attack zombie_growl zombie_roar
55
+ effect: acid_splash arrow_hit bite_splash blood_hit blood_splash boost_burst cannon_blast capture_burst cartoon_impact cash_sparkle cash_sparkle_2 coin_sparkle collapse_dust crash_burst critical_smoke damage_smoke damage_sparks damage_sparks_2 damage_sparks_3 dash_trail dash_trail_2 dismember dodge_dust dust_puff dust_puff_2 dust_puff_3 electric_burst eliminated_burst explosion explosion_burst finish_confetti fire_burst fireball fireball_burst ghost_mist gold_rush golf_cup golf_hit grenade_blast hammer_impact heal_glow healing_glow hit_burst hook_hit hook_hit_2 impact_flash_critical impact_flash_small impact_shockwave impact_shockwave_2 impact_shockwave_3 impact_sparks ink_cloud item_glow magic_blast magic_sparkle magic_vortex metal_hit meteor_fire mine_burst muzzle_flash objective_pickup player_hit poison_cloud rage_burst rainbow_burst rainbow_burst_2 rapid_slash respawn_burst revive_burst revive_glow rickshaw_burn ringout_explosion rocket_explosion rot_pulse rune_pickup shield_burst shield_pop slap_hit slash_burst slash_burst_2 slash_burst_3 smoke_puff smoke_puff_2 sonar_pulse sparkle_burst sparkle_burst_2 sparkle_burst_3 sparkler speed_burst step_dust stun_stars stun_stars_2 stun_stars_3 sword_slash tank_burning tank_explosion terrain_blast top_collision_impact w_firethrowe w_firethrust_finale_2026 water_burst water_splash wind_leaves
56
+ flipbook: blood_fine blood_mist blue_flame bubble_float dust_fine_grey dust_puff electric_spark ember_glow explosion_burst explosion_soot gray_smoke heart_pulse hot_spark_burst leaf_flutter magic_sparkle muzzle_cone muzzle_flash_star orange_flame poison_cloud smoke_puff smoke_soft_grey snowflake_spin spark_hot_grey star_twinkle tracer_streak water_splash white_smoke
57
57
  </asset_word_library>
58
58
 
59
59
  <texture_dsl_usage>
@@ -73,6 +73,7 @@ flipbook: blue_flame bubble_float dust_puff electric_spark ember_glow explosion_
73
73
  - `#road_network Name ... #end`: a road GRAPH the engine meshes into junction-merged road tiles at load (carriageway, miter-blended intersections, curbs, sidewalks, center dashes, crosswalks). Body statements end with `;`: `cell = 32000;` (tile grid cm, optional), `class = width_cm, sidewalk_cm, curb_w_cm, curb_h_cm, "CarriagewayMat", "CurbMat", "SidewalkMat", "MarkingMat";` (repeatable; edges index classes in order; empty marking name = no markings), `nodes = x, y, x, y, ...;` (cm, repeatable/appends), `edges = nodeA, nodeB, classIndex, ...;` (triplets, repeatable), `curve = a, b, c1x, c1y[, c2x, c2y];` (optional per a→b edge: quadratic/cubic bezier control points in cm; omit = straight; junctions meet curves at their end tangents; too-tight curvature for the class width is a load error). The block spawns the network itself: tiled road meshes plus walkable per-edge slabs (no companion object needed); optional `position = x, y, z;` offsets the whole network. Editor edits fold back into this block on save — re-read it before patching. Prefer this over hand-built per-segment road boxes: junctions come out clean and one graph edit reflows everything.
74
74
  - `#terrain_bytes "terrain.url" ... #end`: embedded uploaded-terrain heightfield payload (base64 of zlib-compressed terrain bytes) satisfying `terrain X { model = "terrain.url" }` with zero network fetches, so the world is self-contained offline. Blocks are machine-generated (desktop `embed_terrain` CLI), not hand-authored - and never required to submit: validation resolves uploaded `terrain.` assets itself. Prefer procedural terrain (`SpawnTerrainFromHeights` + `TerrainHeights*`) for new worlds.
75
75
  - Emission is linear (1 soft self-lit, 4 lamp, 16+ neon bloom): put it on small accents - lamps, signs, runes, windows; large emissive surfaces wash out the scene, keep those <= 1.
76
+ - A surface still reading WHITE at emission 0/low is specular+bloom, not emission: glossy (low roughness) under a strong sun blooms to a white blob - fix with roughness 0.8+ (matte) and/or a darker tint; lowering emission further changes nothing.
76
77
  </texture_dsl_usage>
77
78
 
78
79
  <adjuster_usage>
@@ -82,7 +83,7 @@ flipbook: blue_flame bubble_float dust_puff electric_spark ember_glow explosion_
82
83
  - Add an #adjuster block whenever the look is a matter of taste the user may want to hand-tune (grass, ground, water, wind, tree LOD).
83
84
  - Lighting/sky/grade knobs (sun color/intensity, skybox tint/saturation/exposure, SSAO, vignette, scene contrast/saturation/exposure) are USER-owned: never write or retune them, as knobs or calls; lighting/mood requests -> Adjust panel.
84
85
  - SetWater* knobs set the INITIAL ocean state: they replay after load-time code, so a `knob SetWaterEnabled = 0` line keeps water off across reloads (the editor's Find > Water delete writes it). Code that changes water after load (OnSpawned, timers, events) still wins at runtime.
85
- - Knobs: SetGrassRootColor (color), SetGrassTipColor (color), SetGrassBrightnessVariationPercent (0..300), SetGrassSizeVariationPercent (0..300), SetGrassHeightMinCm (0..300), SetGrassHeightMaxCm (0..300), SetGrassWavePeriodCm (100..3000), SetGrassWindStrengthCm (0..50), SetGrassWindSpeedPercent (0..300), SetGrassBladeWidthPercent (50..200), SetGrassSpacingCm (0..100), SetGrassTerrainActiveDistanceM (0..500), SetGrassCullDistanceM (0..500), SetGrassFadeDistancePercent (0..100), SetGrassFarThinningPower (0..8), SetTerrainErosionDetailPercent (0..300), SetSunColor (color), SetSunIntensity (0..20), SetSunRotation (0..360), SetSunTilt (0..90), SetSkyLightIntensity (0..8), SetSkyLightColor (color), SetSkyLightSaturation (0..3), SetSkyboxTint (color), SetSkyboxSaturation (0..3), SetSkyboxExposure (0..3), SetSkyboxHaze (0..8), SetSkyboxContrast (0..3), SetSkyboxGroundColor (color), SetSkyboxColor (color), SetSkyboxCloudCoverage (0..1), SetSkyboxStarIntensity (0..3), SetShadowBlurRadius (0..20), SetShadowOpacity (0..1), SetShadowLift (0..3), SetShadowLiftThreshold (0.02..0.3), SetShadowDistance (0..500), SetFogColor (color), SetFogStartDistance (0..2000), SetFogEndDistance (0..2000), SetFogSkyboxAffect (0..100), SetHeightFogEnabled (0..1), SetHeightFogTop (0..200), SetHeightFogBottom (-100..200), SetHeightFogSoftness (0..1), SetSsaoIntensity (0..1), SetSsaoDistance (0..10), SetBloomThreshold (0..3), SetBloomIntensity (0..2), SetTerrainNormalStrengthPercent (0..300), SetContrast (0..4), SetSaturation (0..4), SetExposure (-3..3), SetVignetteStrength (0..1), SetVignetteRadius (0..1), SetVignetteSoftness (0..1), SetVignetteColor (color), SetWaterEnabled (0..1), SetWaterSeaLevelCm (-2000..10000), SetWaterAmplitudeCm (0..500), SetWaterWavelengthCm (100..20000), SetWaterSteepness (0..1), SetWaterDirectionDeg (0..360), SetWaterSpeedPercent (0..400), SetWaterShallowColor (color), SetWaterDeepColor (color), SetWaterColorMixRangeCm (1..2000), SetWaterTransparency (0..1), SetWaterReflectionStrength (0..2), SetWaterReflectionDistortion (0..2), SetWindDirectionDeg (0..360), SetWindStrength (0..1), SetWindGustiness (0..1), SetTreeLodSwitchDistanceM (0..300), SetTreeMeshDistanceM (0..1000), SetTreeCullDistanceM (0..3000), SetTreeFadeDistancePercent (5..80), SetTreeFarLeafDensityPercent (10..300)
86
+ - Knobs: SetGrassRootColor (color), SetGrassTipColor (color), SetGrassBrightnessVariationPercent (0..300), SetGrassSizeVariationPercent (0..300), SetGrassHeightMinCm (0..300), SetGrassHeightMaxCm (0..300), SetGrassWavePeriodCm (100..3000), SetGrassWindStrengthCm (0..50), SetGrassWindSpeedPercent (0..300), SetGrassBendStrengthPercent (0..200), SetGrassBladeWidthPercent (50..200), SetGrassSpacingCm (0..100), SetGrassTerrainActiveDistanceM (0..500), SetGrassCullDistanceM (0..500), SetGrassFadeDistancePercent (0..100), SetGrassFarThinningPower (0..8), SetTerrainErosionDetailPercent (0..300), SetSunColor (color), SetSunIntensity (0..20), SetSunRotation (0..360), SetSunTilt (0..90), SetSkyLightIntensity (0..8), SetSkyLightColor (color), SetSkyLightSaturation (0..3), SetSkyboxTint (color), SetSkyboxSaturation (0..3), SetSkyboxExposure (0..3), SetSkyboxHaze (0..8), SetSkyboxContrast (0..3), SetSkyboxGroundColor (color), SetSkyboxColor (color), SetSkyboxCloudCoverage (0..1), SetSkyboxStarIntensity (0..3), SetShadowBlurRadius (0..20), SetShadowOpacity (0..1), SetShadowLift (0..3), SetShadowLiftThreshold (0.02..0.3), SetShadowDistance (0..500), SetFogColor (color), SetFogStartDistance (0..2000), SetFogEndDistance (0..2000), SetFogSkyboxAffect (0..100), SetHeightFogEnabled (0..1), SetHeightFogTop (0..200), SetHeightFogBottom (-100..200), SetHeightFogSoftness (0..1), SetSsaoIntensity (0..1), SetSsaoDistance (0..10), SetBloomThreshold (0..3), SetBloomIntensity (0..2), SetTerrainNormalStrengthPercent (0..300), SetContrast (0..4), SetSaturation (0..4), SetExposure (-3..3), SetVignetteStrength (0..1), SetVignetteRadius (0..1), SetVignetteSoftness (0..1), SetVignetteColor (color), SetWaterEnabled (0..1), SetWaterSeaLevelCm (-2000..10000), SetWaterAmplitudeCm (0..500), SetWaterWavelengthCm (100..20000), SetWaterSteepness (0..1), SetWaterDirectionDeg (0..360), SetWaterSpeedPercent (0..400), SetWaterShallowColor (color), SetWaterDeepColor (color), SetWaterColorMixRangeCm (1..2000), SetWaterTransparency (0..1), SetWaterMurkDensity (0..4), SetWaterReflectionStrength (0..2), SetWaterReflectionDistortion (0..2), SetWindDirectionDeg (0..360), SetWindStrength (0..1), SetWindGustiness (0..1), SetTreeLodSwitchDistanceM (0..300), SetTreeMeshDistanceM (0..1000), SetTreeCullDistanceM (0..3000), SetTreeFadeDistancePercent (5..80), SetTreeFarLeafDensityPercent (10..300)
86
87
  Example:
87
88
  #adjuster
88
89
  section "Grass"
@@ -95,15 +96,16 @@ knob SetGrassHeightMaxCm = 45 range 0..120
95
96
  - `#particles Name ... #end` defines local effect asset `effect.Name`; `#particles effect.Name` also works, but prefer short `Name`. Body is a JSON array; each object is one emitter component.
96
97
  - Every local component needs a top-level `"particleTextureName"`: `"flipbook.<word>"` for an animated sprite-sheet atlas from the shared flipbook library (best for fire/smoke/magic; lowercase subject words like `flipbook.orange_flame`; misses render a glow placeholder until the word is minted), `"texture.TextureName.color"` with a matching `#texture TextureName`, or `"image.<User>.<Name>"` referencing a real ori image asset you actually know (never invent one). Use `texture.*.color` (`baked.*` addresses material-slot maps, not particle textures; `.normal`/`.orm` are not particle flipbooks).
97
98
  - Spawn with scene `effect Spark { effect = "effect.Name" }` - or, for prop-attached fire/smoke, prefer a `particles("<word>", at: ...)` socket inside the `#mesh` (see <mesh_dsl_usage>). From code pass the ASSET as a static import: `SpawnEffectWithAutoDestroy(Ori.effect.Name, pos)` (returns the spawned object — `.SetSizeUniform(n)` to size it), or `Ori.alias.effect.<word>` for aliases. A `Scene.<object>` reference is not an effect asset (W2C0405).
98
- - Sizing: declare `"boundingBoxSize": [x, y, z]` (meters, Z-up; per-component, max wins) as the effect's authored real-world footprint, and author emitters (`radius`, `sizeSequence`, speeds) at that real scale. The object's `size` (cm, like any object) then scales the effect by `size / boundingBoxSize` — e.g. a campfire authored with `boundingBoxSize [1, 1, 1.5]` placed with `size = 100` renders at its authored 1m footprint. Without `boundingBoxSize` the base is a legacy 10cm box, so `size = 100` blows the effect up 10x — always declare it. Size effects with `size`, not `scale`. The effect's authored local origin renders at the object's `position` (no anchoring): author ground effects with their base at z=0 and bursts centered on the origin.
99
+ - Sizing: declare `"boundingBoxSize": [x, y, z]` (meters, Z-up; per-component, max wins) as the effect's authored real-world footprint, and author emitters (`radius`, `sizeSequence`, speeds) at that real scale. The object's `size` (cm, like any object) then scales the effect by `size / boundingBoxSize` — e.g. a campfire authored with `boundingBoxSize [1, 1, 1.5]` placed with `size = 100` renders at its authored 1m footprint. Without `boundingBoxSize` the base is a legacy 10cm box, so `size = 100` blows the effect up 10x — always declare it. Size effects with `size`, not `scale`. Author emitters freely around your origin; when the content is not origin-centered, add `"boundingBoxCenter": [x, y, z]` (meters; where the box CENTER sits relative to that origin; default [0,0,0]) so the box covers the content — e.g. a ground flame rising 0..1.5m declares [0, 0, 0.75]. Placement matches meshes: the object's `position` rests the declared box's bottom on the point (`transform_pivot = center` centers it); code spawns (`SpawnEffect*`) put the box CENTER at the given position.
99
100
  - JSON values: scalars are numbers, vecs are `[x,y]`/`[x,y,z]`, curves are up to 8 `[[life01, value], ...]`; `colorSequence` uses `[[life01, [r,g,b]], ...]`. Prefer numeric `0/1` for booleans.
100
- - CPU/import keys: `_particleName_` ignored label; `particleCount` live-particle capacity override, not spawn count; `emitterPosition`/`emitterRotation` component-local offset/XYZ degrees; `boundingBoxSize` authored footprint in meters (see sizing bullet above).
101
+ - CPU/import keys: `_particleName_` ignored label; `particleCount` live-particle capacity override, not spawn count; `emitterPosition`/`emitterRotation` component-local offset/XYZ degrees; `boundingBoxSize`/`boundingBoxCenter` authored footprint + box placement in meters (see sizing bullet above).
101
102
  - Flipbook keys: `framesX`, `framesY`, `totalFrames`, `flipbookAnimationSpeed`, `flipbookStartRandom`. For `flipbook.<word>` refs these auto-fill from the library at load; set them only to override.
102
103
  - Spawn keys: `spawnStartDelay`, `spawnRate` per sec, `isLooping`, `duration` seconds (`0` means no shader stop; use finite duration for one-shots), `burstParticleCount` (fires at t=0, then every `burstInterval` seconds while emitting; `burstInterval` unset = the t=0 burst only).
103
104
  - Shape keys: `emitterShapeType` = `"sphere"|"box"|"cylinder"|"disc"` or `0..3`; `shapeStyle` = `"volume"|"surface"`; `shapeInOut` = `"in"|"out"|"both"` (omitted defaults inward); `radius`, `cylinderHeight`, `boxSize`, `shapePartial`, `lifeTimeRange`, `speedRange`, `spreadAngle` `[yaw,pitch]` degrees, `lockedToEmitter` (`0` default = particles keep world position once spawned - trails stay behind a moving emitter; `1` = particles ride it, e.g. torch flame). Box surface emits from +Z face; cylinder height is local X; disc uses `cylinderHeight` as thickness. Emission direction: each shape emits along its own radial direction; `shapeInOut` omitted = INWARD, `"out"` flips outward, `"both"` = 50/50. `spreadAngle [yaw, pitch]` then jitters that direction by uniform +/-yaw degrees about the emitter's local Y axis and +/-pitch degrees about its X axis (fixed local axes, not a cone around the direction).
104
105
  - Visual/motion keys: `sizeConstant` or `sizeSequence`; `opacityConstant` or `opacitySequence`; `colorConstant` or `colorSequence`; `accelerationVector` authored Z-up; `drag` seconds to halve velocity; `rotationRange`, `rotationSpeedRange`; `orientation` 0 facing camera / 1 world-up / 2 velocity-parallel / 3 velocity-perpendicular; `additiveBlend`, `isHidden`, `softParticleFadeDisabled`, `softParticleFadeDistance`, `squashConstant` or `squashSequence` (positive stretches up, negative sideways); `lit` 1 = sun+sky shading (smoke/dust/debris read as lit volumes; leave 0 for emissive fire/glow).
105
106
  - Resolution key: components render at full (native) resolution by default (crisp edges, no distance shimmer). Set `"renderResolution": "half"` on soft/volumetric high-overdraw components (smoke, fog, glow) — cuts GPU fill cost on weak GPUs; avoid on hard-edged/crisp content (`"full"` is accepted as an explicit no-op).
106
107
  - Ribbon/trail components (boost trails, sword arcs, tracers, dash streaks): `"type": "ribbon"` renders one connected camera-facing strip through the emitter's recent world path instead of billboards; layer with billboard components in the same effect (ideal boost = ribbon streak + sparse additive orbs). Keys: `trailSeconds` (point max age = trail length, default 0.5), `pointsPerSecond` (path sampling rate, default 30), `ribbonUv` = `"stretch"` (default) | `"repeat_per_meter"` (tiles by real distance), `ribbonPoints` (ring cap; defaults to fit trailSeconds*pointsPerSecond, max 256); `sizeConstant`/`sizeSequence` = strip WIDTH in meters over point age; texture/flipbook, color/opacity, `additiveBlend`, `renderResolution`, `boundingBoxSize`, `emitterPosition`/`emitterRotation`, soft-fade keys keep their exact meaning. Emission/shape/motion keys (`spawnRate`, `lifeTimeRange`, `emitterShapeType`, `speedRange`, `spreadAngle`, `drag`, `orientation`, `duration`, ...) are load ERRORS on a ribbon component. Ribbon effects are always continuous; the strip exists only while the emitter MOVES (attach to a moving object; `preview_effect` sweeps the emitter for you). Object `size` scales strip width — trail length is temporal (`trailSeconds` x actual speed). A trail that looks unchanged after resizing its object wants `trailSeconds`/`sizeSequence` edits, not more `size`.
108
+ - Gun tracers / hitscan beams / lightning bolts: spawn ONE thin stretched mesh (or ribbon effect) per shot from muzzle to impact - LookAt the impact, scale the length axis to the distance, despawn in 0.05-0.15s; never per-frame display-cube chains. Bolt lifetime must be SHORTER than the refire interval or successive bolts merge into a solid rope; lightning = the same bolt with a few midpoints offset sideways per spawn + a ribbon afterglow.
107
109
  - Mesh components (debris, coins, leaves, shards, casings): `"type": "mesh"` renders lit opaque 3D instances of a real mesh instead of sprites; layer with billboard/ribbon components in one effect (rock burst = mesh chunks + dust billboards + one flash). `"particleMeshName"`: a local `"mesh.Name"` or a bare-alias `"alias.model.<noun>"` (library-bound or background-generated; placeholder cube until it lands) — or an array of up to 4, picked per particle (identical chunks read fake). Meshes keep their own materials and receive scene lighting: `colorConstant`/`colorSequence` tints (omit = untinted), `opacityConstant`/`opacitySequence` dither-fades, `sizeConstant`/`sizeSequence` = largest mesh dimension in meters. `"meshAlign"`: `"tumble"` (default; `"tumbleSpeedRange": [min,max]` deg/s random-axis, default [90, 360]) | `"velocity"` (mesh +Z along travel: arrows, shards) | `"world"` (authored orientation). Emission/shape/motion keys keep their exact billboard meaning. Texture/flipbook keys, `orientation`, `rotationRange`/`rotationSpeedRange`, `squash*`, `additiveBlend`, `softParticleFade*`, `renderResolution` are load ERRORS on a mesh component. `"castShadow": 1` enables shadow casting (default off; a fading particle stops casting, like skinned deaths). `"groundBounce": 0..1` bounces world-space particles off terrain/static ground with that restitution and lets them settle until life ends (visual bounce, not physics; `lockedToEmitter` particles skip it). HDR `colorConstant`/`colorSequence` excess over 1.0 becomes emissive glow. Each particle is a real lit draw — keep `spawnRate * lifeTime` under ~100 and meshes low-poly.
108
110
  - Runtime-managed fields are not useful in JSON: `time`, `delta_time`, `world_matrix`, `world_matrix_inv`, `emitter_time`, `emitter_id`, `system_scale`, `instance_tint`, `instantClearOnRemove`, padding fields. Unknown keys only log warnings.
109
111
  Example:
@@ -151,7 +153,7 @@ out = normalize(biquad(lp, sweep, cutoff = 2200, q = 1.2) * env_adsr(0.005, 0.1,
151
153
  - Effects on meshes: `particles("<effect word>", at: (x,y,z)[, axis:, scale:])` in the mesh body embeds a particle effect the way `emitter()` embeds a light - mesh-local, riding every instance/rotation/saved object. The word must be a quoted literal and resolves like `effect.<word>` (local `#particles` block name, case-sensitive, or lowercase library word). Rest-pose like emitter(); prefer loops (fire, smoke, drips). For prop-attached fire/smoke prefer this over hand-placed effect objects.
152
154
  - Material slots: `material: "Name"` on generators or `paint(g, material: "Name")`. A slot name resolves to world `material.Name` when it exists (pair slots with `#texture Name` for low-poly color-blocking). Precedence: object/batch material override > explicit submesh override > authored local slot material > intrinsic GLB PBR.
153
155
  - Canonical slot names auto-fill from the built-in material library when the world doesn't declare them (library meshes only use these; name list in <texture_dsl_usage>). Recolor one for every library mesh by declaring it, e.g. `material Wood { base = "WoodDetail" tint = "#8a2b1e" }`.
154
- - GlassTransparent is the real translucent glass (fresnel reflection + grime; casts no shadow) - only for panes with real geometry behind them (balustrades, canopies, display cases), NOT hollow building window walls (blend reveals the empty shell; use `interior_window_pbr`, next clause). Derive tints in one line - `material PoolGlass { base = "GlassTransparent" tint = "#3A7E8C" }` - and override `opacity = 0..1` (transmission) / `glassRoughness = 0..1` (reflection blur) only to tune.
156
+ - GlassTransparent is the real translucent glass (fresnel reflection + grime; casts no shadow) - only for panes with real geometry behind them (balustrades, canopies, display cases), NOT hollow building window walls (blend reveals the empty shell; use `interior_window_pbr`, next clause). Derive tints in one line - `material PoolGlass { base = "GlassTransparent" tint = "#3A7E8C" }` - and override `opacity = 0..1` (1 = opaque) / `glassRoughness = 0..1` (reflection blur) only to tune.
155
157
  - Hollow building window walls (where GlassTransparent would expose the empty shell): `material TowerWin { base = "InteriorRooms" shader = "interior_window_pbr" tint = "#D8CFC0" glassTint = "#3A4E4A" }` - opaque fake-parallax rooms, night-lit cells automatic. Base picks the interior per building: `"InteriorRooms"` homes, `"InteriorOffice"` workplaces. Homes get side drapes by default (`drapeSides` = per-side width 0..0.35, 0 disables; offices default 0). `tint` = mullions; `roomW/roomH/roomDepth/bayW` m override 4.41/3.3/4.0/1.47 - repeat PITCHES of the fake-room grid (set to the real floor/bay pitch), not opening sizes; `roomOffsetX/roomOffsetZ` m shift the grid datum (default 0).
156
158
  </mesh_dsl_usage>
157
159
 
@@ -232,10 +234,16 @@ event OnSpawned {
232
234
  - Use TileGrid helpers for cheap walkable/not-walkable A* on tile coordinates. TileIds in returned paths are opaque Numbers; never decode them with `%` or `/`. Use `TileGridPathTile(Grid, TileId, OriginTile)` or `TileGridPathWorld(Grid, TileId, OriginTile)`.
233
235
  - `TileGridCreate(TilesX, TilesY, DefaultWalkable)` returns an opaque compact List. `TileGridCreate(TilesX, TilesY, DefaultWalkable, EdgeBlockingEnabled)` enables optional edge-wall storage when the Bool is true. Do not call generic mutating List functions (`Add`, `Set`, `Resize`, `Clear`, `Pop`, etc.) on it; use TileGrid helpers. Padded grid capacity is capped at 1,048,576 tiles.
234
236
  - Edge-blocking grids can use `TileGridSetEdgeBlocked(Grid, X1, Y1, X2, Y2, Blocked)` for cardinal-adjacent tile pairs. Compact grids reject SetEdgeBlocked; `TileGridIsEdgeBlocked(...)` returns false for valid compact-grid edges. Edge-enabled diagonal pathfinding does not cross blocked cardinal edges, and a diagonal step requires all four cardinal edges around the crossed 2x2 tile corner to be clear.
235
- - `BuildTileBlockedGridFromTag(OriginTile, TilesX, TilesY, BlockerTag)` creates a walkable grid and blocks tiles whose world-center point overlaps an object with the tag. Build/rebuild grids when blockers change, not every frame.
236
- - `TileGridSetWalkableFromStaticColliders(Grid, OriginTile, ZMin, ZMax)` re-rasterizes an existing non-layered grid from the static world colliders: every tile resets, and a tile blocks when any static collider's world AABB overlaps its rect within the [ZMin, ZMax] cm band (rotated colliders use their conservative AABB; colliders covering the whole grid footprint - floors, world bounds - are ignored). Keep ZMin above the walk surface (e.g. 20) so partial floor slabs don't block their tiles. Call once after building/editing static geometry - walls and crates then block FindPath without hand-authored SetWalkable loops; re-call after edits.
237
+ - `BuildTileBlockedGridFromTag(OriginTile, TilesX, TilesY, BlockerTag)` creates a walkable grid and blocks tiles whose world-center point overlaps an object with the tag - sampled on OriginTile.z's plane only, so blockers floating above/below it are missed (0 tiles blocked while tagged blockers exist = runtime error naming their z span). Volumetric blocking: TileGridSetWalkableFromStaticColliders (ZMin/ZMax) or TileGridStampObject. Build/rebuild grids when blockers change, not every frame.
238
+ - `TileGridSetWalkableFromStaticColliders(Grid, OriginTile, ZMin, ZMax)` re-rasterizes an existing grid from the static colliders: every tile resets, and a tile blocks when any static collider's world AABB overlaps its rect within the [ZMin, ZMax] cm band (rotated colliders use their conservative AABB; colliders covering the whole grid footprint - floors, world bounds - are ignored). Static world objects, static PhysicsObjects, and tilemap solid cells all block; keep ZMin above the walk surface AND above any solid ground tilemap's top (e.g. 20) so floor slabs don't block their tiles. Layered grids rasterize per layer ([ZMin, ZMax] relative to each layer plane). It RESETS every tile - call it BEFORE the FromTerrain pair; for runtime placements stamp instead of re-rastering.
239
+ - `TileGridSetWalkableFromTerrain(Grid, OriginTile, MaxSlope01)` marks tiles UNWALKABLE where the topmost terrain at the tile center is steeper than MaxSlope01 (slope01 = g/(1+g); 0.5 = 45deg; walkers wedge above ~0.5, so 0.4-0.45 is a safe unit ceiling) or absent. Subtractive only - never re-opens tiles.
240
+ - `TileGridSetEdgesFromTerrain(Grid, OriginTile, MaxStepCm)` (edge-blocking grids) blocks the edge between cardinal neighbors whose terrain height difference exceeds MaxStepCm: cliffs become impassable EDGES while rim tiles stay standable; graded ramps (small per-tile rise) stay open. Tile centers sample mid-cell, so a hard TierCm cliff reads as two TierCm/2 steps - MaxStepCm = TierCm/3 separates cliff jumps from ramp rise; size ramps >= 2 tiles of run per tier step so their slope stays below the ~45deg walk limit.
241
+ - Cliff-map load order (manager OnSpawned): collider raster -> FromTerrain -> EdgesFromTerrain -> BakeCrowdObstacles -> IsReachable asserts. Then placements only stamp.
242
+ - `TileGridStampRect(Grid, X1, Y1, X2, Y2, Blocked)` / `TileGridStampObject(Grid, OriginTile, Obj, Blocked)` stamp footprints incrementally (rect corners clamp to the grid; spawn: true, despawn: false re-opens the stamped rect - overlapping footprints must re-stamp their survivors) - cheaper than re-rastering after each placement.
243
+ - `TileGridIsReachable(Grid, X1, Y1, X2, Y2)` (layered: 7-arg form) = "does an 8-dir path exist" without building one - assert connectivity (spawn points, ramps) in a manager OnSpawned with `RaiseWorldError` so broken maps fail at load, not mid-game; also check before wall placements that could seal a region.
244
+ - `TileGridBakeCrowdObstacles(Grid, OriginTile)` bakes avoidance line obstacles from the grid's blocked edges and unwalkable borders so crowd units are never pushed off cliffs or into tilemap walls avoidance cannot see. It is a snapshot: re-bake after runtime walkability edits (opened gates, razed bridges); placed buildings already repel via their own colliders, no re-bake needed.
237
245
  - One grid, many movers (RTS): build the grid ONCE on a manager scene object (`var Grid: List<Number>` field; `TileGridCreate` + `TileGridSetWalkableFromStaticColliders` in its OnSpawned) and let every unit reach it through a scene cast - `TileGridFindPath8((Scene.Manager as HQ).Grid, ...)`. Cross-class field access works for List fields; never rebuild the grid per unit.
238
- - `TileGridFindPath4/8(Grid, StartX, StartY, GoalX, GoalY[, GoalToleranceTiles])` returns a reversed path List: Goal ... Start. Empty means blocked start/goal, out of bounds, or no path. GoalToleranceTiles (0-16) accepts the cheapest walkable tile within that ring of the goal - set it when ordering onto colliders (buildings, resource nodes); empty then means the ring itself is unreachable. Compact TileGridFindPath8 preserves corner cutting through unwalkable side tiles; edge-enabled grids still require crossed cardinal edges to be clear.
246
+ - `TileGridFindPath4/8(Grid, StartX, StartY, GoalX, GoalY[, GoalToleranceTiles])` returns a reversed path List: Goal ... Start. Empty means blocked start/goal, out of bounds, or no path (a TRUE verdict - the search budget covers the whole grid, so a no-path query floods the goal's component; on big maps gate mass orders with one TileGridIsReachable, share flow fields, and cache no-path results). GoalToleranceTiles (0-16) accepts the cheapest walkable tile within that ring of the goal - set it when ordering onto colliders (buildings, resource nodes); empty then means the ring itself is unreachable, and out-of-grid Start/Goal clamp to the nearest edge tile (a chase target that walked off the grid paths to the boundary instead of erroring). Compact TileGridFindPath8 preserves corner cutting through unwalkable side tiles; edge-enabled grids still require crossed cardinal edges to be clear.
239
247
  - `TileGridHasLineOfSight(Grid, StartX, StartY, GoalX, GoalY)` (layered: 7-arg form, same Z only) returns true when the straight tile-center corridor is fully walkable (crossed edges clear on edge grids; exact corner crossings also need both side tiles). Chasing a moving target: LOS true -> `MoveTowardContinuous` at the live position, false -> FindPath + follow.
240
248
  - `TileGridSmoothPath(Grid, Path)` returns a new reversed path with waypoints dropped wherever the straight corridor between the survivors is clear (string pulling; never smooths across a layer change). Walkers zigzagging tile centers -> smooth once after FindPath, before following.
241
249
  - To follow a path, call `MoveAlongTilePathContinuous(Path, Grid, OriginTile, Speed[, ArriveWithinCm[, OrientTurnRate]])` each frame: one call steps the mover, pops reached waypoints, and returns true once the path is consumed (false for an already-empty path). ArriveWithinCm (default 1) completes the FINAL waypoint within that distance - set it when the goal can be occupied (resource node, building) so contact does not stall arrival. OrientTurnRate faces the mover along its travel (deg/s; 0 = instant) - RTS vehicles read wrong without it. Prefer it over manual MoveToward + Pop loops; it is one sim call per mover per frame.
@@ -467,6 +475,7 @@ event OnSpawned {
467
475
  - PhysicsObject: like WorldObject, but starts as dynamic/CanCollide physics
468
476
  - CrowdObject: Useful as creatures/walkable-NPCs. like WorldObject, but starts with crowd collision avoidance
469
477
  - it steers around other crowd agents and obstacles it approaches at an angle; a blocker dead-ahead STOPS it (avoidance is anti-collision, not pathfinding) - route around structures with tile pathfinding
478
+ - RTS units: route with `MoveAlongTilePathContinuous` on a `crowd` receiver - the path sets the preferred velocity and avoidance shapes it every frame (global path + local separation). The zero-call `StartTilePathFollow` is waypoint-granular, so avoidance cannot shape it mid-segment - use it for overlap-tolerant swarms instead. Terrain cliffs and tilemap walls are invisible to avoidance until `TileGridBakeCrowdObstacles` bakes them from the nav grid.
470
479
  - Avoidance scope: XY-plane only; Z/height is ignored.
471
480
  - Gravity is ON at spawn; crowd bodies stand on static geometry, terrain, and tilemaps (not on dynamic objects). ClimbingCrowdObject remains the climb/stack-capable crowd.
472
481
  - For grid-based or fixed-lane games (e.g., Tower Defense), avoid using CrowdObject, as its built-in avoidance can cause objects to move off their intended path.
@@ -479,6 +488,7 @@ event OnSpawned {
479
488
  - Terrain + static primitive obstacles; supports elevator-like climbing
480
489
  - Can climb/stack on other climbers; large swarms may pile into a single moving blob
481
490
  - DisplayObject: like WorldObject but visual-only — no collision, no interaction events (Touched, ClickThisObject, etc. will never fire), doesn’t respond to forces
491
+ - When a display shell forms a player-reachable structure (building, wall), add a static collision core or invisible collider proxy behind it — display-only geometry is walked through.
482
492
  - EffectObject: visual effects
483
493
  - pointLight: local point light. `pointLight L { position = (0, 0, 150) radius = 500 intensity = 4 color = (1, 0.85, 0.6) }` - radius cm (default 100 = dim 1m pool); optional cast_shadow = true, light_diffuse_scale/light_specular_scale. For a bulb on a mesh prop, prefer an emitter(...) socket in the #mesh (see <mesh_dsl_usage>)
484
494
  - spotLight: cone along the object's +X facing (aim with rotation); pointLight keys plus cos_inner/cos_outer = cosine of the half-angle, not degrees (defaults 24deg/30deg)
@@ -630,6 +640,8 @@ Applies to all physics types: Dynamic, Static, and Kinematic.
630
640
  - `collision = mesh` objects keep mesh collision while static or moved as a kinematic platform (players ride them); giving one gravity or PreventOverlap drops it back to box collision.
631
641
  - SetCharacterPreventOverlap(true) gives a kinematic object fake-physics separation from CanCollide objects and supplies a gravity character's ground support: off on a player with gravity = falls through the floor
632
642
  - SetCharacterOverlapIgnoreTag(Tag, IsOn) makes this character's overlap resolution skip objects with that tag (selective ghosting, e.g. walk through Tag.Enemy while charging) without touching ground collision; Touched/regions still fire. Prefer it over toggling SetCharacterPreventOverlap or SetCanCollide for pass-through-some-objects behavior.
643
+ - Code-spawned character movers stack inside each other until SetCharacterPreventOverlap(true) (players ship with it on).
644
+ - Corpses: disable gravity BEFORE SetCanCollide(false) (a gravity character with no collision falls through the floor), and clear gameplay tags so queries/wave counters skip the body.
633
645
  </defaults>
634
646
 
635
647
  <movement_rules>
@@ -650,6 +662,7 @@ Applies to all physics types: Dynamic, Static, and Kinematic.
650
662
  - These continuous movers drive ONE frame of velocity then stop: call them every frame (a brain loop that Waits 0.2s between calls crawls at ~1/12 speed).
651
663
  - On gravity-affected characters (the PlayerObject default; EnableCharacterGravity(true) objects) the Z component of these calls is silently DISCARDED - gravity/jump owns vertical velocity, only X/Y apply, and the mover never lifts. Flying/hovering: EnableCharacterGravity(false) (players: SetPlayerModeHover); jumps: Jump(). Gravity-off and bodyless objects honor full 3D velocity.
652
664
  - Gravity characters auto-step rises up to 45cm (capped at 1/4 body height for small NPCs); taller needs a ramp or Jump()
665
+ - Gravity-off chasers that nose into the ground: LookAtHorizontal + MoveTowardContinuousHorizontal(Facing) - full-3D LookAt at a lower target pitches the body, and facing-driven movement follows it down.
653
666
  - To move somewhere over N seconds, use an explicit per-frame loop instead of a fire-and-forget helper:
654
667
  <example_of_move_over_time>
655
668
  var target = GetPosition().ShiftUp(300)
@@ -869,52 +882,52 @@ PrintTag(Tag: Number)
869
882
  PrintDivider()
870
883
  SetAutoGameLogOn()
871
884
  PlayerPrint(PlayerIndex: Number, Text: Text)
872
- SetSunIntensity(Intensity: Number) // Default: 4
885
+ SetSunIntensity(Intensity: Number) // Default: 4 [global: all clients]
873
886
  SetSunSpecularScale(Scale: Number) // Default: 1
874
- SetSunRotation(Rotation: Number) // Default: 10. Azimuth, degrees from +X toward +Y; shadows fall toward Rotation+180
875
- SetSunTilt(Tilt: Number) // Default: 46. Elevation above the horizon, degrees (90 = overhead)
887
+ SetSunRotation(Rotation: Number) // Default: 10. Azimuth, degrees from +X toward +Y; shadows fall toward Rotation+180 [global: all clients]
888
+ SetSunTilt(Tilt: Number) // Default: 46. Elevation above the horizon, degrees (90 = overhead) [global: all clients]
876
889
  SetSkybox(Skybox: Object)
877
890
  SetSkyboxHorizonTilt(AngleDegrees: Number) // Default: 0
878
891
  SetSkyboxRotation(RotationDegrees: Number) // Default: 0
879
- SetSkyboxIsNight(IsNight: Bool)
892
+ SetSkyboxIsNight(IsNight: Bool) // true swaps to the FIXED near-black night skybox - it ignores tint/haze, so it will not blend with fog (hard dark zenith). Night sky too black / seams against fog -> keep this false and build twilight: SetSunTilt near 0, dark SetSkyboxTint + SetSkyboxHaze, stars via SetSkyboxStarIntensity
880
893
  SetSkyboxSunVisible(Visible: Bool)
881
- SetSkyboxTint(Color: Vector)
882
- SetSkyboxSaturation(Saturation: Number) // Default: 1. With procedural sky, sky grade calls also re-tint the ambient lighting (IBL)
883
- SetSkyboxExposure(ExposureStops: Number) // Default: 0
884
- SetSkyLightIntensity(Intensity: Number) // Default: 2
885
- SetSkyLightColor(Color: Vector)
886
- SetSkyLightSaturation(Saturation: Number) // Default: 1
887
- SetBloomThreshold(Threshold: Number) // Default: 2
894
+ SetSkyboxTint(Color: Vector) [global: all clients]
895
+ SetSkyboxSaturation(Saturation: Number) // Default: 1. With procedural sky, sky grade calls also re-tint the ambient lighting (IBL) [global: all clients]
896
+ SetSkyboxExposure(ExposureStops: Number) // Default: 0 [global: all clients]
897
+ SetSkyLightIntensity(Intensity: Number) // Default: 2 [global: all clients]
898
+ SetSkyLightColor(Color: Vector) [global: all clients]
899
+ SetSkyLightSaturation(Saturation: Number) // Default: 1 [global: all clients]
900
+ SetBloomThreshold(Threshold: Number) // Default: 2 [global: all clients]
888
901
  SetBloomSoftKnee(SoftKnee: Number) // Default: 0.5
889
- SetBloomIntensity(Intensity: Number) // Default: 0.15
902
+ SetBloomIntensity(Intensity: Number) // Default: 0.15 [global: all clients]
890
903
  SetBloomClampValue(Clamp: Number) // Default: 1
891
- SetSsaoIntensity(Intensity01: Number) // Default: 1
892
- SetSsaoDistance(DistanceMeters: Number) // Default: 0.5
904
+ SetSsaoIntensity(Intensity01: Number) // Default: 1 [global: all clients]
905
+ SetSsaoDistance(DistanceMeters: Number) // Default: 0.5 [global: all clients]
893
906
  SetSsrLow()
894
907
  SetSsrHigh()
895
908
  SetSsrOff()
896
909
  SetSsrRoughnessBlurMultiplier(Multiplier: Number) // Default: 2
897
910
  SetSsrRoughnessMipClamp(LowerMip: Number, UpperMip: Number) // Default: 0, 0
898
911
  SetSsrIntensity(Intensity0To10: Number) // Default: 1
899
- SetShadowBlurRadius(Radius: Number) // Default: 2.8
912
+ SetShadowBlurRadius(Radius: Number) // Default: 2.8 [global: all clients]
900
913
  SetLocalShadowBlurRadius(Radius: Number) // Default: 12
901
914
  SetShadowDepthBiasConstant(Units: Number) // Default: 1
902
915
  SetShadowDepthBiasSlopeScale(Scale: Number) // Default: 2.5
903
- SetShadowOpacity(Opacity01: Number) // Default: 1
916
+ SetShadowOpacity(Opacity01: Number) // Default: 1 [global: all clients]
904
917
  SetStaticLodTransitions(Lod1Size: Number, Lod2Size: Number, Lod3Size: Number) // Default: 0.18, 0.07, 0.025
905
918
  SetStaticLodShadowTransitions(Lod1Size: Number, Lod2Size: Number, Lod3Size: Number) // Same screen-size units as SetStaticLodTransitions, but for meshes drawn into the sun-shadow maps (defaults higher: shadows tolerate earlier LOD). Lower toward the view values if a large caster's shadow silhouette looks low-poly or pops. Default: 0.35, 0.18, 0.08
906
- SetContrast(Contrast: Number) // Power curve around mid-gray, pre-tonemap: shadows compress, never crush to black. Default: 1 = neutral; 0 = flat gray, 2 = strong
907
- SetSaturation(Saturation: Number) // Saturation multiplier. Default: 1 = neutral; 0 = grayscale, 2 = vivid
908
- SetExposure(Exposure: Number) // EV stops, pre-tonemap: +1 = twice as bright, -1 = half. Default: 0
909
- SetShadowLift(Amount: Number) // Default: 2; 0 = off
910
- SetShadowLiftThreshold(Threshold: Number) // Default: 0.06
919
+ SetContrast(Contrast: Number) // Power curve around mid-gray, pre-tonemap: shadows compress, never crush to black. Default: 1 = neutral; 0 = flat gray, 2 = strong [global: all clients]
920
+ SetSaturation(Saturation: Number) // Saturation multiplier. Default: 1 = neutral; 0 = grayscale, 2 = vivid [global: all clients]
921
+ SetExposure(Exposure: Number) // EV stops, pre-tonemap: +1 = twice as bright, -1 = half. Default: 0 [global: all clients]
922
+ SetShadowLift(Amount: Number) // Default: 2; 0 = off [global: all clients]
923
+ SetShadowLiftThreshold(Threshold: Number) // Default: 0.06 [global: all clients]
911
924
  SetSmaaEdgesThreshold(Threshold01: Number) // Default: 0.01
912
925
  SetAdaptiveRenderQualityEnabled(Enabled: Bool) // Default: true. Renderer may temporarily drop SSR/SSAO/bloom on slow frames; false pins full quality
913
926
  SetGlobalMipBias(Bias: Number) // Default: 0. Mobile wasm applies its startup bias only; changing this later may not rebuild already-uploaded textures.
914
- SetVignetteStrength(Strength: Number) // Default: 0
915
- SetVignetteRadius(Radius: Number) // Default: 0.75
916
- SetVignetteSoftness(Softness: Number) // Default: 0.25
917
- SetVignetteColor(Color: Vector)
927
+ SetVignetteStrength(Strength: Number) // Default: 0 [global: all clients]
928
+ SetVignetteRadius(Radius: Number) // Default: 0.75 [global: all clients]
929
+ SetVignetteSoftness(Softness: Number) // Default: 0.25 [global: all clients]
930
+ SetVignetteColor(Color: Vector) [global: all clients]
918
931
  SetDefaultClimbingCrowdSpeed(Speed: Number)
919
932
  SetClimbingCrowdPaused(IsPaused: Bool) // Freeze climbingCrowd step (movement + depenetration/climb).
920
933
  SetClimbingCrowdSolveSteps(Steps: Number)
@@ -922,26 +935,26 @@ SetAllLocalShadowsEnabled(Enabled: Bool)
922
935
  SetAllDecalsEnabled(Enabled: Bool)
923
936
  SetGravity(Gravity: Number)
924
937
  SetTerminalVelocityZ(MaxFallSpeed: Number)
925
- SetFogStartDistance(StartDistance: Number) // Default: 10. Meters (not cm). The skybox is fogged only via SetFogSkyboxAffect or height fog; underwater, automatic murk overrides all fog settings
926
- SetFogEndDistance(EndDistance: Number) // Default: 600. Meters
927
- SetHeightFogEnabled(Enabled: Bool)
928
- SetHeightFogTop(Top: Number) // Default: 50. Meters
929
- SetHeightFogBottom(Bottom: Number) // Default: 0. Meters
930
- SetHeightFogSoftness(Softness: Number) // Default: 1
938
+ SetFogStartDistance(StartDistance: Number) // Default: 10. Meters (not cm). The skybox is fogged only via SetFogSkyboxAffect or height fog; underwater, automatic murk overrides all fog settings. One world value - per-player override: SetFogDistances [global: all clients]
939
+ SetFogEndDistance(EndDistance: Number) // Default: 600. Meters. One world value, every player - per-player override: SetFogDistances [global: all clients]
940
+ SetHeightFogEnabled(Enabled: Bool) [global: all clients]
941
+ SetHeightFogTop(Top: Number) // Default: 50. Meters [global: all clients]
942
+ SetHeightFogBottom(Bottom: Number) // Default: 0. Meters [global: all clients]
943
+ SetHeightFogSoftness(Softness: Number) // Default: 1 [global: all clients]
931
944
  SetGpuCullingDistance(DistanceMeters: Number) // Default: 0 (distance culling off)
932
945
  SetFrustumCulling(Enabled: Bool)
933
946
  SetFrustumCullingMargin(MarginMeters: Number) // Default: 0
934
947
  SetDecalCullingDistanceM(DistanceMeters: Number) // Default: 0
935
- SetGrassSpacingCm(SpacingCm: Number) // Default: 0 (auto)
936
- SetGrassTerrainActiveDistanceM(DistanceMeters: Number) // Default: 140
937
- SetGrassCullDistanceM(DistanceMeters: Number) // Default: 140
938
- SetGrassFadeDistancePercent(FadeBandPercent: Number) // Default: 50
939
- SetGrassFarThinningPower(Power: Number) // Default: 3
940
- SetTreeLodSwitchDistanceM(DistanceMeters: Number) // Leaf cards -> whole-tree impostor switch distance, desktop meters (mobile auto-scales down). Default: 0 = auto (140 / 90)
941
- SetTreeMeshDistanceM(DistanceMeters: Number) // Real branch-mesh max draw distance, desktop meters; impostors only beyond. Default: 0 = auto (400 / 260)
942
- SetTreeCullDistanceM(DistanceMeters: Number) // Trees vanish entirely past this, desktop meters (the outermost bound - it caps the mesh + leaf-switch ranges under it). Default: 0 = auto (800 / 300)
943
- SetTreeFadeDistancePercent(FadeBandPercent: Number) // Card->impostor crossfade band as % of the switch distance, clamped 5..80. Default: 36
944
- SetTreeFarLeafDensityPercent(DensityPercent: Number) // Leaf-card density kept across the fade band, clamped 10..300; <100 thins earlier (cheaper), >100 denser. Default: 100
948
+ SetGrassSpacingCm(SpacingCm: Number) // Default: 0 (auto) [global: all clients]
949
+ SetGrassTerrainActiveDistanceM(DistanceMeters: Number) // Default: 140 [global: all clients]
950
+ SetGrassCullDistanceM(DistanceMeters: Number) // Default: 140 [global: all clients]
951
+ SetGrassFadeDistancePercent(FadeBandPercent: Number) // Default: 50 [global: all clients]
952
+ SetGrassFarThinningPower(Power: Number) // Default: 3 [global: all clients]
953
+ SetTreeLodSwitchDistanceM(DistanceMeters: Number) // Leaf cards -> whole-tree impostor switch distance, desktop meters (mobile auto-scales down). Default: 0 = auto (140 / 90) [global: all clients]
954
+ SetTreeMeshDistanceM(DistanceMeters: Number) // Real branch-mesh max draw distance, desktop meters; impostors only beyond. Default: 0 = auto (400 / 260) [global: all clients]
955
+ SetTreeCullDistanceM(DistanceMeters: Number) // Trees vanish entirely past this, desktop meters (the outermost bound - it caps the mesh + leaf-switch ranges under it). Default: 0 = auto (800 / 300) [global: all clients]
956
+ SetTreeFadeDistancePercent(FadeBandPercent: Number) // Card->impostor crossfade band as % of the switch distance, clamped 5..80. Default: 36 [global: all clients]
957
+ SetTreeFarLeafDensityPercent(DensityPercent: Number) // Leaf-card density kept across the fade band, clamped 10..300; <100 thins earlier (cheaper), >100 denser. Default: 100 [global: all clients]
945
958
  SetAssetSubmeshHue(ModelAsset: Object, SubmeshIndex: Number, HueDegrees: Number)
946
959
  SetAssetSubmeshSaturation(ModelAsset: Object, SubmeshIndex: Number, Saturation: Number) // Chroma multiplier: 1 = neutral, 0 = grayscale
947
960
  SetAssetSubmeshBrightness(ModelAsset: Object, SubmeshIndex: Number, Brightness: Number) // Gain: 1 = neutral
@@ -969,7 +982,7 @@ Number.ToText() -> Text
969
982
  Bool.ToText() -> Text
970
983
  Position.ToText() -> Text
971
984
  ColorHex(Hex: Text) -> Position
972
- RandomNumber(From: Number, To: Number) -> Number
985
+ RandomNumber(From: Number, To: Number) -> Number // To exclusive; From == To returns From.
973
986
  RandomChancePercent(Percent: Number) -> Bool // Inside player input events: fully predictable (predicted result = final result). Elsewhere it returns false during client prediction (corrected on confirm), so use it only for delay-tolerant side effects like item drops.
974
987
  RandomPositionWithinRegion(Region: Object) -> Vector
975
988
  RandomPositionInDisc(Center: Position, Radius: Number) -> Vector
@@ -986,7 +999,7 @@ Number.Min(Other: Number) -> Number
986
999
  Number.Max(Other: Number) -> Number
987
1000
  Number.Clamp(Min: Number, Max: Number) -> Number
988
1001
  Number.Sign() -> Number
989
- Number.Sin() -> Number // Input is radians
1002
+ Number.Sin() -> Number // Sin/Cos/Tan take radians; SinDegree/CosDegree/TanDegree take degrees
990
1003
  Number.Cos() -> Number
991
1004
  Number.Tan() -> Number
992
1005
  Number.SinDegree() -> Number
@@ -1228,7 +1241,7 @@ Object.SetIsMouseLookOn(IsMouseLookOn: Bool)
1228
1241
  Object.SetMouseVisible(IsMouseVisible: Bool)
1229
1242
  Object.SetCrosshairVisible(IsCrosshairVisible: Bool)
1230
1243
  Object.SetOrientingWithCameraYaw(IsOrientingWithCameraYaw: Bool) // true: body yaw tracks camera every frame (aim/strafe mode), so a held/aimed weapon stays aligned with the body; takes precedence over Move*Facing calls' facing. Off by default: body only turns when moving.
1231
- Object.SetCameraPivotOffset(Offset: Vector)
1244
+ Object.SetCameraPivotOffset(Offset: Vector) // Replaces the whole pivot (default (0,-39,87)), not additive; camera-mode switches never restore it. Also live in first person (any mode with zoom <= 0): z=87 = native eye height, z=0 sits 87cm below the eye. Author crouch/stand as two absolute offsets.
1232
1245
  Object.SetCameraZoom(Distance: Number)
1233
1246
  Object.SetCameraFieldOfView(FieldOfView: Number)
1234
1247
  Object.SetCameraTiltDown(PitchDown: Number)
@@ -1364,7 +1377,7 @@ Object.SetWaterShallowColor(R: Number, G: Number, B: Number)
1364
1377
  Object.SetWaterDeepColor(RGB: Vector) // Deep-water tint.
1365
1378
  Object.SetWaterDeepColor(R: Number, G: Number, B: Number)
1366
1379
  Object.SetWaterColorMixRange(ShallowCm: Number, DeepCm: Number) // Depth range for shallow-to-deep tint.
1367
- Object.SetWaterTransparency(Alpha: Number) // Water alpha/refraction blend.
1380
+ Object.SetWaterTransparency(Clarity: Number) // 1 = clear (full refraction), 0 = opaque surface.
1368
1381
  Object.SetEmissionColor(RGB: Vector) // Glow tint; unset/near-black = glows in the object's own color
1369
1382
  Object.SetEmissionColor(R: Number, G: Number, B: Number) // Glow tint; unset/near-black = glows in the object's own color
1370
1383
  Object.SetEmissionIntensity(Intensity: Number) // Linear glow: 0 off, 1 soft self-lit, 4 lamp, 16+ neon bloom
@@ -1435,9 +1448,9 @@ Object.SetCameraLookAtThisFrame(Position: Position, LookAt: Position)
1435
1448
  Object.SetChaseCameraThisFrame(TargetPosition: Position, ForwardDirection: Vector, BackDistance: Number, Height: Number, LookAtHeight: Number) // Places camera at TargetPosition - normalize(ForwardDirection.xy)*BackDistance + Z*Height, looking at TargetPosition + Z*LookAtHeight
1436
1449
  Position.ExplosionShake(Frequency: Number) -> Position
1437
1450
  Object.FindChildUI(Name: Text) -> Object
1438
- SetSunColor(Color: Vector) // Default: (1, 1, 1) white
1451
+ SetSunColor(Color: Vector) // Default: (1, 1, 1) white [global: all clients]
1439
1452
  SetSunColor(R: Number, G: Number, B: Number)
1440
- SetFogColor(Color: Vector)
1453
+ SetFogColor(Color: Vector) [global: all clients]
1441
1454
  SetFogColor(R: Number, G: Number, B: Number)
1442
1455
  LoadWorldTransferClear()
1443
1456
  LoadWorldTransferPush(Value: Number)
@@ -1457,7 +1470,7 @@ AnyBasicType.NearestPlayerNonSpectator() -> Object
1457
1470
  SetSsrRoughnessFade(StartRoughness: Number, EndRoughness: Number) // Default: 0.68, 0.7
1458
1471
  SetSsrRayFade(NearFadePower: Number, FarFadePower: Number) // Default: 0.08, 0.8
1459
1472
  SetSkyboxHue(HueDegrees: Number) // Default: 0
1460
- SetSkyboxContrast(Contrast: Number) // Contrast multiplier. Default: 1 = neutral
1473
+ SetSkyboxContrast(Contrast: Number) // Contrast multiplier. Default: 1 = neutral [global: all clients]
1461
1474
  Hash2(X: Number, Y: Number, Seed: Number) -> Number // Deterministic [0,1): constant within each integer X/Y cell (see <procedural_generation>)
1462
1475
  ValueNoise2(X: Number, Y: Number, Seed: Number) -> Number // Deterministic smooth noise [0,1), X/Y in cell units
1463
1476
  Fbm2(X: Number, Y: Number, Octaves: Number, Seed: Number) -> Number // Deterministic fractal noise [0,1), Octaves 1..8
@@ -1478,7 +1491,7 @@ Object.ShowOutlineHighlight(Player: Object, ThicknessPixels: Number, Color: Vect
1478
1491
  Object.HideOutlineHighlight(Player: Object) // Removes this player's outline on caller (no-op if absent)
1479
1492
  Object.EnableLocalSelectionBox(BorderColor: Vector, FillColor: Vector, FillOpacity: Number, BorderWidthPixels: Number, MinDragPixels: Number) // PlayerObject only. Enables a visual-only local drag box for this player; gameplay selection should use Event.MouseDownPosition/Event.MousePosition
1480
1493
  Object.DisableLocalSelectionBox() // PlayerObject only. Disables the visual-only local drag box
1481
- Object.EnableLocalWeaponView(Offset: Position, RotationDegrees: Vector, Scale: Number) // PlayerObject only. Renders this player's equipped weapon as a local first-person camera-attached visual for the owning client (active only in first-person camera). Offset is camera-local cm (+X right, +Y up, +Z forward); RotationDegrees (0,0,0) = barrel forward; e.g. (Position(15, -25, 32), Vector(2, 4, 0), 1.0) for an FPS-style close lower-right framing (a close-in gun keeps the auto-arms shoulder area off-screen). Visual-only; gameplay still uses EquipWeapon/GetHeldWeapon.
1494
+ Object.EnableLocalWeaponView(Offset: Position, RotationDegrees: Vector, Scale: Number) // PlayerObject only. Renders this player's equipped weapon as a local first-person camera-attached visual for the owning client (active only in first-person camera). Offset is camera-local cm (+X right, +Y up, +Z forward); RotationDegrees is a first-person camera tilt, (0,0,0) = barrel forward (third person seats the weapon on the hand frame + grip anchor, not on this value); e.g. (Position(15, -25, 32), Vector(2, 4, 0), 1.0) for an FPS-style close lower-right framing (a close-in gun keeps the auto-arms shoulder area off-screen). Visual-only; gameplay still uses EquipWeapon/GetHeldWeapon.
1482
1495
  Object.DisableLocalWeaponView() // PlayerObject only. Disables the local first-person weapon visual
1483
1496
  Object.GetWeaponAnchorWorldDir(AnchorName: Text) -> Vector // Anchor local +X (forward) transformed to world space
1484
1497
  Object.GetWeaponAnchorWorldUp(AnchorName: Text) -> Vector // Anchor local +Z transformed to world space
@@ -1508,19 +1521,19 @@ Object.PressAIAction(Action: Number) // Bot action tap (Action.Jump etc). Down f
1508
1521
  Object.DespawnAIPlayer() // Removes a bot (errors on real players). Plain Destroy() also works on bots
1509
1522
  Object.SetTerrainGrass(Model: Object, Material: Object) // Terrain only; Model: Ori.model.* or Ori.model.mesh.* (#mesh blade), None = built-in grass (tuft cards; see SetTerrainGrassStyle); Material: Material.X (#texture auto-material) or None = built-in atlas (usually enough; colors come from the grass knobs). On tuft cards the material's texture replaces the built-in card atlas (2x2 variant cells, uv+clamp+cutout; greyscale luminance = root->tip gradient, color still comes from the grass color knobs). Per-terrain (each terrain can have its own grass style)
1510
1523
  Object.SetTerrainGrassWeightmap(Material: Object) // Terrain only; Material: #texture auto-material; R channel of its color = grass density 0..1 across the terrain; None clears (full density). Overrides #terrain_splat out.grass; prefer out.grass when density should follow the terrain (height/slope), since a #texture cannot see it
1511
- Object.SetWeaponConfig(WeaponModel: Object, IdleAnim: Object, ReloadAnim: Object, FireAnim: Object, ForegripAnchor: Text, GripAnchor: Text, MuzzleAnchor: Text, FireInterval: Number, ReloadDuration: Number) // Register per-weapon-model TPS config. IdleAnim auto-plays as upper-body loop on EquipWeapon (if no upper animation is active); anims accept InvalidId = off. Anchor names may be "" = built-in defaults (foregrip/grip). FireInterval/ReloadDuration are seconds, readable via GetWeaponFireInterval/GetWeaponReloadDuration for script fire loops.
1524
+ Object.SetWeaponConfig(WeaponModel: Object, IdleAnim: Object, ReloadAnim: Object, FireAnim: Object, ForegripAnchor: Text, GripAnchor: Text, MuzzleAnchor: Text, FireInterval: Number, ReloadDuration: Number) // Register per-weapon-model held-weapon config. IdleAnim auto-plays as upper-body loop on EquipWeapon (if no upper animation is active); anims accept InvalidId = off. Anchor names may be "" = built-in defaults (foregrip/grip). GripAnchor seats third-person AND the viewmodel; no foregrip anchor on the model = support hand dropped = one-handed hold. FireInterval/ReloadDuration are seconds, readable via GetWeaponFireInterval/GetWeaponReloadDuration for script fire loops.
1512
1525
  Object.GetWeaponFireInterval(WeaponModel: Object) -> Number // Seconds between shots from the weapon model's SetWeaponConfig (0 when unset)
1513
1526
  Object.GetWeaponReloadDuration(WeaponModel: Object) -> Number // Reload seconds from the weapon model's SetWeaponConfig (0 when unset)
1514
1527
  Object.SetEmitting(IsOn: Bool) // EffectObject only. false: stop spawning new particles (existing ones finish while still following the emitter); true: resume. Emitter stays alive.
1515
1528
  Object.DestroyAfterParticles() // EffectObject only. Stops emission, keeps emitter following until existing particles finish, then destroys it. Use instead of Destroy() for attached looping VFX (e.g. thrusters).
1516
1529
  Object.DestroyImmediate() // EffectObject only. Destroys the emitter and hard-clears its live particles instantly (no dying tail).
1517
1530
  Object.ShowSelectionRing(Player: Object, Radius: Number, Color: Vector, ZOffset: Number) // As 3-arg; ZOffset cm shifts ring vertically from feet (negative grounds a flying unit's ring)
1518
- SetSkyboxCloudCoverage(Coverage: Number) // Procedural sky only (no SetSkybox asset). Default: 0.1; 0 = clear sky, 1 = overcast
1519
- SetSkyboxHaze(Haze: Number) // Procedural sky only. Default: 0.5; 0.3 = crisp alpine air, 2-3 = hazy horizon
1520
- SetSkyboxStarIntensity(Intensity: Number) // Night star overlay brightness; visible only with the sun near/below the horizon or SetSkyboxIsNight(true). Default: 1; 0 = no stars
1531
+ SetSkyboxCloudCoverage(Coverage: Number) // Procedural sky only (no SetSkybox asset). Default: 0.1; 0 = clear sky, 1 = overcast [global: all clients]
1532
+ SetSkyboxHaze(Haze: Number) // Procedural sky only. Default: 0.5; 0.3 = crisp alpine air, 2-3 = hazy horizon [global: all clients]
1533
+ SetSkyboxStarIntensity(Intensity: Number) // Night star overlay brightness; visible only with the sun near/below the horizon or SetSkyboxIsNight(true). Default: 1; 0 = no stars [global: all clients]
1521
1534
  SetSkyboxCloudDetail(Detail: Number) // Procedural sky only. Cloud fractal detail. Default: 1; 0 = soft blobs, 2 = max wispy detail
1522
1535
  SetSkyboxCloudScale(Scale: Number) // Procedural sky only. Cloud pattern size. Default: 1; 0.5 = big clouds, 2 = many small clouds
1523
- SetSkyboxGroundColor(Color: Vector) // Procedural sky only. Ground-bounce light color lighting surfaces from below. Default: (0.34, 0.44, 0.32) dim green; brightness follows the sky
1536
+ SetSkyboxGroundColor(Color: Vector) // Procedural sky only. Ground-bounce light color lighting surfaces from below. Default: (0.34, 0.44, 0.32) dim green; brightness follows the sky [global: all clients]
1524
1537
  SetSkyBillboardMaterial(Slot: Number, Material: Object) // Textured quad composited into the sky (moon/galaxy/gate). Slot 0..3. Samples the material's texture0 (e.g. a #texture color map); None clears. Show with SetSkyBillboardSize
1525
1538
  SetSkyBillboardDirection(Slot: Number, RotationDegrees: Number, TiltDegrees: Number) // Where in the sky (same convention as SetSunRotation/SetSunTilt). Default: 0, 45
1526
1539
  SetSkyBillboardSize(Slot: Number, AngleDegrees: Number) // Angular size in degrees (moon is ~0.5, use 5-20 for a large moon). Default: 0 = hidden
@@ -1529,7 +1542,7 @@ SetSkyBillboardIntensity(Slot: Number, Intensity: Number) // Default: 1; >1 glow
1529
1542
  SetSkyBillboardRoll(Slot: Number, RollDegrees: Number) // Rotation around the view direction. Default: 0
1530
1543
  SetSkyBillboardAdditive(Slot: Number, IsAdditive: Bool) // true = additive glow blend (galaxy/gate), false = alpha over sky (moon). Default: false
1531
1544
  Object.SetTerrainSplat(SplatRules: Text) // Terrain only; SplatRules: #terrain_splat block name; baked RGB weights replace slope/height auto-blend for the SetTerrainLayers materials (R=Steep slot, G=High, B=Low; base = leftover); rules may also assign out.grass = grass density, or out.albedo = final color (colormap mode; replaces layer blending entirely). "" clears
1532
- SetWaterPlanarReflection(Strength: Number, Distortion: Number) // Mirror reflection of the scene on the GLOBAL water surface (SetWaterEnabled) only; placed water meshes always use skybox reflections. Strength 0 disables, Distortion scales wave wobble. Defaults: 0.7, 0.3
1545
+ SetWaterPlanarReflection(Strength: Number, Distortion: Number) // Mirror reflection of the scene on the GLOBAL water surface (SetWaterEnabled) only; placed water meshes always use skybox reflections. Strength 0 disables, Distortion scales wave wobble. Defaults: 0.7, 0.3 [global: all clients]
1533
1546
  Object.SetHoverHPBarMaterial(Material: Object) // Custom look for caller's hover HP bar; Material.X (#shader or #texture auto-material), None reverts to default. #shader gets ctx.fraction/ctx.background_color and draws the whole bar as one quad (textures don't squash). Persists across SetHoverHPBar updates; ClearHoverBars removes it
1534
1547
  Object.SetHoverSPBarMaterial(Material: Object) // Same as SetHoverHPBarMaterial for the hover SP bar
1535
1548
  Object.SetHoverBarMaterial(BarIndex: Number, Material: Object) // Custom look for caller's SetHoverBar bar at BarIndex (0..=29); Material.X or None reverts to default. See SetHoverHPBarMaterial for the #shader contract
@@ -1541,13 +1554,13 @@ Object.SetUiScrollOffset(X: Number, Y: Number) // Container (frame/vStack/hStack
1541
1554
  Object.GetUiScrollOffsetX() -> Number
1542
1555
  Object.GetUiScrollOffsetY() -> Number
1543
1556
  Object.SetTerrainGrassHeightCm(HeightCm: Number) // Terrain only; average blade height in cm for this terrain (default 28, clamped 1..300). Global Min/Max Height rescale it proportionally; custom #mesh grass is scaled by HeightCm/28
1544
- SetGrassWindStrengthCm(AmplitudeCm: Number) // Global grass tip sway amplitude in cm at default height; taller grass sways proportionally more (default 4, 0 = still air, clamped 0..200)
1557
+ SetGrassWindStrengthCm(AmplitudeCm: Number) // Global grass tip sway amplitude in cm at default height; taller grass sways proportionally more (default 4, 0 = still air, clamped 0..200) [global: all clients]
1545
1558
  Object.SetTerrainGrassStyle(Style: Number) // Terrain only; built-in grass look: 0 = alpha-cut tuft cards (default, cheap, mobile-safe), 1 = geometry blades (much heavier; pair with SetGrassSpacingCm for dense hero fields). Ignored when a custom grass Model is set
1546
- SetGrassRootColor(Color: Vector) // Built-in grass (cards/blades) root color, sRGB 0..1; blades gradient root->tip. Default #41591c
1547
- SetGrassBrightnessVariationPercent(Percent: Number) // Global per-tuft/per-clump brightness randomness (+-) in percent (100 = default, 0 = uniform, clamped 0..300)
1548
- SetGrassHeightMinCm(HeightCm: Number) // Global grass height in wave troughs, cm (default 20, clamped 0..300). Pair with SetGrassHeightMaxCm; equal values = flat even field. Local average height (soft envelope): per-tuft randomness still spreads around it
1549
- SetGrassTipColor(Color: Vector) // Built-in grass (cards/blades) tip color, sRGB 0..1. Default #93b944
1550
- SetWind(DirectionDeg: Number, Strength01: Number, Gustiness01: Number) // Default: 30, 0.3, 0.5. Renderer-only sway (trees/leaves); strength 0 stills the air
1559
+ SetGrassRootColor(Color: Vector) // Built-in grass (cards/blades) root color, sRGB 0..1; blades gradient root->tip. Default #41591c [global: all clients]
1560
+ SetGrassBrightnessVariationPercent(Percent: Number) // Global per-tuft/per-clump brightness randomness (+-) in percent (100 = default, 0 = uniform, clamped 0..300) [global: all clients]
1561
+ SetGrassHeightMinCm(HeightCm: Number) // Global grass height in wave troughs, cm (default 20, clamped 0..300). Pair with SetGrassHeightMaxCm; equal values = flat even field. Local average height (soft envelope): per-tuft randomness still spreads around it [global: all clients]
1562
+ SetGrassTipColor(Color: Vector) // Built-in grass (cards/blades) tip color, sRGB 0..1. Default #93b944 [global: all clients]
1563
+ SetWind(DirectionDeg: Number, Strength01: Number, Gustiness01: Number) // Default: 30, 0.3, 0.5. Renderer-only sway (trees/leaves); strength 0 stills the air [global: all clients]
1551
1564
  TerrainHeightsNoise(Heights: List, SamplesX: Number, SamplesY: Number, Mode: Number, ScaleCells: Number, Octaves: Number, Seed: Number, AmplitudeCm: Number, Gain: Number) // Overwrite Heights with noise (see <terrain_generation>). Mode 0=fbm 1=ridged(mountains) 2=billow(dunes) 3=voronoi(mesas) 4=gradient/perlin(smooth equal-sized rounded hills; zero-mean - via AddNoise it adds SIGNED detail, no mean shift); ScaleCells=feature size; Gain=per-octave amplitude factor, 0=default 0.5 (0.1=near-mono smooth base, 0.95=equal-energy rough detail)
1552
1565
  TerrainHeightsAddNoise(Heights: List, SamplesX: Number, SamplesY: Number, Mode: Number, ScaleCells: Number, Octaves: Number, Seed: Number, AmplitudeCm: Number, Gain: Number) // Same but adds on top (detail layers)
1553
1566
  TerrainHeightsIslandFalloff(Heights: List, SamplesX: Number, SamplesY: Number, StartRadius01: Number, EdgeNoise01: Number, Seed: Number) // Multiply by radial mask fading to 0 at edge — islands. StartRadius01/EdgeNoise01 are 0..1 fractions (NOT cells; errors outside 0..1). EdgeNoise01 makes the coast ragged (0=circle, ~0.3 natural)
@@ -1577,11 +1590,12 @@ Voronoi2(X: Number, Y: Number, Seed: Number) -> Number // Deterministic cellular
1577
1590
  TerrainHeightsGradePath(Heights: List, SamplesX: Number, SamplesY: Number, PointsXYCells: List, WidthCells: Number, HeightStartCm: Number, HeightEndCm: Number, BlendCells: Number) // Flatten a graded road/ramp along polyline: flatten height lerps HeightStartCm->HeightEndCm over the path arc length — climbing roads/trails (FlattenPath = equal ends)
1578
1591
  TerrainScatterOnMask(PointsXYOut: List, Mask: List, SamplesX: Number, SamplesY: Number, Count: Number, MinSpacingCells: Number, Seed: Number) // Deterministic scatter: up to Count (<=10000) points into PointsXYOut (must be [], filled flat x0,y0,.. fractional cells), Mask 0..1 = accept probability, MinSpacingCells apart; tight mask/spacing may yield fewer — tree/rock/prop placement
1579
1592
  Object.SetTerrainSplatMask(Mask: List, SamplesX: Number, SamplesY: Number) // Terrain only; copies a 0..1 mask (must be SamplesX*SamplesY = terrain grid) into the `user` input plane of #terrain_splat rules (flow mask = wet dirt in gullies etc.); [] clears. Set in OnSpawned; not persisted with baked terrain
1580
- SetGrassWavePeriodCm(PeriodCm: Number) // Global meadow-wave feature size in cm (default 700 = ~7m waves, 2000 = broad swells, 300 = choppy; clamped 100..3000)
1581
- SetGrassSizeVariationPercent(Percent: Number) // Global per-tuft/per-clump height randomness (+-) in percent (100 = default, 0 = even height, clamped 0..300)
1582
- SetGrassHeightMaxCm(HeightCm: Number) // Global grass height on wave crests, cm (default 90, clamped 0..300). Brightness ripple + ground mottle auto-follow the Min..Max swing
1583
- SetGrassWindSpeedPercent(Percent: Number) // Global grass wind animation speed (gust drift + sway phase) in percent (100 = default, clamped 0..500). Adjusting it never pops: phase accumulates
1584
- SetGrassBladeWidthPercent(Percent: Number) // Built-in grass blade/tuft width in percent (100 = default, clamped 10..400). Width already auto-follows height so the texture never stretches; this is the extra wispy-vs-lush override
1593
+ SetGrassWavePeriodCm(PeriodCm: Number) // Global meadow-wave feature size in cm (default 700 = ~7m waves, 2000 = broad swells, 300 = choppy; clamped 100..3000) [global: all clients]
1594
+ SetGrassSizeVariationPercent(Percent: Number) // Global per-tuft/per-clump height randomness (+-) in percent (100 = default, 0 = even height, clamped 0..300) [global: all clients]
1595
+ SetGrassHeightMaxCm(HeightCm: Number) // Global grass height on wave crests, cm (default 90, clamped 0..300). Brightness ripple + ground mottle auto-follow the Min..Max swing [global: all clients]
1596
+ SetGrassWindSpeedPercent(Percent: Number) // Global grass wind animation speed (gust drift + sway phase) in percent (100 = default, clamped 0..500). Adjusting it never pops: phase accumulates [global: all clients]
1597
+ SetGrassBendStrengthPercent(Percent: Number) // Terrain-grass player-bend strength in percent (100 = default parting, 0 = grass stays still around players - stealth/hide-in-grass; clamped 0..200) [global: all clients]
1598
+ SetGrassBladeWidthPercent(Percent: Number) // Built-in grass blade/tuft width in percent (100 = default, clamped 10..400). Width already auto-follows height so the texture never stretches; this is the extra wispy-vs-lush override [global: all clients]
1585
1599
  Object.SetUiDraggable(IsOn: Bool) // UI element only. Enable engine drag: press + small move starts a drag (UiDragStart), release fires UiDrop; a real drag suppresses ClickButton. Markup equivalent: draggable=true
1586
1600
  ItemName(Item: Object) -> Text // Item def's display name (Item.X handle); "" if not an item
1587
1601
  ItemTip(Item: Object) -> Text // Item def's tooltip text; "" if not an item
@@ -1618,16 +1632,16 @@ Text.Length() -> Number // Character count (chars, not bytes - Thai etc. count p
1618
1632
  Text.Substring(Start: Number, Count: Number) -> Text // Chars [Start, Start+Count), 0-based, clamped to the text; negative Start or Count <= 0 -> empty Text.
1619
1633
  SetOcclusionCulling(Enabled: Bool) // Default: false (experimental Hi-Z occlusion culling)
1620
1634
  TerrainHeightsErosionFilter(Heights: List, SamplesX: Number, SamplesY: Number, CellCm: Number, ScaleCells: Number, Octaves: Number, StrengthCm: Number, Seed: Number, Mask: List, RidgeMapOut: List) // Stateless erosion filter (Phacelle gullies, no droplet sim): slope-aligned V-gullies + dendritic ridges; altitude fade keeps peaks sharp and valley floors intact. ScaleCells=largest gully size, StrengthCm=max carve/raise, Octaves 1..8, Mask=0..1 weights ([]=all), RidgeMapOut (pass [] List, auto-sized) 0..1: 0=crease 1=ridge (splat/tree/drainage rules). The go-to eroded-mountain look. Heavy: cost ~ sx*sy*Octaves (513 grid + 5 octaves = noticeable load time; prefer <=257 grids or <=4 octaves when loads must stay snappy)
1621
- SetTerrainErosionDetailPercent(Percent: Number) // Global display-only knob: scales the GPU sub-cell erosion-gully detail on all terrain surfaces, and the displayed gully depth of #terrain recipe terrains (100 = default, clamped 0..300, 0 = smooth). Visual only — collision/heights unchanged; grass follows the displayed surface automatically
1635
+ SetTerrainErosionDetailPercent(Percent: Number) // Global display-only knob: scales the GPU sub-cell erosion-gully detail on all terrain surfaces, and the displayed gully depth of #terrain recipe terrains (100 = default, clamped 0..300, 0 = smooth). Visual only — collision/heights unchanged; grass follows the displayed surface automatically [global: all clients]
1622
1636
  TerrainHeightsOriErosion(Heights: List, SamplesX: Number, SamplesY: Number, CellCm: Number, BaseScaleCells: Number, ErosionScaleCells: Number, Octaves: Number, StrengthCm: Number, SlopeStrength: Number, BranchStrength: Number, Seed: Number, Mask: List, ErosionMapOut: List) // OriErosion directional erosion (the #terrain recipe engine as a bulk op; docs/ori_erosion_spec.md): cos-wave gullies steered by the base slope with per-octave branch feedback. BaseScaleCells = base-noise feature size (for slope direction recovery), ErosionScaleCells = first-octave gully size, SlopeStrength ~3, BranchStrength ~0.5, StrengthCm = carve depth. Mask scales accumulation ([] = full); note masked zones sink ~0.5*StrengthCm (water datum). ErosionMapOut (pass [] List, auto-sized) = hx*0.5+0.5 for splat user-plane coloring
1623
1637
  SetTerrainDisplayExtension(RadiusM: Number) // Display-only: renders procedural terrain BEYOND the sim grid out to RadiusM (0 = off), no collision. The generator params come from the world's #terrain block (required; errors without one) — build the sim grid with TerrainHeightsFromTerrain from the same block and the extension continues it seamlessly. Pair with SetCameraFarDistanceM to actually see it
1624
1638
  SetCameraFarDistanceM(Meters: Number) // Display-only camera far plane in meters; 0 = engine default 1000, else clamped 1000..8000. Distant terrain needs SetFogEndDistance raised too; light clustering keeps near-field tuning; static geometry keeps sun shadows to ~2km (cached far layer; desktop)
1625
1639
  Object.SpawnDamageNumber(Amount: Number) // Damage number above caller: pop-arc motion, world-scaled, size grows with Amount; rounds to integer. Call from WasAttacked with Event.Damage. For custom look use the 5-arg SpawnFloatingText overload
1626
1640
  Object.SpawnFloatingText(Text: Text, Color: Vector, SizeScale: Number, Motion: Number, Anchor: Number) // Styled overload: SizeScale multiplies text size; Motion 0=RiseFade 1=PopArc 2=Sticky 3=BounceLand; Anchor 0=constant screen size 1=scales with camera distance
1627
1641
  SetDefaultFloatingTextFont(Font: Object) // World default font for SpawnFloatingText/SpawnDamageNumber (e.g. Ori.font.google.Lobster); None reverts to built-in
1628
- SetWaterEnabled(Enabled: Bool, SeaLevelCm: Number) // THE main water: global displaced ocean surface (Gerstner waves) at SeaLevelCm height. One per world; use Object.SetIsWater meshes for extra pools/streams at other heights (still by default; Object.SetWaterFlow makes streams/falls). Default: off. Camera below the ocean or a flat SetIsWater top gets auto underwater murk (tint follows SetWaterShallowColor/DeepColor)
1629
- SetWaterWaves(AmplitudeCm: Number, WavelengthCm: Number, Steepness01: Number, DirectionDeg: Number, SpeedPercent: Number) // Ocean swell. AmplitudeCm = total wave height budget, WavelengthCm = dominant wavelength, Steepness01 = chop (near 1 = sharp crests), DirectionDeg = travel direction, SpeedPercent = phase speed (100 = physical dispersion). Defaults: 60, 4000, 0.65, 0, 100
1630
- SetWaterColors(ShallowRGB: Vector, DeepRGB: Vector, MixRangeCm: Number, Transparency01: Number) // Ocean tints. MixRangeCm = water depth over which ShallowRGB blends to DeepRGB, Transparency01 = refraction mix. Defaults: (0.18,0.56,0.53), (0.04,0.16,0.24), 300, 0.9
1642
+ SetWaterEnabled(Enabled: Bool, SeaLevelCm: Number) // THE main water: global displaced ocean surface (Gerstner waves) at SeaLevelCm height. One per world; use Object.SetIsWater meshes for extra pools/streams at other heights (still by default; Object.SetWaterFlow makes streams/falls). Default: off. Camera below the ocean or a flat SetIsWater top gets auto underwater murk (tint follows SetWaterShallowColor/DeepColor) [global: all clients]
1643
+ SetWaterWaves(AmplitudeCm: Number, WavelengthCm: Number, Steepness01: Number, DirectionDeg: Number, SpeedPercent: Number) // Ocean swell. AmplitudeCm = total wave height budget, WavelengthCm = dominant wavelength, Steepness01 = chop (near 1 = sharp crests), DirectionDeg = travel direction, SpeedPercent = phase speed (100 = physical dispersion). Defaults: 60, 4000, 0.65, 0, 100 [global: all clients]
1644
+ SetWaterColors(ShallowRGB: Vector, DeepRGB: Vector, MixRangeCm: Number, Transparency01: Number) // Ocean tints. MixRangeCm = water depth over which ShallowRGB blends to DeepRGB, Transparency01 = refraction mix. Defaults: (0.18,0.56,0.53), (0.04,0.16,0.24), 300, 0.9 [global: all clients]
1631
1645
  TerrainHeightsFromTerrain(Heights: List, RidgesOut: List, SamplesX: Number, SamplesY: Number, CellSizeCm: Number) // Fill Heights from the world's #terrain recipe block (gradient base -> height mask -> erosion; errors without a #terrain block): the one-call way to build a terrain whose SetTerrainDisplayExtension continuation is exactly seamless. RidgesOut (pass [] List, auto-sized) = 0..1 erosion ridge map for splat user-plane coloring. CellSizeCm must match the SpawnTerrainFromHeights cell size (the recipe's cm values are absolute)
1632
1646
  Object.SetTerrainGrassSpawnMaterial(Material: Object) // Terrain only; Material: material with a #shader - a CUSTOM grass spawn COMPUTE shader replacing the default density logic (writes GrassInstance directly; can call ori_terrain_display_height for the rendered surface incl. recipe terrains). None clears. For procedural per-point density (e.g. recipe worlds where a baked weightmap can't extend)
1633
1647
  Object.SetTerrainSurfaces(SurfacesName: Text) // Terrain only; SurfacesName: #terrain_surfaces block name (up to 8 tiled PBR surfaces packed into texture arrays; lines `surface = <albedo>, <normal>, <tiling_m>[, <orm>[, <grass01>]]` - optional orm alpha carries height for crisp height-blended transitions; optional grass01 = grass density factor on that surface (default 1 for the first surface, 0 for the rest, so grass skips rock/snow); pair with SetTerrainSurfaceWeightsMaterial for per-texel weights). "" clears
@@ -1661,7 +1675,7 @@ Vector.RotateByEuler(Yaw: Number, Pitch: Number, Roll: Number) -> Vector // Rota
1661
1675
  Vector.ToYawPitch() -> Vector // Treat this vector as a direction: returns Vector(yaw, pitch, 0) in degrees. Yaw 0 = +X (counter-clockwise toward +Y), pitch positive = up. Zero-length input gives (0, 0, 0)
1662
1676
  YawPitchToDirection(Yaw: Number, Pitch: Number) -> Vector // Unit direction from aim angles in degrees (inverse of ToYawPitch): yaw 0 = +X, pitch positive = up
1663
1677
  SetDefaultFont(Font: Object) // World default font for all UI text/buttons that don't set one (e.g. Ori.font.google.Fredoka); None reverts to the engine default (Nunito)
1664
- SetModelAnchor(Model: Object, AnchorName: Text, LocalPosition: Position, LocalRotationEulerDegrees: Vector) // Weapon sits wrong in the hand / anchor misplaced -> define or replace any named anchor ("grip", "muzzle", custom): model-root local, cm Z-up, rotation maps anchor axes (+X = forward) into model axes; wins over the asset's own anchors, call before or after EquipWeapon
1678
+ SetModelAnchor(Model: Object, AnchorName: Text, LocalPosition: Position, LocalRotationEulerDegrees: Vector) // Weapon sits wrong in the hand / anchor misplaced -> define or replace any named anchor ("grip", "muzzle", custom): model-root local, cm Z-up, rotation maps anchor axes (+X = forward) into model axes; wins over the asset's own anchors, call before or after EquipWeapon; a grip anchor seats BOTH the third-person hold and the EnableLocalWeaponView viewmodel
1665
1679
  SwitchStage(Name: Text) // `#stage` projects only: switch to another stage of this project (multiplayer-safe; all stages ship in the project source, so Name may be dynamic). Use LoadWorldTransferPush before switching to carry values across.
1666
1680
  Object.SetRenderOffset(OffsetCm: Vector, RotationEulerDegrees: Vector, Scale: Number) // World/display/player objects only (crowds/instance batches reject). Visual-only offset on top of the sim transform (bob/lean/sway); colliders/AI/queries unaffected. OffsetCm shifts in WORLD space (not rotated into the object's local frame); rotation composes after the object's own and pivots at the object CENTER (SetRotation pivots at origin = ref-box bottom-center). Call per-frame for procedural animation; ClearRenderOffset resets
1667
1681
  Object.ClearRenderOffset() // Remove this object's visual render offset
@@ -1669,7 +1683,7 @@ Object.RaycastObject(Origin: Position, Direction: Vector, MaxDistance: Number) -
1669
1683
  Object.RaycastObjectWithTag(Origin: Position, Direction: Vector, MaxDistance: Number, Tag: Number) -> Object // RaycastObject limited to objects carrying Tag
1670
1684
  Object.RaycastObjectIgnoreTag(Origin: Position, Direction: Vector, MaxDistance: Number, IgnoreTag: Number) -> Object // RaycastObject that skips objects carrying IgnoreTag (e.g. ignore pickups/projectiles)
1671
1685
  Object.RaycastPosition(Origin: Position, Direction: Vector, MaxDistance: Number) -> Position // Impact point of RaycastObject's ray; on miss returns Origin + Direction.GetNormal() * MaxDistance
1672
- SetTerrainNormalStrengthPercent(Percent: Number) // Display-only scale on the terrain surface texture normal (#terrain_surfaces worlds); 0 = flat, 100 = authored strength. Default: 100
1686
+ SetTerrainNormalStrengthPercent(Percent: Number) // Display-only scale on the terrain surface texture normal (#terrain_surfaces worlds); 0 = flat, 100 = authored strength. Default: 100 [global: all clients]
1673
1687
  PlaySoundAtPosition(Sound: Object, Position: Position, Volume: Number) // One-shot at a world position: each client hears it attenuated and stereo-panned from its own camera (hearing radius 3000cm; silent beyond). Use for gunshots/impacts/pickups; plain PlaySound is for global UI/music
1674
1688
  PlaySoundAtPosition(Sound: Object, Position: Position, Volume: Number, HearingRadiusCm: Number) // PlaySoundAtPosition with an explicit hearing radius in cm; volume fades quadratically to 0 at the radius
1675
1689
  TileGridHasLineOfSight(Grid: List, StartX: Number, StartY: Number, GoalX: Number, GoalY: Number) -> Bool
@@ -1679,7 +1693,7 @@ Object.SetTerrainGrassVisible(Visible: Bool) // Terrain only; false = no grass o
1679
1693
  SpawnEffectAimed(Effect: Object, Position: Position, Direction: Vector) -> Object // Spawns with the effect's authored up/emission axis aimed along Direction (e.g. exhaust: SpawnEffectAimed(fx, GetPosition(), -GetFacingDirection())). Zero direction = unrotated.
1680
1694
  Object.SetEmitterLightsEnabled(Enabled: Bool) // Toggle the lights this object's mesh bakes via emitter(...) sockets (default on) - e.g. lamps dark at day
1681
1695
  Object.GetEmitterLightsEnabled() -> Bool
1682
- SetFogSkyboxAffect(Percent: Number) // Default: 0 (sky ignores distance fog). 100 = distant sky fully fogged, ~30 = horizon haze
1696
+ SetFogSkyboxAffect(Percent: Number) // Default: 0 (sky ignores distance fog). 100 = distant sky fully fogged, ~30 = horizon haze [global: all clients]
1683
1697
  TileGridSetWalkableFromStaticColliders(Grid: List, OriginTile: Vector, ZMin: Number, ZMax: Number)
1684
1698
  Object.SetCursorUiMode(On: Bool) // true: release mouse-look AND show the cursor so players can click UI (menus/shops); false: restore gameplay look. Prefer over toggling SetIsMouseLookOn/SetMouseVisible separately.
1685
1699
  Object.SetBoneRotation(BoneName: Text, EulerDegrees: Vector) // Replace the named bone(...) rig joint's local rotation (Euler degrees Z-up, #clip convention); wins over the playing clip for that bone until cleared. Max 16 bones per object. Display-only: colliders/physics unaffected. Call per-frame in forever{} for tails, breathing, head tracking
@@ -1701,12 +1715,12 @@ Object.GetAnchorWorldPos(AnchorName: Text) -> Position // World position of a so
1701
1715
  Object.GetAnchorWorldDir(AnchorName: Text) -> Vector // Anchor local +X (forward) rotated to world space; unit vector, unaffected by object scale. The socket axis: parameter is the anchor's local +Z (see GetAnchorWorldUp).
1702
1716
  Object.GetAnchorWorldUp(AnchorName: Text) -> Vector // Anchor local +Z (the socket's declared axis:) rotated to world space; unit vector, unaffected by object scale.
1703
1717
  IsWorldReady() -> Bool // true once the current load's scene OnSpawned batch has fully started (see event OnWorldReady); false again from the start of a new load/restart. Poll it before placing things on procedurally built ground/rooms.
1704
- SetShadowDistance(DistanceMeters: Number) // Crisp sun-shadow range in meters; past it only static geometry casts (coarse cached shadows to ~2km, desktop). Default: 50 (character scale); building-onto-building / city blocks need 200-300. Cost: shadow edges get chunkier as range grows
1718
+ SetShadowDistance(DistanceMeters: Number) // Crisp sun-shadow range in meters; past it only static geometry casts (coarse cached shadows to ~2km, desktop). Default: 50 (character scale); building-onto-building / city blocks need 200-300. Cost: shadow edges get chunkier as range grows [global: all clients]
1705
1719
  SetDebugRenderMode(Mode: Number) // Diagnostic view: renders ONE lighting/material component ungraded instead of the shaded frame, to tell wrong albedo from wrong light from wrong geometry. 0 off, 1 albedo, 2 normal, 3 material ao, 4 ssao, 5 ao*ssao (what ambient is multiplied by - 0 means no ambient can reach the surface), 6 direct sun, 7 ambient/sky, 8 shadow mask, 9 roughness, 10 metallic, 11 emissive, 12 local lights. Ship worlds with 0; the playtest/live_screenshot `debug_view` parameter is the per-capture equivalent. Default: 0
1706
1720
  PersistClear()
1707
1721
  Object.SetInstance(Index: Number, Offset: Vector, RotationEuler: Vector, Size: Vector, ColorRGB: Vector) // Batch only. Overwrites the instance at Index (0..GetInstanceCount-1); args like AddInstance. Errors on out-of-range Index
1708
1722
  Object.RemoveInstance(Index: Number) // Batch only. Swap-remove: the LAST instance moves into Index, count shrinks by 1. Errors on out-of-range Index
1709
- SetSkyboxColor(Color: Vector) // Procedural sky only. Base color multiplied into the sky bake before grading (alien/stylized skies); SetSkyboxTint post-multiplies the graded display instead. Default: (1, 1, 1)
1723
+ SetSkyboxColor(Color: Vector) // Procedural sky only. Base color multiplied into the sky bake before grading (alien/stylized skies); SetSkyboxTint post-multiplies the graded display instead. Default: (1, 1, 1) [global: all clients]
1710
1724
  GetRayHitDistance(Position: Position, Direction: Vector, Tag: Number) -> Number // Tag filters to objects WITH that tag; 0 is a real tag index, NOT "no filter" — use the 2-arg overload for unfiltered rays. Distance in cm to the first hit, -1 on miss — range gates and damage falloff.
1711
1725
  GetRayHitDistance(Position: Position, Direction: Vector) -> Number // Unfiltered. Distance in cm to the first hit, -1 on miss — range gates and damage falloff; prefer this over measuring to GetRayHitPosition, whose miss sentinel is Position + Direction * 1000000.
1712
1726
  SetSkyboxCloudType(Type: Number) // Procedural sky only. Cloud vertical form. Default: 0.35; 0 = flat haze layer, 1 = towering cumulus
@@ -1717,7 +1731,7 @@ TileGridFlowFieldBuild(Grid: List, GoalTiles: List) -> List
1717
1731
  Object.StartTileFlowFollow(Field: List, Grid: List, OriginTile: Vector, Speed: Number) -> Bool
1718
1732
  TilePathFollowTakeBlocked() -> List
1719
1733
  Object.SetSubmeshTint(SubmeshIndex: Number, TintRGB: Vector) // THIS object's per-submesh tint (faction colors): same LOD-flattened slot space as SetAssetSubmeshTint; multiplies SetColor and the asset tint (black kills). Tint (1,1,1) clears the slot. Skinned models fully supported; tinted statics leave the LOD-collapse fast path; InstanceBatch/TileMap handles reject
1720
- SetFogOfWarEnabled(Enabled: Bool) // RTS fog of war: per-TEAM vision grid sized from the largest terrain (runtime error without one). Each viewer sees own-team vision; unexplored = black, explored-but-unseen = grey memory (objects hidden), visible = clear. Radius discs only (no line-of-sight blocking); audio is not gated. Enable once at world start; false clears everything. No default sight: until Object.SetSightRadius lands on TEAMED objects, teamed viewers see a near-black stage - grant sight in the same change as the enable
1734
+ SetFogOfWarEnabled(Enabled: Bool) // RTS fog of war: per-TEAM vision grid sized from the largest terrain (runtime error without one). Each viewer sees own-team vision; unexplored = black, explored-but-unseen = grey memory (objects hidden), visible = clear. Radius discs only (no line-of-sight blocking); audio is not gated. Enable once at world start; false clears everything. No default sight: until Object.SetSightRadius lands on TEAMED objects, teamed viewers see a near-black stage - grant sight in the same change as the enable. Global (one grid, all players); max 8 distinct sighted teams, later teams see nothing. Per-PLAYER vision: SetTeam(GetPlayerIndex() + 1) on each player + their owned objects, shared objects stay teamless; SetSightRadius(100000) = that player sees everything
1721
1735
  Object.SetSightRadius(RadiusCm: Number) // THIS object provides fog vision to ITS team (GetTeam) in a RadiusCm disc, refreshed ~every 8 ticks while alive; 0 unregisters. Teamless objects provide no vision. Give it to units/buildings after SetFogOfWarEnabled
1722
1736
  IsPositionVisibleToTeam(Position: Position, TeamId: Number) -> Bool // True when the position is currently in TeamId's live vision (explored-only memory returns false). Unset/no-team viewers see everything; a team that never held vision sees nothing. Fog disabled = always true. For AI/scripting; rendering hides automatically
1723
1737
  GetTerrainBoundsMin() -> Position // World-space min corner of the LARGEST terrain (z = lowest height sample). Errors when no terrain exists. Fog and the minimap snapshot use the same terrain.
@@ -1750,6 +1764,18 @@ SessionErrorText() -> Text // Reason for state 3 (empty otherwise), e.g. relay u
1750
1764
  SessionPlayerCount(Index: Number) -> Number // Connected player count for a listed session (0 = unknown).
1751
1765
  OpenSessionBrowser() // Open the engine's built-in session browser UI (no-op in headless/validation).
1752
1766
  Object.ShatterAndDestroy() // Destroy() plus a debris burst from the model's baked chunk set (needs `#mesh Name destructible: <word>`; without it, plain Destroy()). Debris is display-only - no sim collision.
1767
+ TerrainSlopeAtXY(X: Number, Y: Number) -> Number // slope01 (g/(1+g); 0.5 = 45deg) of topmost terrain at world XY; 1 if no terrain (void = unwalkable). Walkers wedge above ~0.5
1768
+ TileGridSetWalkableFromTerrain(Grid: List, OriginTile: Vector, MaxSlope01: Number)
1769
+ TileGridSetEdgesFromTerrain(Grid: List, OriginTile: Vector, MaxStepCm: Number)
1770
+ TileGridStampRect(Grid: List, X1: Number, Y1: Number, X2: Number, Y2: Number, Blocked: Bool)
1771
+ TileGridStampObject(Grid: List, OriginTile: Vector, Obj: Object, Blocked: Bool)
1772
+ TileGridIsReachable(Grid: List, X1: Number, Y1: Number, X2: Number, Y2: Number) -> Bool
1773
+ TileGridIsReachable(Grid: List, X1: Number, Y1: Number, Z1: Number, X2: Number, Y2: Number, Z2: Number) -> Bool
1774
+ TileGridBakeCrowdObstacles(Grid: List, OriginTile: Vector)
1775
+ TerrainHeightsFromTiers(Heights: List, SamplesX: Number, SamplesY: Number, Tiers: Text, TierCm: Number) // REPLACE Heights from an ASCII tier map (digits = tier * TierCm, '.' = 0, 'r' = ramp; first row = max Y). See <terrain_generation>
1776
+ RaiseWorldError(Message: Text) // Fail-loud assert: raises a Weave runtime error carrying Message (validation surfaces it; in play the program pauses like any script error)
1777
+ SetWaterMurkDensity(Density: Number) // Scales underwater-camera murk: 1 = default, 0 = crystal clear (underwater/side-view games), max 4. [global: all clients]
1778
+ Object.SetFogDistances(StartM: Number, EndM: Number) // THIS player's display fog distances in meters, replacing the global SetFogStartDistance/SetFogEndDistance on their screen only (night vision, zombie-side sight); EndM 0 or negative clears back to the globals
1753
1779
 
1754
1780
  </built_in_function_list>
1755
1781
 
@@ -1792,6 +1818,8 @@ event OnSpawned {
1792
1818
  - Flat gameplay areas: TerrainHeightsFlattenDisc/Rect/Path AFTER noise/erosion so nothing roughens them again. ThermalErode + RemapCurve make raw noise look natural (erode first, then remap for plateaus/cliffs).
1793
1819
  - Prefer 129..257 samples per axis (513 max; big lists inflate sim state — generate in OnSpawned local vars so they are GC'd after spawn).
1794
1820
  - GroundHeightAtXY(x, y) -> world Z cm of the topmost ground at world XY (downward raycast over terrain + static colliders; 0 if nothing). Use for placing props/villages on generated ground; works immediately after SpawnTerrainFromHeights in the same event.
1821
+ - TerrainSlopeAtXY(x, y) -> slope01 of the topmost terrain at world XY (0.5 = 45deg; no terrain = 1, treat void as unwalkable). Slopes steeper than ~0.5 silently immobilize walkers - keep unit routes below it or block those tiles/edges in the nav grid (see <tile_pathfinding>).
1822
+ - TerrainHeightsFromTiers(Heights, SamplesX, SamplesY, Tiers, TierCm) REPLACES the field with plateau heights from an ASCII tier map in a triple-quoted Text (digits 0-9 = tier, h = tier * TierCm; '.' = 0; 'r' = ramp graded toward its lower neighbor; rows = lines, FIRST row = MAX Y / north). Hand-drawn RTS cliff maps: one char per nav tile, then TileGridSetEdgesFromTerrain(MaxStepCm = TierCm/3) derives the cliff edges; compose Smooth/Erode/splat after.
1795
1823
  - Realism combo: Warp after base noise (kills grid-straight lines), then ErosionFilter (fast stateless gullies/ridges; run AFTER RemapCurve so the detail lands at final scale, and its look continues sub-cell on the GPU display surface). Avoid HydraulicErode/ThermalErode by default — slow iterative CPU sims; reach for HydraulicErode only when routed drainage or its flow/deposit masks are truly needed. MaskFromFlow gives a wetness mask WITHOUT eroding.
1796
1824
  - Terrain-following rivers: FlowPath traces downhill from a spring cell into a CarvePath-ready point list (stops at sea level = MinHeightCm). Check PathXYOut has >= 4 numbers (2 points) before carving.
1797
1825
  - Roads that climb: GradePath lerps the flatten height start->end along the path (use terrain heights at the endpoints); FlattenPath only does constant height.
@@ -2084,7 +2112,7 @@ event OnPlayerReconnected
2084
2112
  - text align uses words: align=(horizontal, vertical) where horizontal=left|center|right, vertical=top|center|bottom. Defaults: button text is already CENTER, textLabel is top-left; only set align to override (e.g. align=(center, center) to center a label). In script use SetTextAlign(h, v) with 0/1/2 = left/center/right, top/center/bottom.
2085
2113
  - Text off-center in a panel: put the textLabel INSIDE the frame with NO size (a size-less child of a plain frame inherits the frame's full rect) + align=(center, center). Never center by hand-tuned offset - text width is not measurable, guessed offsets are always off.
2086
2114
  - Fonts: SetFont(Ori.font.google.<Family_Name>) uses any Google Font (fonts.google.com) directly, no upload; underscores for spaces, optional weight/style suffix (e.g. Ori.font.google.Roboto_Mono, Ori.font.google.Lobster, Ori.font.google.Roboto_Mono.700italic). Uploaded font assets use SetFont(Ori.font.<creator>.<name>). UI text without a font uses the world default: SetDefaultFont(Ori.font...) sets it, default Nunito.
2087
- - Declarative fonts: textLabel/button clauses accept font_size = N (base units, default 16) and font = "font.google.<Family_Name>" / "font.<creator>.<name>" — prefer these over SetFontSize/SetFont calls in OnSpawned. Text never auto-shrinks to fit its rect - match font_size to the rect.
2115
+ - Declarative fonts: textLabel/button clauses accept font_size = N (base units, default 16) and font = "font.google.<Family_Name>" / "font.<creator>.<name>" — prefer these over SetFontSize/SetFont calls in OnSpawned. Text never auto-shrinks to fit its rect - match font_size to the rect; textLabel overflow = clip clamps drawn glyphs to the label rect (default wrap lets long text spill past it).
2088
2116
 
2089
2117
  - PREFER auto-layout containers over manual offsets: vStack (stack down) / hStack (stack across) / grid (set columns). They self-arrange children, so you don't hand-place each element.
2090
2118
  - HUG (recommended default): a vStack/hStack with NO `size` auto-sizes to fit its children + padding + gaps. Just author the children; the container grows to wrap them.
@@ -2100,14 +2128,14 @@ event OnPlayerReconnected
2100
2128
  - cover = screen (frame): rect = the player's FULL real window instead of the 1600x900 base box - backdrops/vignettes reach wide-monitor edges (unflagged UI lays out in the centered base box, leaving side bands there). Children anchor inside it normally, so a HUD wrapped in a cover frame hugs true screen corners. Owned screen canvases only.
2101
2129
  - visible = false starts any element hidden (there is no `hidden` field); SetVisible(true) reveals it - same flag.
2102
2130
  - clip_to_bounds = true clips children (and hit-testing) to this rect; block_input = true blocks clicks passing through. Containers (frame/vStack/hStack/grid) default block_input = TRUE - set block_input = false on overlay panels that must not swallow clicks on the world behind them (other elements default false).
2103
- - Interactable elements (buttons, classed elements, draggables) consume clicks before the world: no click-through move/shoot/ClickThisObject under them, so no guard code needed. block_input additionally swallows clicks on non-interactable containers; a decorative classed element that must NOT eat world clicks sets click_through = true.
2131
+ - Interactable elements (buttons, classed elements, draggables) consume clicks before the world: no click-through move/shoot/ClickThisObject under them, so no guard code needed. block_input additionally swallows clicks on non-interactable containers; a decorative classed element that must not eat clicks (world clicks, or a button it is layered over) sets click_through = true.
2104
2132
  - Scrollable container: set clip_to_bounds=true + block_input=true on the container, then SetUiScrollOffset(X, Y) shifts its content (children move by -offset; rect/clip stay). Read back with GetUiScrollOffsetX/Y(). Wire event OnMouseScroll { } (Event.ScrollDelta, positive = wheel up) to adjust Y. Wheel over input-blocking UI does not zoom the camera. Authored start offset: scroll_offset = (x, y).
2105
2133
  - Rounded corners + border work on frame/button/progressBar (textLabel: neither; image: corner_radius only): corner_radius = N (base units, all 4 corners), border_width = N (base units; border shows only when > 0), border_color = #RRGGBB | #RRGGBBAA | (r,g,b). Authoring-only: no SetUi* simcall changes these at runtime.
2106
2134
  - progressBar: color = fill, background_color = track; fill ratio via SetProgress(Value, MaxValue).
2107
2135
  - count = N (2..=256, canvas child elements): parse-time repeat — the element and its whole subtree expand into N copies named <Name>0..<Name>N-1 (e.g. `frame Slot { count = 9 ... }` -> Slot0..Slot8, each resolvable by name). Use for marker/gauge/slot pools instead of hand-numbering; copies stack until code positions them via SetUiOffset; resolve copies dynamically via Panel.FindChildUI("Slot" + i). Counts nest (rows x cells).
2108
2136
  - image nine_slice = (uv_frac, border): scalable panel art — the outer uv_frac (0..0.5) of the texture becomes a fixed border-unit rim (corners keep size, edges/center stretch). Use for stretchy frames/panels from one texture.
2109
2137
  - frame/vStack/hStack/grid also accept image = "image.*" as a background fill (drawn over color/border, under children; nine_slice applies). Combine with material= freely.
2110
- - text/button shadows are off by default; set shadow_color = #000000B4 (or any alpha > 0) to enable.
2138
+ - text/button shadows are off by default; set shadow_color = #000000B4 (or any alpha > 0) to enable; 6-digit hex is fully opaque (#000000 = solid shadow), 8 digits control alpha.
2111
2139
  - UI text covers Latin-1 plus common symbol blocks (punctuation – — … •, arrows, geometric shapes ◆●▶, misc symbols ★♦⚙, dingbats ✦✔). Emoji and CJK render as NOTHING (validation rejects). Icons still look best as image assets.
2112
2140
  - text_color defaults white; a button with a background color set but no text_color auto-picks a readable default (white on dark, near-black on light).
2113
2141
  - Colors accept optional 8-digit hex alpha (e.g. #3A3A3AFF) in addition to #RRGGBB and (r,g,b).
@@ -3165,6 +3193,265 @@ display WorldGenObj : WorldGen { visible = false }
3165
3193
  </example_grassy_eroded_hills>
3166
3194
 
3167
3195
 
3196
+ <example_rts_skirmish>
3197
+ // RTS Skirmish - cliffs, nav grid, crowd squads (the canonical RTS nav pattern)
3198
+ // Terrain: hand-drawn tier map (TerrainHeightsFromTiers) - north plateau, south flat,
3199
+ // two ramps. Cliffs become blocked nav EDGES, ramp tiles stay open.
3200
+ // Nav: ONE authored source (the tier map); the grid derives from it with the canonical
3201
+ // load order: collider raster -> FromTerrain -> EdgesFromTerrain -> BakeCrowdObstacles
3202
+ // -> TileGridIsReachable + RaiseWorldError (a mis-built map fails at load, not mid-game).
3203
+ // Units: `crowd` bodies routed by the shared grid - FindPath8 once per order,
3204
+ // MoveAlongTilePathContinuous every frame (avoidance shapes the velocity: global path
3205
+ // + local separation). Each unit drives ITSELF in its Update; orders arrive via fields.
3206
+ // Player: spectator + top-down camera; right-click orders the green squad. Red squad
3207
+ // patrols the plateau and both sides auto-attack in range.
3208
+ // Buildings: a tower placed AFTER the raster stamps its footprint incrementally
3209
+ // (TileGridStampObject) - placements never re-raster the grid.
3210
+
3211
+ #set TileSize = 200
3212
+
3213
+ alias model.tower // bare: auto-binds a generated mesh from the shared library
3214
+ alias model.wall
3215
+
3216
+ #class Battlefield
3217
+ var Grid: List<Number> = []
3218
+ var OriginT = Vector(-32, -32, 0) // grid origin in TILE units; world = tile * TileSize
3219
+ var GreenAlive = 0
3220
+ var RedAlive = 0
3221
+ var Banner: Object
3222
+
3223
+ event OnSpawned {
3224
+ // 65x65 height samples, 200cm cells: terrain spans +-6400cm centered at the origin.
3225
+ // 16x16 tier chars = one char per 4 nav tiles. FIRST text row = NORTH (max Y).
3226
+ // Tier 1 = 300cm plateau; 'r' columns grade two ramps; everything else is cliff.
3227
+ var sx = 65
3228
+ var H: List<Number> = []
3229
+ H.Resize(sx * sx, 0)
3230
+ TerrainHeightsFromTiers(H, sx, sx, """1111111111111111
3231
+ 1111111111111111
3232
+ 1111111111111111
3233
+ 1111111111111111
3234
+ 111111rr1111rr11
3235
+ 000000rr0000rr00
3236
+ 0000000000000000
3237
+ 0000000000000000
3238
+ 0000000000000000
3239
+ 0000000000000000
3240
+ 0000000000000000
3241
+ 0000000000000000
3242
+ 0000000000000000
3243
+ 0000000000000000
3244
+ 0000000000000000
3245
+ 0000000000000000""", 300)
3246
+ var Terrain = SpawnTerrainFromHeights(H, sx, sx, 200, Position(0, 0, 0))
3247
+ Terrain.SetTerrainLayers(Material.GrassTex, Material.RockTex, Material.SandTex)
3248
+
3249
+ // Wall line guarding the west ramp foot, with a deliberate gap (static colliders:
3250
+ // spawned BEFORE the raster so it picks them up like any building).
3251
+ var wx = -3
3252
+ while wx <= 3 {
3253
+ if wx != 0 { SpawnAtTile(SavedObject.WallPiece, Vector(-6 + wx, -6, 0)) }
3254
+ wx = wx + 1
3255
+ }
3256
+
3257
+ // The canonical nav build. 64x64 edge-blocking grid over the terrain footprint.
3258
+ Grid = TileGridCreate(64, 64, true, true)
3259
+ TileGridSetWalkableFromStaticColliders(Grid, OriginT, 20, 200) // resets every tile; FIRST
3260
+ TileGridSetWalkableFromTerrain(Grid, OriginT, 0.45) // steep + void (subtract)
3261
+ TileGridSetEdgesFromTerrain(Grid, OriginT, 100) // cliffs = edges; TierCm/3
3262
+ TileGridBakeCrowdObstacles(Grid, OriginT) // avoidance sees the same walls
3263
+
3264
+ // Fail-loud map asserts: both squads' ground must connect via the ramps.
3265
+ if !TileGridIsReachable(Grid, 32, 8, 32, 56) {
3266
+ RaiseWorldError("south flat cannot reach the north plateau - ramp sealed")
3267
+ }
3268
+
3269
+ // Incremental placement: a watchtower on the south flat. StampObject blocks its
3270
+ // footprint tiles without re-rastering; the seal guard would catch a bad spot.
3271
+ var t = SpawnAtTile(SavedObject.Watchtower, Vector(-2, -12, 0))
3272
+ TileGridStampObject(Grid, OriginT, t, true)
3273
+ if !TileGridIsReachable(Grid, 32, 8, 32, 56) {
3274
+ RaiseWorldError("tower placement sealed the map - unstamp or move it")
3275
+ }
3276
+
3277
+ Banner = Scene.Hud.FindChildUI("Banner")
3278
+ Banner.SetText("Right-click: order the green squad")
3279
+ }
3280
+
3281
+ // Units register/deregister so the manager can call the fight.
3282
+ func UnitJoined(team: Number) {
3283
+ if team == 0 { GreenAlive += 1 } else { RedAlive += 1 }
3284
+ }
3285
+ func UnitDied(team: Number) {
3286
+ if team == 0 { GreenAlive -= 1 } else { RedAlive -= 1 }
3287
+ if GreenAlive <= 0 { Banner.SetText("RED holds the plateau") }
3288
+ if RedAlive <= 0 { Banner.SetText("GREEN takes the plateau!") }
3289
+ }
3290
+ #end
3291
+
3292
+ #class Trooper
3293
+ var Team = 0
3294
+ var Hp = 30
3295
+ var Path: List<Number> = []
3296
+ var HasOrder = false
3297
+ var LastGoalX = -1
3298
+ var LastGoalY = -1
3299
+ var Speed = 260 // cm/s
3300
+ var AttackTimer: Timer
3301
+ var PatrolFlip = false
3302
+
3303
+ event OnSpawned {
3304
+ SetHoverHPBar(Hp, 30)
3305
+ AttackTimer.StartCountDown(1)
3306
+ }
3307
+
3308
+ // Orders are FIELDS: over-time builtins only run on self, so the owner (player class /
3309
+ // patrol logic) writes the goal and the unit paths + walks in its own Update.
3310
+ func OrderMoveToTile(goalX: Number, goalY: Number) {
3311
+ // Re-clicking the same spot must NOT re-path: a fresh path starts at the current
3312
+ // tile CENTER, so mid-tile movers would first walk backward to it.
3313
+ if HasOrder and goalX == LastGoalX and goalY == LastGoalY { return }
3314
+ var bf = Manager()
3315
+ // NextTo = "path to it, or beside it": walkable goals path exactly; a blocked goal
3316
+ // (clicked on a tower/wall/cliff void) completes on the best adjacent tile.
3317
+ var p = TileGridFindPath8NextTo(bf.Grid, MyTileX(), MyTileY(), goalX, goalY)
3318
+ if p.Count() == 0 { HasOrder = false; return } // unreachable: honest no-path, stay put
3319
+ // Drop the start-tile waypoint (reversed list: Goal..Start): orders issued mid-tile
3320
+ // head for the next corner instead of stepping back onto the tile center.
3321
+ p.RemoveAt(p.Count() - 1)
3322
+ if p.Count() == 0 { HasOrder = false; return } // ordered onto the tile it stands on
3323
+ Path = TileGridSmoothPath(bf.Grid, p)
3324
+ LastGoalX = goalX
3325
+ LastGoalY = goalY
3326
+ HasOrder = true
3327
+ }
3328
+
3329
+ func Manager() -> Battlefield { return (Scene.Manager0 as Battlefield) }
3330
+ func MyTileX() -> Number { return WorldToTile(GetPosition()).X - Manager().OriginT.X }
3331
+ func MyTileY() -> Number { return WorldToTile(GetPosition()).Y - Manager().OriginT.Y }
3332
+
3333
+ event Update {
3334
+ var bf = Manager()
3335
+ // Walk: one call per frame; avoidance shapes it (crowd body + continuous mover).
3336
+ if HasOrder {
3337
+ // ArriveWithinCm 90: a squadmate resting near the goal must not stall the
3338
+ // arrival (avoidance stops dead-ahead; generous arrive completes the order).
3339
+ if MoveAlongTilePathContinuous(Path, bf.Grid, bf.OriginT, Speed, 90, 360) {
3340
+ HasOrder = false
3341
+ if Team == 1 { PatrolFlip = not PatrolFlip } // red: bounce between posts
3342
+ }
3343
+ } else if Team == 1 {
3344
+ // Red squad patrols the plateau rim between two posts.
3345
+ if PatrolFlip { OrderMoveToTile(20, 52) } else { OrderMoveToTile(44, 52) }
3346
+ }
3347
+
3348
+ // Auto-attack: nearest enemy trooper within 500cm, 1 hit/s.
3349
+ if AttackTimer.IsDone() {
3350
+ var target = NearestEnemy(500)
3351
+ if target.Exists() {
3352
+ (target as Trooper).TakeHit(10)
3353
+ SpawnFloatingText("-10")
3354
+ AttackTimer.StartCountDown(1)
3355
+ }
3356
+ }
3357
+ }
3358
+
3359
+ func NearestEnemy(rangeCm: Number) -> Object {
3360
+ var best: Object = None
3361
+ var bestD = rangeCm
3362
+ for u in GetAllObjectsWithSavedType(SavedObject.GreenTrooper) {
3363
+ var d = DistanceTo(u)
3364
+ if (u as Trooper).Team != Team and d < bestD { best = u; bestD = d }
3365
+ }
3366
+ for u in GetAllObjectsWithSavedType(SavedObject.RedTrooper) {
3367
+ var d = DistanceTo(u)
3368
+ if (u as Trooper).Team != Team and d < bestD { best = u; bestD = d }
3369
+ }
3370
+ return best
3371
+ }
3372
+
3373
+ func TakeHit(dmg: Number) {
3374
+ Hp -= dmg
3375
+ SetHoverHPBar(Hp, 30)
3376
+ if Hp <= 0 {
3377
+ Manager().UnitDied(Team)
3378
+ Die()
3379
+ }
3380
+ }
3381
+ #end
3382
+
3383
+ #class player
3384
+ event OnSpawned {
3385
+ SetPlayerModeSpectator()
3386
+ SetVisible(false)
3387
+ SetCameraToTopDown()
3388
+ // RTS overview out of the box (the default top-down zoom reads as a grass close-up);
3389
+ // the wheel still zooms within the limits.
3390
+ SetCameraZoom(4200)
3391
+ SetCameraUserZoomLimits(800, 9000)
3392
+ TeleportToTile(0, -8)
3393
+
3394
+ // Green squad on the south flat (owned by whoever spawned first; co-op players
3395
+ // share command of the same squad in this small demo).
3396
+ if GetPlayerIndex() == 0 {
3397
+ var bf = (Scene.Manager0 as Battlefield)
3398
+ var i = 0
3399
+ while i < 4 {
3400
+ var u = SpawnAtTile(SavedObject.GreenTrooper, Vector(-4 + i * 2, -10, 0))
3401
+ u.SetColor(Vector(0.2, 0.9, 0.3))
3402
+ (u as Trooper).Team = 0
3403
+ bf.UnitJoined(0)
3404
+ i = i + 1
3405
+ }
3406
+ i = 0
3407
+ while i < 3 {
3408
+ var r = SpawnAtTile(SavedObject.RedTrooper, Vector(-6 + i * 6, 22, 0))
3409
+ r.SetColor(Vector(0.95, 0.25, 0.2))
3410
+ (r as Trooper).Team = 1
3411
+ bf.UnitJoined(1)
3412
+ i = i + 1
3413
+ }
3414
+ }
3415
+ }
3416
+
3417
+ event RightMouseClickByThisPlayer {
3418
+ // Ground click: terrain + static colliders only, so clicking through your own
3419
+ // troops still lands on the ground; Invalid when the cursor misses the world.
3420
+ var p = GetMouseTargetGroundPosition()
3421
+ if !p.IsValid() { return }
3422
+ var bf = (Scene.Manager0 as Battlefield)
3423
+ var t = WorldToTile(p)
3424
+ var slot = 0
3425
+ for u in GetAllObjectsWithSavedType(SavedObject.GreenTrooper) {
3426
+ // 2-tile goal spacing: adjacent-tile goals let arriving units body-block each
3427
+ // other (no rest-occupancy yet); a spaced 2x2 formation settles cleanly.
3428
+ (u as Trooper).OrderMoveToTile(
3429
+ (t.X - bf.OriginT.X + (slot % 2) * 2).Clamp(0, 63),
3430
+ (t.Y - bf.OriginT.Y + (slot / 2).RoundDown() * 2).Clamp(0, 63))
3431
+ slot = slot + 1
3432
+ }
3433
+ }
3434
+ #end
3435
+
3436
+ saved GreenTrooper {
3437
+ crowd body : Trooper { model = "cube" size = (40, 40, 90) }
3438
+ }
3439
+ saved RedTrooper {
3440
+ crowd body : Trooper { model = "cube" size = (40, 40, 90) }
3441
+ }
3442
+ saved WallPiece {
3443
+ object wall { model = "alias.model.wall" size = (200, 60, 160) }
3444
+ }
3445
+ saved Watchtower {
3446
+ object base { model = "alias.model.tower" size = (300, 300, 700) }
3447
+ }
3448
+
3449
+ screenCanvas Hud { textLabel Banner { offset = (20, 20) size = (560, 30) align = (left, center) text = "..." color = (1, 1, 1) } }
3450
+ display Manager0 : Battlefield { visible = false position = (0, 0, 0) }
3451
+
3452
+ </example_rts_skirmish>
3453
+
3454
+
3168
3455
  <example_saved_block_font>
3169
3456
  // Declarative fonts work inside saved blocks (font = "font.google.<Family>" +
3170
3457
  // font_size); spawned copies keep the custom font.