oriverse-engine 0.1.9 → 0.1.11
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.
- package/LICENSE.md +30 -30
- package/README.md +8 -8
- package/dist/AGENT_ONBOARDING.md +74 -74
- package/dist/CODEX_PROMPT.md +7 -7
- package/dist/ktx_bridge.js +17 -0
- package/dist/oriverse_wgpu.d.ts +74 -45
- package/dist/oriverse_wgpu.js +319 -120
- package/dist/oriverse_wgpu_bg.wasm +0 -0
- package/dist/oriverse_wgpu_bg.wasm.d.ts +50 -44
- package/dist/shader_prewarm_manifest.json +1 -1
- package/dist/snippets/oriverse_networking_shared-e43478064e11e46c/inline0.js +40 -32
- package/dist/snippets/oriverse_networking_shared-e43478064e11e46c/inline1.js +32 -21
- package/dist/snippets/oriverse_user_client-a55220d4991e3856/src/library_capture_idb.js +54 -0
- package/dist/starter/AGENTS.md +2 -2
- package/dist/starter/CLAUDE.md +2 -2
- package/dist/starter/game.html +6 -6
- package/dist/templates/game_cdn.html +6 -6
- package/dist/weave_documentation.txt +698 -393
- package/package.json +1 -1
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
|
|
2
2
|
>>>>>>>>>>>>
|
|
3
3
|
Weave World Description Language Documentation
|
|
4
|
-
Version:
|
|
4
|
+
Version:07Sep26-20:39-36010
|
|
5
5
|
>>>>>>>>>>>>
|
|
6
6
|
|
|
7
7
|
<weave_language>
|
|
8
8
|
- Weave is used to code on Oriverse (syntax similar to Swift for logic, plus scene declarations at top level).
|
|
9
9
|
- A Weave file has two kinds of top-level content:
|
|
10
|
-
- scene declarations: `object`, `saved`, `physics`, `crowd`, `walker`, `display`, `region`, and lights `pointLight`/`spotLight`/`areaLight` — describe what exists in the world.
|
|
10
|
+
- scene declarations: `object`, `saved`, `physics`, `crowd`, `climbingCrowd`, `walker`, `display`, `region`, and lights `pointLight`/`spotLight`/`areaLight` — describe what exists in the world.
|
|
11
11
|
- class code: `#class <Name> ... #end` blocks of logic; each block compiles to bytecode attached to a game object.
|
|
12
|
-
- Compiler directives (top-level only): #class, #shader (custom WGSL on the engine lit material — lighting/shadows/IBL stay engine-owned; `@vertex { }` mutates ctx.world_pos for wind/sway, fragment writes out.base_color/world_normal/orm; bind via `material M { shader = "S" }`; live knobs via SetMaterialParameterNumber; body authoring in the shader_dsl skill), #texture (CPU-baked procedural PBR texture; auto-creates `material <Name>` usable as `material = "<Name>"`; defaults to triplanar/repeat/opaque (triplanar follows the instance - rotated/moved/duplicated props keep their pattern; `mapping = triplanar_world;` = world-space projection that continues across objects for modular kits, `mapping = uv;` = authored UVs), supports `wrap = clamp;`, `filter = nearest;` (pixel-art), `render_mode = cutout;`, and scalar `out.alpha`; see <texture_dsl_usage>; body authoring in the texture_dsl skill), #mesh (local CPU-baked procedural static mesh model `mesh.<Name>`; see <mesh_dsl_usage>; body authoring in the mesh_dsl skill), #tree (procedural tree species `tree.<Name>`; see <tree_dsl_usage>), #forest (scattered-tree region `forest.<Name>`; see <forest_dsl_usage>), #scatter (scattered-model region `scatter.<Name>`, display-only, no collision; see <scatter_dsl_usage>), #road_network (road/street graph meshed at load into junction-merged tiles + walkable slabs; grammar in its bullet below), #placement (grid-repeated model family - facade/street rhythm; see <placement_usage>), #particles (local particle effect JSON asset `effect.<Name>`; `particleTextureName` takes `"flipbook.<word>"` for a shared-library animated atlas, `"texture.<Texture>.color"` for a local #texture, or `"image.<User>.<Name>"` for a known ori image asset; see particle_vfx skill), #sound (local CPU-baked procedural sound asset `sound.<name>`; see <sound_dsl_usage>), #adjuster (user-tunable look knobs; see <adjuster_usage>), #rules (see <world_rules>), #end, #set <Name> = <Number> (TileSize, Realistic; texture policy, display-only: `#set TextureMaxResolution 1024` caps every market texture this world downloads to <=1024px [picks the market's smaller tier], `#set TextureFullResolutionAssets "model.a.x, model.b.y"` always loads listed assets at full resolution, `#set TextureFullResolutionUpgrade 1` enables the desktop post-load full-res texture re-fetch [default off: the world keeps its load-time texture tier — project-load assets land quarter-res; wasm/mobile never run the upgrade]), #doc_version <N> (authoring doc version; see <updating_old_worlds>).
|
|
12
|
+
- Compiler directives (top-level only): #class, #shader (custom WGSL on the engine lit material — lighting/shadows/IBL stay engine-owned; `@vertex { }` mutates ctx.world_pos for wind/sway, fragment writes out.base_color/world_normal/orm; bind via `material M { shader = "S" }`; live knobs via SetMaterialParameterNumber; body authoring in the shader_dsl skill), #texture (CPU-baked procedural PBR texture; auto-creates `material <Name>` usable as `material = "<Name>"`; defaults to triplanar/repeat/opaque (triplanar follows the instance - rotated/moved/duplicated props keep their pattern; `mapping = triplanar_world;` = world-space projection that continues across objects for modular kits, `mapping = uv;` = authored UVs), supports `wrap = clamp;`, `filter = nearest;` (pixel-art), `render_mode = cutout;`, and scalar `out.alpha`; see <texture_dsl_usage>; body authoring in the texture_dsl skill), #svg (SVG-subset drawing rasterized at load to `baked.<Name>.color` with alpha - icons, HUD art, logos, signs; auto-creates a cutout uv `material <Name>`; header `size=N` = long side px, short side follows the viewBox; body authoring in the svg_dsl skill), #mesh (local CPU-baked procedural static mesh model `mesh.<Name>`; see <mesh_dsl_usage>; body authoring in the mesh_dsl skill), #tree (procedural tree species `tree.<Name>`; see <tree_dsl_usage>), #forest (scattered-tree region `forest.<Name>`; see <forest_dsl_usage>), #scatter (scattered-model region `scatter.<Name>`, display-only, no collision; see <scatter_dsl_usage>), #road_network (road/street graph meshed at load into junction-merged tiles + walkable slabs; grammar in its bullet below), #placement (grid-repeated model family - facade/street rhythm; see <placement_usage>), #particles (local particle effect JSON asset `effect.<Name>`; `particleTextureName` takes `"flipbook.<word>"` for a shared-library animated atlas, `"texture.<Texture>.color"` for a local #texture, or `"image.<User>.<Name>"` for a known ori image asset; see particle_vfx skill), #sound (local CPU-baked procedural sound asset `sound.<name>`; see <sound_dsl_usage>), #fieldmap (persistent GPU canvas stamped from scripts - trails/footprints/scorch; see <field_maps>), #adjuster (user-tunable look knobs; see <adjuster_usage>), #rules (see <world_rules>), #end, #set <Name> = <Number> (TileSize, Realistic; texture policy, display-only: `#set TextureMaxResolution 1024` caps every market texture this world downloads to <=1024px [picks the market's smaller tier], `#set TextureFullResolutionAssets "model.a.x, model.b.y"` always loads listed assets at full resolution, `#set TextureFullResolutionUpgrade 1` enables the desktop post-load full-res texture re-fetch [default off: the world keeps its load-time texture tier — project-load assets land quarter-res; wasm/mobile never run the upgrade]), #doc_version <N> (authoring doc version; see <updating_old_worlds>), #artstyle "<technique, palette, linework, mood>" (subject-free; inherited by every image/flipbook gen call and search_assets ranking).
|
|
13
|
+
- For Enhanced (EEVEE-style) rendering, edit the top-level `#set EnhancedRendering 1` through the normal Weave apply flow; `0` or absent keeps the original Fast renderer. Device availability still applies; this is display-only and needs no menu selection.
|
|
13
14
|
- Scene numeric fields support constant arithmetic: `+`, `-`, `*`, `/`, unary sign, parentheses.
|
|
14
|
-
- One statement per line; separate statements on the same line with `;`. An empty list literal `[]` needs a List-typed context, e.g. `var H: List<Number> = []`.
|
|
15
|
+
- One statement per line; separate statements on the same line with `;`. A statement ends at the line break: wrap after a trailing operator or comma (call args and list literals may span lines); a line starting with `-` is a new statement (unary minus), never a continuation. An empty list literal `[]` needs a List-typed context, e.g. `var H: List<Number> = []`.
|
|
15
16
|
- Numbers are deterministic 48.16 fixed-point; tiny fractions lose precision — track small quantities in a smaller unit (e.g. hundredths of a cm as integers).
|
|
16
17
|
- No recursion: direct or mutual func call cycles are a compile error; rewrite as loops (a List can serve as an explicit stack).
|
|
17
18
|
- Class-body functions sit beside events: `func Heal(Target: Object, Amount: Number) -> Number { return Amount }`; omit `-> Type` when nothing is returned; zero-arg funcs still declare `()`; another instance's func needs a typed cast (`(u as Trooper).TakeHit(10)`).
|
|
@@ -23,7 +24,7 @@ Weave World Description Language Documentation
|
|
|
23
24
|
- For axis-aligned cube walls/floors/platforms, prefer `bounds_min=(x1,y1,z1)` + `bounds_max=(x2,y2,z2)` over `position`+`size`; it names exact world-space box corners and avoids center/half-size mistakes. Example: `object NorthWall { model="cube" bounds_min=(-1500,1100,0) bounds_max=(1500,1180,280) }`. Cube boxes only (`model="cube"`; `region_cube` for regions) — other models must use position+size. Do not combine with position/rotation/size/height/tile fields.
|
|
24
25
|
- Object size clamps per axis at load: 500m static-collidable, 100m movable-physics, 1km with collision off — tile bigger floors/walls from 500m pieces.
|
|
25
26
|
- Grass on objects: static mesh `object`/`display` clauses accept grass = true (blades on upward faces; steep faces stay bare; display-only, no collision; global SetGrass* look knobs apply; skinned models grow nothing). On model = "cube" blades cover the top face (yaw rotation only) and grass_border = round|noise (edge falloff, default full face) + grass_border_noise_scale = 220 (cm, noise feature size) shape the edge.
|
|
26
|
-
- Prefer `height = ...` for imported/custom models to preserve proportions; use `ScaleToHeight(...)` at runtime; use `size = ...` only when intentionally stretching X/Y/Z.
|
|
27
|
+
- Prefer `height = ...` for imported/custom models to preserve proportions; use `ScaleToHeight(...)` at runtime; use `size = ...` only when intentionally stretching X/Y/Z. Without either, a market model keeps its upload height — often toy-scale; set `height` from a real-world target (car ~150, sofa ~80).
|
|
27
28
|
- "world description" = the serialized text of a world (scene + classes); saved from the editor and pasted back to reload. AI builds these; users paste them in.
|
|
28
29
|
- `#class player` is auto-attached to every PlayerObject. Do not declare the player in scene. Declaring it REPLACES the built-in default player: call SetDefaultPlayerControlsEnabled(true) in its OnSpawned to keep built-in WASD move + jump, or code a movement loop — with neither, players cannot move (see <camera>).
|
|
29
30
|
</weave_language>
|
|
@@ -44,24 +45,25 @@ Weave World Description Language Documentation
|
|
|
44
45
|
- Aliases make the top of the world file a small asset dictionary: swap a model/effect/image/sound everywhere by editing one line. They also expose assets for runtime manipulation and let a human rebind them from the Build panel [Replace] button.
|
|
45
46
|
- Name aliases by TYPE: `alias.<type>.<name>` with <type> in {model, effect, image, sound}, e.g. `model.goblin`, `effect.explosion`, `image.gold_icon`, `sound.hit`. A typed alias must resolve to a matching asset type.
|
|
46
47
|
- You usually do NOT know real ori urls. Prefer typed alias placeholders and let the system/human bind real assets later:
|
|
47
|
-
- All four types may be referenced UNDECLARED or declared bare (`alias sound.hit`, no `=` target); they resolve from the
|
|
48
|
-
- MODEL aliases
|
|
48
|
+
- All four types may be referenced UNDECLARED or declared bare (`alias sound.hit`, no `=` target); they resolve from the libraries below, show a placeholder when missing (cube / default explosion / placeholder sprite / placeholder clip), and a human can rebind them. Generation availability depends on the asset type.
|
|
49
|
+
- MODEL aliases select existing library models. A missing model remains a placeholder; adapt a library mesh, author a local `#mesh`, or select an existing marketplace asset. `mesh_library_search` retrieves editable source; `use_mesh_asset` imports an exact pick. Save useful new or adapted meshes with `save_mesh_asset`. Check rig and clip metadata before choosing a character model.
|
|
49
50
|
- IMAGE aliases resolve the same way from a generated-UI-image library: bare `alias image.gold_icon` binds a generated icon by name at load; on a miss it shows a placeholder sprite while an icon is generated in the background. Prefer bare image aliases for UI icons; name them by subject (`image.gold_icon`, `image.energy_icon`).
|
|
50
51
|
- SOUND aliases resolve the same way from a generated-sound library: bare `alias sound.coin_pickup` binds a generated clip by name at load; on a miss it plays a placeholder clip while a sound is generated in the background. Name sound aliases by the event they accompany (`sound.coin_pickup`, `sound.sword_hit`, `sound.door_creak`) so generation prompts come out right.
|
|
51
52
|
- ANIMATION: referencing an undefined `Ori.anim.canon.<verb>` appends the canonical-clip library's `#clip <verb> on canon` block at load (plain action verbs: `anim.canon.cheer`, `anim.canon.stomp`); it plays on any rigged humanoid via engine retarget. On a library miss the character keeps its current animation; the verb is queued for house minting and binds on a later load. A world-authored `#clip <verb> on canon` always wins.
|
|
52
53
|
- EFFECT aliases resolve the same way from a generated-effect library: bare `alias effect.sparkle_burst` binds a generated `#particles` block by name at load; on a miss it shows a default explosion while an effect is generated in the background. Name effect aliases by visual (`effect.sparkle_burst`, `effect.heal_glow`, `effect.smoke_puff`).
|
|
53
54
|
- Never invent a fake `ori.*` url: either leave a typed alias undeclared / bare (gets resolved or a placeholder) or declare it with a real `ori.*` url you actually know.
|
|
55
|
+
- The word is your handle for the slot; the library binds by MEANING: word + `desc="..."` + the object's class and `size` + `#artstyle` pick the closest existing asset of that kind under any library word in the `#artstyle` look (name one of low_poly [default], painterly, realistic, pixel, anime, voxel, cartoon, watercolor, clay in the string). Missing models need an explicit choice or local mesh; other types use their supported generation lanes. Add `desc=` where the bare word under-specifies (`alias model.bear desc="huge scarred grizzly boss"`); `size=(x,y,z)` cm on model, `size=(w,h)` UI base units on image.
|
|
54
56
|
- Reference aliases as strings in scene fields: `model = "alias.model.goblin"`, `effect = "alias.effect.explosion"`.
|
|
55
57
|
- Reference aliases in Weave code through `Ori.alias.<type>.<name>`: `SetModel(Ori.alias.model.goblin)`, `SpawnEffect(Ori.alias.effect.explosion, GetPosition())`, `SetUiImage(Ori.alias.image.gold_icon)`.
|
|
56
58
|
- Reuse ONE alias per semantic asset everywhere, so rebinding one declaration swaps every usage at once (e.g. every enemy uses `alias.model.goblin`). Keep aliases world-local; never chain one alias to another.
|
|
57
59
|
</asset_aliases>
|
|
58
60
|
|
|
59
61
|
<asset_word_library>
|
|
60
|
-
- 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
|
|
62
|
+
- 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 can match existing assets by meaning. A missing model needs a local mesh or another selection; other types use their supported generation lanes. Flipbooks are authored via flipbook_gen.
|
|
61
63
|
model: abandoned_car alchemist alien_bug alien_hive alley_monster ambulance ammo_crate amphora anchor aqua_penguin assembler athlete aunt auntie automaton awakened axe ball bamboo 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 byrd 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 centurion chair chair_2 champ checkpoint cheese cheese_2 chest chicken chicken_coop chime_lantern chosen chunk_floor circular_saw clay_buddy cleric cloud clue_item clue_item_2 coin collector column command_center container_04 cottage cousin cow crate crate_2 crate_a crop crop_plot crossbow crowbar crystal crystal_cluster crystal_shard cultist cup customer customer_2 cutting_board cutting_board_2 cyclops darkling dead_tree dog donu dragon drill druid dual_blades durian elegant_woman elegant_woman_2 ember_fox enemy_spawn energy_drink evidence_item exp_gem fan farm_boy farmhouse farmhouse_floor fence finish_arch fire_truck fish fish_2 fishing_boat fishing_boat_2 fishing_rod flag flag_2 flamethrower flashlight flat_rock_slab flower fog_horn food_crate forager_hut forge forklift foundation fountain fox fridge fridge_2 frog frying_pan frying_pan_2 fuel_pump fungus furniture_bookshelf furniture_table furniture_table_2 furniture_wardrobe gargoyle gate generator ghoul ghoul_2 giant_head gilded_hourglass glimmer_crate goblin godfather godzilla golden_beak_shaman golden_coin grandma grandpa grape grape_2 grass_rock grass_rock_cliff great_sword green_maple_tree greenhouse gremlin gremlin_nob grocery_box ground_item guard guard_tower guardian hammer hamster harpy hay_bale hay_bale_2 heal_pickup held_item helicopter hero_necromancer hero_warrior hexaghost 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 jaw_worm jetski kid killer knife knight lab_crate_a ladder ladder_a lagavulin lamp lamp_2 lance lane lantern lantern_2 light_pole lighthouse_keeper lion log_pile log_pile_2 looter louse lumber_camp machine_gun mage magnet market_stall maw mecha_chameleon medic medicine_crate mil_supply_set mine miner minotaur moss_boar motorcycle mushroom mystic nemesis nephew niece night_watchman ninja_runner npc nurse oak_tree officer oil_drum oil_lamp owl paddle palm_tree palm_tree_2 parasite patient pearl_bush pebble person person_2 pickaxe pickup_orb pig pine_tree pistol pistol_2 plate plate_2 player_char police_car pond poop projectile pumpkin pyramid pyramid_2 rabbit rabbit_runner radio_console 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 rowboat rowboat_2 runic_obelisk runic_obelisk_2 sandbag sawmill scavenger school scifi_mil_crate sea_mine sedan sedan_2 sentinel_drone sentry shark sheep shield shipping_container shop_counter shop_floor shopkeeper shotgun shower shuriken signpost signpost_2 signpost_3 skeleton skull slaver slime slime_boss small_rock smg smoke_bomb snail snecko sniper_rifle sofa soil_tile soldier spear spider sports_car squid stair star star_core statue stepmother stilt_house stone_pile stonecutter_lodge storehouse storm_hearth storm_shrine supply_crate surgeon survivor sword table tank_hull tannery taskmaster telephone television tent timber_bundle time_eater tire toaster toaster_2 tool_chest torch torch_2 torus tower training_dummy training_dummy_2 transient 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 wizard_staff wolf wolf_2 wood_fence wood_fence_2 wooden_stool worker_robot zebrite_totem zombie
|
|
62
|
-
image: acid_slime_m acid_slime_s acolyte airtank_icon ak_rifle_icon alien_bug angled_player_banner aorta ascended_one awakened_one axe_icon banana_weapon_icon bandage_icon banshee barracks_icon baseball_bat_icon bean_icon bean_seeds_icon bear berries_icon blue_slaver bone_icon book_icon boss_skull bread_icon bullet_icon cabbage_icon campfire_icon canned_food_icon card_all_in card_bad_beat card_bargain card_borrowed_nerve card_brace card_charge card_chipped_edge card_cinch card_cleave card_dead_man_hand card_discipline card_double_slash card_doubling_down card_escalating_debt card_execute card_flail card_focus card_fortify card_fortune card_hex card_hexed_needle card_house_rules card_hunker card_inverted_wager card_last_stand card_ledger_balance card_loaded card_long_odds card_lunge card_marked_ledger card_mend card_pawn_the_ward card_pick_the_lock card_pray card_rage card_read_the_table card_reckless_cleave card_reversal card_scavenge card_sharpen card_shatter card_shave_the_die card_shield card_skull_crusher card_slash card_smash card_snap_shot card_snipe card_strain card_tallow_draught card_temper card_the_long_count card_the_whole_table card_tin_ward card_two_fingers card_unleash card_weaken card_weighted_coin card_whirlwind carrot_icon cave_rat cavern_battleground ceaseless_statue cheese_icon chrono_wisp cinder_fiend clock_icon clockwork_hound coconut_icon coin_icon corrupt_heart crop_icon crossed_swords crossed_swords_2 crosshair crowbar_icon cultist cultist_acolyte cute_paw_cursor cutthroat dagger darkling darkling_spawn dash_icon deca deck_icon deck_icon_2 donu energy_icon exploder factory_icon fat_gremlin feather_icon fish_bone_icon fish_icon fishing_rod_icon flamethrower_icon flint_icon fluffy_sheep_party_portrait foe_bone_abacus foe_chain_warden foe_coin_shill foe_marrow_cantor foe_needle_witch foe_tallow_priest foe_the_gutterhound foe_the_hexwright foe_the_house foe_wax_cur forest_ancient_tree_spirit_wide_splash forest_ent fungi_beast fungi_sporeling gnawing_mass goblin goblin_brute gold_coin_icon gold_icon gold_icon_2 green_louse gremlin_fat gremlin_leader gremlin_sneaky gremlin_wizard grenade_launcher_icon guardian_mech hand_icon harvester_icon health_icon health_icon_2 hero_necromancer hero_warrior hexaghost hide_icon hoe_icon honey_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 intent_attack intent_block intent_curse inverse_trapezoid_top_bar iron_ore_icon jaw_worm knife_icon knight_helmet lagavulin laser_gun_icon leaf_icon lich loading_splash log_icon longodds_hall longodds_table looter machine_gun_icon mackerel_icon mad_gremlin maw metal_cast_icon mold_icon monster_head moon_icon nemesis ninja_runner node_boss node_elite node_fight node_rest node_shop obsidian_icon obsidian_sentry orange_cat_party_portrait orb_walker orc panel_frame parsnip_icon parsnip_seeds_icon pickaxe_icon pill_bottle_icon pistol_icon plank_icon player_debtor poison_icon potato_icon potato_seeds_icon power_icon purple_hive_mind_insect_warrior_wide_splash qa_probe_gem radish_icon red_louse red_slaver refinery_icon reptomancer repulsor resin_icon revolver_icon rifle_icon road_tiles_icon road_tiles_icon_2 robot_face robot_vending_mech_champion_wide_splash rocket_launcher_icon rope_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 sentry shield_gremlin shotgun_icon silent skeleton skeleton_archer skill_dagger_icon skill_fireaura_icon skill_hammer_icon skill_shield_icon skill_stealth_icon slaver slime_boss slime_horror snake_dagger snapper_icon sneaky_gremlin snecko snecko_hatchling sniper_rifle_icon snowflake_spin soda_can_icon spider spike_slime spike_slime_l spike_slime_m spike_slime_s spiker spire_acolyte spire_shard spire_shield spire_spear squid_icon steak_icon stick_icon stone_icon straight_road_icon_transparent_no_background submachine_gun_icon sun_icon syringe_gun_icon tank_icon taskmaster 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 time_eater torch_icon traffic_light_icon traffic_light_icon_2 traffic_light_icon_transparent_no_background transient tuna_icon turret_icon twigs_icon undead_death_knight_wide_splash undead_skull vampire ventricle water_bottle_icon water_drop_icon watering_can_icon werewolf white_chicken_party_portrait witch withered_titan wolf wood_icon yokai_mask yokai_samurai_oni_wide_splash
|
|
63
|
-
sound: ambient_horror apartment_ambience arena_warning baby_raptor_step backfire ball_hit banana_boomerang baton_hit baton_swing bear_shotgun bite blade_hit blast body_thump body_thump_2 boost boost_burst bow_hit branch_snap brass_gong cannon_blast cannon_fire car_horn car_horn_2 card_cast card_draw card_play cash_pickup cash_pickup_2 character_select checkpoint chomp civilian_scream civilian_scream_2 coin_drop coin_pickup coin_pickup_2 core_collect 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 dice_rattle 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 enemy_attack energy_empty engine_acceleration engine_idle exit_unlock explosion finish finish_chime fish_caught fishing_cast fishing_reel flamethrower_burst flare_pop foe_die fog_horn food_complete food_complete_2 front_weapon_activation fusion_burst game_check game_end game_start gameplay_music gameplay_music_2 generator_start glimmer_bell gold_pickup golf_cup golf_swing grenade_launcher gunshot hammer_hit hammer_hit_2 heal_glow heartbeat hit hook_impact hook_impact_2 hook_throw hook_throw_2 item_drop item_pickup item_pickup_2 jet_engine laser_shot laser_shot_2 lasgun_shot level_up level_up_2 level_up_3 level_up_4 level_up_5 lighthouse_bell 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 missile_warning mole_sniper monster_attack monster_attack_2 monster_roar monster_roar_2 owl_hoot pickup piece_capture piece_lock piece_move pistol_reload pistol_reload_2 pistol_shot pistol_shot_2 place player_hit player_hurt player_hurt_2 police_siren punch punch_2 rain_ambience raptor_step ready_up rear_ability_activation relic_click reload repair resource_pickup respawn respawn_2 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 ship_horn shotgun_shot signal_ping siren slab_turn slap slap_hit speed_burst stone_rotate storm_thunder survivor_step sword_clang sword_clang_2 sword_hit sword_hit_2 sword_swing tire_skid toast_pop toy_pop trex_step turn_alert turn_bell 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 ward_up warning_bell warning_siren water_splash wave_crash wave_start weapon_switch whistle wind_gust wind_gust_2 wolf_howl wood_impact wrong_buzz zebrite_chime zombie_attack zombie_growl zombie_roar
|
|
64
|
-
effect: acid_splash arcane_cast arcane_impact arrow_hit bite_hit bite_splash blood_hit blood_splash boost_burst burner burner_2 burner_3 burner_4 burner_5 burner_6 burner_7 burner_8 burner_9 cannon_blast capture_burst cartoon_impact cash_sparkle cash_sparkle_2 coin_sparkle collapse_dust core_pickup 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 electric_sparks elemental_burst eliminated_burst enemy_hit energy_bolt evolution_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 hit_burst_2 hook_hit hook_hit_2 ice_shard impact_flash_critical impact_flash_small impact_shockwave impact_shockwave_2 impact_shockwave_3 impact_sparks impact_sparks_2 ink_cloud item_glow lightning_burst lightning_strike magic_blast magic_sparkle magic_vortex metal_hit meteor_fire mine_burst muzzle_flash muzzle_flash_2 objective_pickup player_hit poison_cloud rage_burst rainbow_burst rainbow_burst_2 rapid_slash repair_sparks respawn_burst respawn_burst_2 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 smoke_puff smoke_puff_2 sonar_pulse sparkle_burst sparkle_burst_2 sparkle_burst_3 sparkler speed_burst steam_burst step_dust stun_stars stun_stars_2 stun_stars_3 sword_hit sword_slash tank_burning tank_explosion terrain_blast top_collision_impact w_firethrowe w_firethrust_finale_2026 water_burst water_splash wind_burst wind_leaves
|
|
64
|
+
image: acid_slime acid_slime_m acid_slime_s acolyte airtank_icon ak_rifle_icon alien_bug angled_player_banner aorta art_aoe art_dodge art_ember art_empower art_evade art_flame art_fury art_guard art_heavy art_hex art_insight art_mend art_multi art_slash art_sweep art_venom art_ward ascended_one automaton awakened_one axe_icon banana_weapon_icon bandage_icon bandit banshee barracks_icon baseball_bat_icon bastion bean_icon bean_seeds_icon bear bee_swarm berries_icon berry_icon blue_slaver bone_icon book_icon book_of_stabbing boss_skull bread_icon bullet_icon byrd cabbage_icon campfire_icon canned_food_icon card_all_in card_bad_beat card_bargain card_borrowed_nerve card_brace card_charge card_chipped_edge card_cinch card_cleave card_dead_man_hand card_discipline card_double_slash card_doubling_down card_escalating_debt card_execute card_flail card_focus card_fortify card_fortune card_hex card_hexed_needle card_house_rules card_hunker card_inverted_wager card_last_stand card_ledger_balance card_loaded card_long_odds card_lunge card_marked_ledger card_mend card_pawn_the_ward card_pick_the_lock card_pray card_rage card_read_the_table card_reckless_cleave card_reversal card_scavenge card_sharpen card_shatter card_shave_the_die card_shield card_skull_crusher card_slash card_smash card_snap_shot card_snipe card_strain card_tallow_draught card_temper card_the_long_count card_the_whole_table card_tin_ward card_two_fingers card_unleash card_weaken card_weighted_coin card_whirlwind carrot_icon cave_rat cavern_battleground ceaseless_statue centurion champ cheese_icon chest_icon chosen chrono_wisp cinder_fiend clock_icon clockwork_hound coconut_icon coin_icon cooked_meat_icon cooked_meat_icon_v2 corrupt_heart crop_icon crossed_swords crossed_swords_2 crosshair crowbar_icon cultist cultist_acolyte cute_paw_cursor cutthroat dagger darkling darkling_spawn dash_icon deca deck_icon deck_icon_2 donu energy_icon exploder factory_icon fat_gremlin feather_icon fiber_icon fiber_plant_icon_v2 fish_bone_icon fish_icon fishing_rod_icon flamethrower_icon flint_icon fluffy_sheep_party_portrait foe_bone_abacus foe_chain_warden foe_coin_shill foe_marrow_cantor foe_needle_witch foe_tallow_priest foe_the_gutterhound foe_the_hexwright foe_the_house foe_wax_cur forest_ancient_tree_spirit_wide_splash forest_ent frail_icon fungi_beast fungi_sporeling fungus gnawing_mass goblin goblin_brute gold_coin_icon gold_icon gold_icon_2 gourd_icon green_louse gremlin gremlin_fat gremlin_leader gremlin_nob gremlin_sneaky gremlin_wizard grenade_launcher_icon guardian guardian_mech hand_icon harvester_icon health_icon health_icon_2 hero_necromancer hero_warrior hexaghost hide_icon hoe_icon honey_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 icon_compass impact_fx intent_attack intent_attack_debuff intent_block intent_buff intent_curse intent_debuff intent_sleep intent_unknown inverse_trapezoid_top_bar iron_ore_icon ironclad jaw_worm jawworm jungle_berry_icon_v2 knife_icon knight_helmet lagavulin laser_gun_icon leaf_icon lich loading_splash log_icon longodds_hall longodds_table looter louse lurker machine_gun_icon mackerel_icon mad_gremlin maw merc_portrait metal_cast_icon mold_icon monster_head moon_icon mystery_icon mystic nemesis ninja_runner nob node_boss node_elite node_fight node_rest node_shop obsidian_icon obsidian_sentry oozeslime orange_cat_party_portrait orb_walker orc panel_frame parasite parsnip_icon parsnip_seeds_icon pickaxe_icon pill_bottle_icon pistol_icon plank_icon player_debtor player_gambler player_hero poison_icon potato_icon potato_seeds_icon power_icon purple_hive_mind_insect_warrior_wide_splash qa_probe_gem radish_icon raw_meat_icon raw_meat_icon_v2 red_louse red_slaver refinery_icon regen_icon relic_chalice relic_core relic_gauntlet relic_lantern relic_oathplate relic_serpent reptomancer repulsor resin_icon revolver_icon rifle_icon road_tiles_icon road_tiles_icon_2 robot_face robot_vending_mech_champion_wide_splash rocket_launcher_icon rope_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 sentry shellwarden shield_gremlin shotgun_icon silent skeleton skeleton_archer skill_dagger_icon skill_fireaura_icon skill_hammer_icon skill_shield_icon skill_stealth_icon slash_fx slaver slime_boss slime_horror snake_dagger snapper_icon sneaky_gremlin snecko snecko_hatchling sniper_rifle_icon snowflake_spin soda_can_icon spear_icon spear_icon_v2 spider spike_slime spike_slime_l spike_slime_m spike_slime_s spiker spire_acolyte spire_shard spire_shield spire_spear squid_icon steak_icon stick_icon stone_icon straight_road_icon_transparent_no_background submachine_gun_icon sun_icon syringe_gun_icon tank_icon taskmaster 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 thorns_icon time_eater torch_icon torch_icon_v2 traffic_light_icon traffic_light_icon_2 traffic_light_icon_transparent_no_background transient tuna_icon turret_icon twigs_icon undead_death_knight_wide_splash undead_skull vagrant vampire ventricle vulnerable_icon warden water_bottle_icon water_drop_icon water_gourd_icon_v2 watering_can_icon weak_icon werewolf white_chicken_party_portrait witch withered_titan wolf wood_icon yokai_mask yokai_samurai_oni_wide_splash
|
|
65
|
+
sound: ambient_horror apartment_ambience arena_warning baby_raptor_step backfire ball_hit banana_boomerang baton_hit baton_swing bear_shotgun bite blade_hit blast blockup body_thump body_thump_2 book_open boost boost_burst bow_hit branch_snap brass_gong cannon_blast cannon_fire car_horn car_horn_2 card_cast card_draw card_play cash_pickup cash_pickup_2 character_select checkpoint chomp civilian_scream civilian_scream_2 click coin_drop coin_pickup coin_pickup_2 core_collect 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 deep_hum deny dice_rattle distant_groan dodge dodge_dust dodge_dust_2 dog_bark dog_pistol door_close door_creak door_creak_long door_open door_open_2 door_unlock dread_horn dry_swallow dual_hit earthquake_rumble earthquake_rumble_2 electric_burst electric_shock elevator_ding eliminated eliminated_2 enemy_attack energy_empty engine_acceleration engine_idle exit_unlock explosion finish finish_chime fish_caught fishing_cast fishing_reel flamethrower_burst flare_pop fluorescent_buzz foe_die foe_turn fog_horn food_complete food_complete_2 found_chime front_weapon_activation fusion_burst game_check game_end game_start gameplay_music gameplay_music_2 generator_start gentle_wind_chime glimmer_bell gold_pickup golf_cup golf_swing grenade_launcher gunshot hammer_hit hammer_hit_2 heal_glow heartbeat hit hook_impact hook_impact_2 hook_throw hook_throw_2 horror_sting item_drop item_pickup item_pickup_2 jet_engine knell knife_hit laser_shot laser_shot_2 lasgun_shot level_up level_up_2 level_up_3 level_up_4 level_up_5 lighthouse_bell line_clear lose machine_gun machine_gun_reload machine_gun_shot magic_blast medkit_pickup medkit_use menu_music metal_hit metal_hit_2 mine missile_launch missile_warning mole_sniper monster_attack monster_attack_2 monster_roar monster_roar_2 owl_hoot page_turn pickup piece_capture piece_lock piece_move pistol_reload pistol_reload_2 pistol_shot pistol_shot_2 place player_breath player_hit player_hurt player_hurt_2 police_siren punch punch_2 rain_ambience raptor_step ready_up rear_ability_activation refuse relic_click reload repair resource_pickup respawn respawn_2 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 shield_clang ship_destroyed ship_horn shotgun_shot signal_ping siren slab_turn slap slap_hit slash soft_wind_chime speed_burst stone_rotate storm_thunder survivor_step sword_clang sword_clang_2 sword_hit sword_hit_2 sword_swing tap tire_skid toast_pop toy_pop trex_step triumph turn_alert turn_bell 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 ward_up warning_bell warning_siren water_drip water_splash wave_crash wave_start weapon_reload weapon_switch whistle win wind_gust wind_gust_2 wind_howl wolf_howl wood_impact wrong_buzz wrong_pick zebrite_chime zombie_attack zombie_growl zombie_roar
|
|
66
|
+
effect: acid_splash arcane_cast arcane_impact arrow_hit aurora barrier_impact basic_hit_impact basic_sword_slash bat_projectile bite_hit bite_splash black_hole blaster_laser blaster_laser_impact blessing_burst blood_ground_splatter blood_hit blood_hit_splash blood_splash blue_plasma_ball blue_plasma_impact boost_burst brief_smoke_puff bullet_blood_splash bullet_impact bullet_trail burner burner_2 burner_3 burner_4 burner_5 burner_6 burner_7 burner_8 burner_9 campfire candle_flame cannon_blast capture_burst cartoon_impact cash_sparkle cash_sparkle_2 charm_aura chest_item_shine chest_top_shine coin_sparkle collapse_dust core_pickup crash_burst critical_smoke cute_star_pickup_burst damage_smoke damage_sparks damage_sparks_2 damage_sparks_3 dash_trail dash_trail_2 dense_ripples dismember dodge_dust dropped_item_marker dust_puff dust_puff_2 dust_puff_3 electric_ball_impact electric_ball_projectile electric_burst electric_overheat_shock electric_sparks elemental_burst eliminated_burst enemy_hit energy_bolt energy_charge environmental_electric_sparks evolution_burst explosion explosion_burst falling_green_petals falling_sakura_petals falling_snow finish_confetti fire_burst fire_impact_realistic fire_impact_stylized fireball fireball_burst fireball_projectile fireflies firework flamethrower_stream flower_area_sparkle flower_burst flying_birds forward_dash_lines forward_muzzle_flash ghost_mist god_rays gold_money_obtained gold_rush golf_cup golf_hit green_circular_area grenade_blast ground_click_marker ground_hologram ground_impact_stylized ground_ping_alert ground_smoke_impact gun_hit_ring_stylized gun_muzzle_flash hammer_impact heal_glow healing_aura healing_burst healing_glow healing_potion_activation heavy_critical_impact heavy_divine_impact heavy_lightning_ground_impact heavy_lightning_strike hit_burst hit_burst_2 hook_hit hook_hit_2 ice_shard ice_smoke_ground_impact impact_flash_critical impact_flash_small impact_shockwave impact_shockwave_2 impact_shockwave_3 impact_sparks impact_sparks_2 ink_cloud item_glow jump_smoke_realistic jump_smoke_stylized large_area_ground_fog large_cloud large_waterfall laser_beam laser_beam_muzzle lava_eruption level_up_burst level_up_light_beam lightball_charge lightball_projectile lightning_burst lightning_strike lightning_strike_impact lingering_smoke_cloud magic_ball_projectile magic_blast magic_ring magic_sparkle magic_vortex magic_wand_impact mana_potion_activation mega_flameball metal_hit meteor_fire meteor_ground_impact mine_burst missile_smoke_trail muzzle_flash muzzle_flash_2 neutral_circular_area objective_pickup orbital_laser orbital_laser_impact overheat_smoke parry_impact player_hit poison_ball_impact poison_ball_projectile poison_cloud poison_ground_area punch_impact radiant_impact_burst rage_burst rainbow_burst rainbow_burst_2 rainbow_trail rapid_slash red_circular_area red_eye_flash repair_sparks respawn_burst respawn_burst_2 revive_burst revive_glow rickshaw_burn ringout_explosion rocket_explosion rot_pulse rotten_smoke_aura rune_pickup saliva_drip sci_fi_item_spawn shallow_water_caustics shield_burst shield_pop single_ripple sky_rainbow sky_stars slap_hit slash_burst slash_burst_2 slash_burst_3 small_explosion small_waterfall smoke smoke_heavy_explosion smoke_puff smoke_puff_2 snow_aura snowball_impact snowball_projectile soft_holy_light_impact sonar_pulse spark_bomb_fuse spark_impact sparkle_burst sparkle_burst_2 sparkle_burst_3 sparkler speed_burst spinning_sword_wind_wave spotlight steam_burst step_dust stun_aura stun_stars stun_stars_2 stun_stars_3 sword_hit sword_impact sword_slash tank_burning tank_explosion terrain_blast thruster_flame top_collision_impact torch_flame toxic_ground_impact toxic_rain_trail volcano_smoke w_firethrowe w_firethrust_finale_2026 walking_puff_stylized warp_arrival warp_departure warp_gate warp_ground_residue water_bubbles water_burst water_fountain water_ground_impact water_splash water_splash_realistic water_splash_stylized waterball_projectile wind_burst wind_impact wind_leaves windball_projectile
|
|
65
67
|
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
|
|
66
68
|
</asset_word_library>
|
|
67
69
|
|
|
@@ -70,30 +72,31 @@ flipbook: blood_fine blood_mist blue_flame bubble_float dust_fine_grey dust_puff
|
|
|
70
72
|
- `#texture Name ... #end` auto-creates triplanar `material Name`. Use it as `material = "Name"` in scene objects, `Material.Name` in Weave code, `terrain.SetTerrainMaterial(Material.Name)`, `terrain.SetTerrainLayers(...)`, `batch.SetBatchMaterial(Material.Name)`, or as a local `#mesh` slot name (`material: "Name"` / `paint(..., material: "Name")`).
|
|
71
73
|
- Masonry patterns (pattern.brick/tile) under triplanar mapping project straight planar joints; on carved/round geometry (columns, moldings, statues) use a coursing-free variant or `mapping = uv;`.
|
|
72
74
|
- Flat color shorthand: `#texture TeamRed color=#B03A2E` creates a non-emissive triplanar `material TeamRed` — for stylized color-blocking and quick placeholders; surfaces meant to read as real should use the built-in library (next clause). Optional `roughness=0..1` and `metallic=0..1` (e.g. `#texture RubberFloor color=#1E2024 roughness=0.95`) — without a high roughness, dark ground colors read pale from sky reflection.
|
|
73
|
-
- Built-in material library — real textured PBR with zero declarations: `material = "Wood"` on any object/batch/terrain (and `Material.Wood` in code) just works; the engine copies the one-line library clause into the world on save, and a world-declared material of the same name always wins. Library: Wood, WoodDark, Plank, Bark, Stone, Rock, Brick, Dirt, Sand, Metal, MetalDark, Gold, Fabric, Cloth, Rope, Straw, Leather, Foliage, Leaf, Grass, Snow, Ceramic, Bone, Glass, GlassTransparent, Water, Default; authored surfaces StylizedBricks, OldTilesWhite, StylizedGrass, PolishedConcrete, Asphalt. Default to these for anything meant to read as a real surface.
|
|
75
|
+
- Built-in material library — real textured PBR with zero declarations: `material = "Wood"` on any object/batch/terrain (and `Material.Wood` in code) just works; the engine copies the one-line library clause into the world on save, and a world-declared material of the same name always wins. Library: Wood, WoodDark, Plank, Bark, Stone, Rock, Brick, Dirt, Sand, Metal, MetalDark, Gold, Fabric, Cloth, Rope, Straw, Leather, Foliage, Leaf, Grass, Snow, White, Ceramic, Bone, Glass, GlassTransparent, Water, Default; authored surfaces StylizedBricks, OldTilesWhite, StylizedGrass, PolishedConcrete, Asphalt. Default to these for anything meant to read as a real surface. MetalDark is a cool mid-grey (#75808B), not near-black - for black metal declare `material Iron { base = "MetalDetail" tint = "#1a1c1f" }`.
|
|
74
76
|
- Derived material (color variant, no extra texture bake): `material WoodRed { base = "Wood" tint = "#8a2b1e" }` copies shader/textures/params from the base material and multiplies its color by tint (quoted hex). `base` may name any built-in above or a tintable near-white detail family (WoodDetail, StoneDetail, MetalDetail, FabricDetail, LeatherDetail, PlasterDetail). Prefer this over writing a `#texture` body when only the color differs.
|
|
75
|
-
Material clauses also accept `emission = N` (self-lit glow in the material's tinted color; linear: 1
|
|
76
|
-
- Use #texture directly on primitives, terrain, batches, and local `#mesh` slots. For #mesh material precedence: object/batch override > explicit submesh override > authored local mesh slot material > intrinsic GLB PBR. Imported GLB material names are not auto-bound to world materials. `tile_m` = meters per pattern repeat (default 1.0, prop scale): RAISE to `2.0;`..`4.0;` for large terrain/floors so repeats are not too tiny; LOWER to `0.3;`..`0.5;` for small props/panels so the pattern does not print larger than the object. Material clauses accept it too (`material X { base = "Fabric" tileM = 0.4 }`).
|
|
77
|
+
Material clauses also accept `emission = N` (self-lit glow in the material's tinted color; linear: 0.3-0.5 = tinted glow that keeps its colour, 1 = as bright as a sunlit white surface, 2 = pastel, 4+ reads white (bloom carries the tint), 8+ only for sub-pixel LEDs / sun discs) and `roughness = 0..1` / `metallic = 0..1` (uniform overrides of the baked surface response) — e.g. `material CyanGlow { base = "MetalDetail" tint = "#19D9FF" emission = 1.5 }`. Opaque materials also accept `lighting = "snow"`: engine snow shading (soft wrapped terminator, low-sun backscatter, distance-faded ice glints; built-in Snow carries it already) for snowy ground/drift materials. `snow_cover = "off"` keeps a material bare under SetSnowCover (interior props, signs).
|
|
78
|
+
- Use #texture directly on primitives, terrain, batches, and local `#mesh` slots. For #mesh material precedence: object/batch override > explicit submesh override > authored local mesh slot material > intrinsic GLB PBR. Imported GLB material names are not auto-bound to world materials; a model's own imported maps are reusable without re-upload: `material X { shader = "..." textures = "model.<creator>.<name>" }` fills tex0/1/2 (basecolor/normal/ORM) — inspect_model lists each model's maps with per-slot urls. `tile_m` = meters per pattern repeat (default 1.0, prop scale): RAISE to `2.0;`..`4.0;` for large terrain/floors so repeats are not too tiny; LOWER to `0.3;`..`0.5;` for small props/panels so the pattern does not print larger than the object. Material clauses accept it too (`material X { base = "Fabric" tileM = 0.4 }`).
|
|
77
79
|
- Pixel-art / retro texel look: `filter = nearest;` samples the baked maps with hard texel edges (no bilinear smoothing, no block compression). Pair with a small bake (`size = 16;`..`64;`) or constant-cell patterns, and usually `mapping = uv;`. Everything else keeps the default linear filtering.
|
|
78
80
|
- Authoring or editing a `#texture` BODY (anything beyond the color=/base= one-liners above): read the `texture_dsl` skill first — statement syntax, builtins (noise/pattern/sdf/filter families), recipes, worked examples. Do not guess builtin names or signatures from memory.
|
|
79
81
|
- Terrain layer sets: assign scalar `out.height` on every layer of the set (or none) — higher-height texels win at SetTerrainLayers blend borders (rock pushing through grass).
|
|
80
82
|
- `#terrain_splat Name ... #end` + `terrain.SetTerrainSplat("Name")`: same expression language with terrain inputs `height` (world m), `slope01` (0 flat..1 vertical), `convex` (-1..1), `ao` (0..1), `moist` (0..1), `user` (0..1, fed by `terrain.SetTerrainSplatMask(mask, sx, sy)`, else 0); `out.color` RGB = SetTerrainLayers Steep/High/Low weights (base = leftover). Baked per-terrain; replaces the slope/height auto-bands for hand-authored placement (e.g. `out.color = vec3(smoothstep(0.4, 0.6, slope01), smoothstep(18, 24, height), sat(moist * 2 - convex));`).
|
|
81
83
|
- Optional scalar `out.grass` in `#terrain_splat` = grass spawn density 0..1 (0 = bare; cover saturates around 0.4, and below ~0.5 grass breaks into clumps whose edge tufts shrink and lose blades, so a painted gradient ends in wispy patches, not a hard line) - keeps grass off beaches/cliffs/dry zones from the same rules that place the textures. Unassigned = full density; an explicit SetTerrainGrassWeightmap overrides it.
|
|
82
84
|
- Colormap mode: `out.albedo` (vec3, mutually exclusive with `out.color`) makes the bake the FINAL surface color instead of layer weights - full per-pixel control (satellite-style coloring, stylized palettes, drainage streaks from `user`). The base SetTerrainMaterial still supplies normal/ORM detail; SetTerrainLayers weights, band blending and macro tint are all bypassed. Set `size = 2048;` (up to 4096) for crisp color; `out.grass` still works alongside.
|
|
83
|
-
- `#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.
|
|
85
|
+
- `#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), `path = "M x,y L ... C ... Z", classIndex;` (repeatable: SVG path data in absolute cm with page-up = +Y; every vertex becomes a node, vertices within 1 cm of an existing node merge into junctions, L/H/V segments become edges, C/Q/S/T/A segments become `curve` edges, `Z` closes to the start - draw a street plan as one drawing with junction points shared between paths; editor saves normalize it into nodes/edges/curve statements). 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.
|
|
84
86
|
- `#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.
|
|
85
|
-
- Emission is linear (1
|
|
87
|
+
- Emission is linear (0.3-0.5 = tinted glow that keeps its colour, 1 = as bright as a sunlit white surface, 2 = pastel, 4+ reads white (bloom carries the tint), 8+ only for sub-pixel LEDs / sun discs): put it on small accents - lamps, signs, runes, windows; large emissive surfaces wash out the scene, keep those <= 1.
|
|
86
88
|
- 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.
|
|
87
89
|
</texture_dsl_usage>
|
|
88
90
|
|
|
89
91
|
<adjuster_usage>
|
|
90
92
|
- `#adjuster ... #end` (top-level): declares hand-tunable global look knobs. Values replay at load end - an OnSpawned Set* of the same value overwrites the user's tune every load (event-driven changes later are fine); slider edits fold back into this block on save. Sliders: grass/ground knobs in the Terrain inspector (click the terrain), SetWater* in Find > Water, the rest in the Adjust panel (top-right sliders icon; links to both inspectors).
|
|
91
|
-
- Body lines: `section "Title"` groups knobs after it; `knob <SimCallName> = <value> [range a..b] [user]`; value is a number,
|
|
93
|
+
- Body lines: `section "Title"` groups knobs after it (cosmetic for scene knobs - the panel regroups them by engine family); `knob <SimCallName> = <value> [range a..b] [user]`; value is a number, `#rrggbb` for color knobs, or a listed word for choice knobs; `range` overrides the slider range of number knobs; a trailing `user` marks the line user-LOCKED (see below). `//` comments ok.
|
|
92
94
|
- Only whitelisted global sim calls (below) are valid knob names; each at most once. Texture params and ranged #mesh params expose per-texture/per-mesh panel knobs on their own; no #adjuster entry for those.
|
|
93
95
|
- 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).
|
|
94
|
-
-
|
|
96
|
+
- Any knob line can carry a trailing ` user` lock (the panel's lock icon; [user] lighting/grade knobs below gain it automatically when the USER tunes them): patches retuning, removing, or unlocking that LINE are rejected (their tune is sovereign), and a script Set* you add on a locked knob blocks submit - retune locked knobs only via the propose_adjust_values tool (an [Apply values] card; only the user's click applies). UNMARKED knob lines - [user] ones included, delegated mood work, fresh worlds - are yours to author as knobs (never as Set* calls: an OnSpawned Set* overwrites the panel every load). Never write or strip a ` user` marker yourself. Dark/moody art direction also works without grade knobs: lights, emissive materials, fog (SetFog* calls/knobs are game-ownable), enclosure, SetVolumetricLightIntensity.
|
|
97
|
+
- Relative nudges ("30% brighter", "shadows a bit lighter"): propose_adjust_deltas({"SetSunIntensity": "+30%"}) reads the live values and mints the same [Apply values] card - one call, no patch/playtest/submit round per nudge.
|
|
95
98
|
- SetWater* knobs set the INITIAL ocean state: a `knob SetWaterEnabled = 0` line keeps water off across reloads (the editor's Find > Water delete writes it).
|
|
96
|
-
- 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),
|
|
99
|
+
- 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), SetGrassBladeDensityPercent (10..100), SetGrassSpacingCm (0..100), SetGrassTerrainActiveDistanceM (0..500), SetGrassCullDistanceM (0..500), SetGrassFadeDistancePercent (0..100), SetGrassFarThinningPower (0..8), SetTerrainErosionDetailPercent (0..300), SetTerrainNormalStrengthPercent (0..300), SetTerrainDisplayExtension (0..8000), SetSunTilt (0..90), SetSunRotation (0..360), SetSunIntensity (0..20) [user], SetSunColor (color) [user], SetSunSpecularScale (0..3), SetSkyLightIntensity (0..8) [user], SetSkyLightColor (color) [user], SetSkyLightSaturation (0..3) [user], SetSkyboxCloudCoverage (0..1), SetSkyboxCloudDetail (0..3), SetSkyboxCloudScale (0..4), SetSkyboxCloudType (0..1), SetSkyboxExposure (0..3) [user], SetSkyboxSaturation (0..3) [user], SetSkyboxContrast (0..3) [user], SetSkyboxTint (color) [user], SetSkyboxHaze (0..8) [user], SetSkyboxGroundColor (color) [user], SetSkyboxStarIntensity (0..3), SetSkyboxColor (color) [user], SetSkyboxSunVisible (0/1), SetSkyboxHorizonTilt (-45..45), SetSkyboxRotation (0..360), SetSkyboxHue (-180..180), SetFogColor (color), SetFogStartDistance (0..2000), SetFogEndDistance (0..2000), SetFogSkyboxAffect (0..100), SetHeightFogEnabled (0/1), SetHeightFogBottom (-100..200), SetHeightFogTop (0..200), SetHeightFogSoftness (0..1), SetShadowDistance (0..500), SetShadowBlurRadius (0..20) [user], SetShadowOpacity (0..1) [user], SetShadowLift (0..3) [user], SetShadowLiftThreshold (0.02..0.3) [user], SetLocalShadowBlurRadius (0..64), SetShadowDepthBiasConstant (0..16), SetShadowDepthBiasSlopeScale (0..8), SetAllLocalShadowsEnabled (0/1), SetStaticLodShadowTransition1 (0..1), SetStaticLodShadowTransition2 (0..1), SetStaticLodShadowTransition3 (0..1), SetExposure (-3..3) [user], SetContrast (0..4) [user], SetSaturation (0..4) [user], SetBloomThreshold (0..3) [user], SetBloomIntensity (0..2) [user], SetBloomSoftKnee (0..1), SetBloomClampValue (0..16), SetSsaoIntensity (0..1) [user], SetSsaoDistance (0..10), SetSsrMode (Off|Low|High), SetSsrIntensity (0..5), SetSsrRoughnessBlurMultiplier (0..8), SetSsrRoughnessMipClampLower (0..8), SetSsrRoughnessMipClampUpper (0..8), SetSsrRoughnessFadeStart (0..1), SetSsrRoughnessFadeEnd (0..1), SetSsrRayFadeNear (0..8), SetSsrRayFadeFar (0..8), SetVolumetricLightIntensity (0..1000), SetVolumetricLightDensity (0..1000), SetVignetteStrength (0..1) [user], SetVignetteRadius (0..1) [user], SetVignetteSoftness (0..1) [user], SetVignetteColor (color) [user], SetWindDirectionDeg (0..360), SetWindStrength (0..1), SetSnowCover (0..1), SetWindGustiness (0..1), SetTreeLodSwitchDistanceM (0..300), SetTreeMeshDistanceM (0..1000), SetTreeCullDistanceM (0..3000), SetTreeFadeDistancePercent (5..80), SetTreeFarLeafDensityPercent (10..300), 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), SetWaterCausticIntensity (0..3), SetWaterReflectionStrength (0..2), SetWaterReflectionDistortion (0..2)
|
|
97
100
|
Example:
|
|
98
101
|
#adjuster
|
|
99
102
|
section "Grass"
|
|
@@ -107,17 +110,17 @@ knob SetGrassHeightMaxCm = 45 range 0..120
|
|
|
107
110
|
- Every local component needs a top-level `"particleTextureName"` (components binding `"material"` may omit it): `"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).
|
|
108
111
|
- Spawn with scene `effect Spark { effect = "effect.Name" }` - or, for prop-attached fire/smoke, prefer a `particles("<ref>", 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). For a muzzle flash or any follow-effect: `SpawnEffectAttached(Ori.effect.Name, holder, "muzzle", 0)` - never chase with per-frame SetPosition.
|
|
109
112
|
- 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.
|
|
110
|
-
- 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.
|
|
113
|
+
- JSON values (strict JSON: negatives are `-0.82`, never `0 - 0.82`): 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.
|
|
111
114
|
- 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).
|
|
112
115
|
- Flipbook keys: `framesX`, `framesY`, `totalFrames`, `flipbookAnimationSpeed`, `flipbookStartRandom`. For `flipbook.<word>` refs these auto-fill from the library at load; set them only to override.
|
|
113
116
|
- Custom shading: `"material": "M"` (billboard components; material with a `#shader`) replaces the texture sample with that shader's fragment - SDF shapes (crisp at any size), dissolves, code-driven looks. Body writes `out.color` from ctx (`life01`, `flipbook_color`, `tint`, ...) - contract in the shader_dsl skill; the other component keys (lit, additiveBlend, sequences, fades) still apply.
|
|
114
|
-
- Spawn keys: `spawnStartDelay`, `spawnRate` per sec, `isLooping
|
|
117
|
+
- Spawn keys: `spawnStartDelay`, `spawnRate` per sec, `duration` seconds, `isLooping` (default `0` = one-shot: a finite `duration` stops emission, `0` streams `spawnRate` on but fires bursts once, and `SpawnEffectWithAutoDestroy` removes the effect after `spawnStartDelay + duration` + particle life; `1` = restart every `spawnStartDelay + duration`, `duration` `0` = never stop - set it on every continuous or repeating emitter), `burstParticleCount` (fires at t=0, then every `burstInterval` seconds while emitting; `burstInterval` unset = the t=0 burst only).
|
|
115
118
|
- Shape keys: `emitterShapeType` = `"sphere"|"box"|"cylinder"|"disc"` or `0..3`; `shapeStyle` = `"volume"|"surface"`; `shapeInOut` = `"in"|"out"|"both"` (omitted defaults inward); `radius`, `cylinderHeight`, `boxSize`, `shapePartial` (fraction of the shape, default 1 = full; sphere: polar cap toward +Z, cylinder: 1 cylinder -> 0 cone, disc: 1 full disc -> 0 rim ring), `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).
|
|
116
119
|
- 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 camera billboard / 1 upright billboard (up locked world-up, still turns to face the camera - trees, flames) / 2 velocity-parallel / 3 velocity-perpendicular / 4 flat on the ground (ripples, rings, ground decals); `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).
|
|
117
120
|
- 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).
|
|
118
121
|
- 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`.
|
|
119
122
|
- 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.
|
|
120
|
-
- 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
|
|
123
|
+
- 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; an unresolved model displays a placeholder cube) — 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.
|
|
121
124
|
- 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.
|
|
122
125
|
Example:
|
|
123
126
|
#texture SmokePuff
|
|
@@ -132,7 +135,7 @@ out.alpha = smoothstep(0.48, 0.18, d);
|
|
|
132
135
|
#end
|
|
133
136
|
#particles SmallSmoke
|
|
134
137
|
[
|
|
135
|
-
{ "particleTextureName": "texture.SmokePuff.color", "boundingBoxSize": [1, 1, 2], "boundingBoxCenter": [0, 0, 0.9], "renderResolution": "half", "spawnRate": 18, "
|
|
138
|
+
{ "particleTextureName": "texture.SmokePuff.color", "boundingBoxSize": [1, 1, 2], "boundingBoxCenter": [0, 0, 0.9], "renderResolution": "half", "spawnRate": 18, "isLooping": 1, "lifeTimeRange": [0.8, 1.4], "emitterShapeType": "sphere", "shapeStyle": "volume", "shapeInOut": "out", "radius": 0.2, "speedRange": [0.3, 0.8], "spreadAngle": [25, 35], "sizeSequence": [[0, 0.25], [1, 1.2]], "opacitySequence": [[0, 0.0], [0.15, 0.5], [1, 0.0]], "colorConstant": [0.65, 0.62, 0.55], "accelerationVector": [0, 0, 0.8], "drag": 0.7 }
|
|
136
139
|
]
|
|
137
140
|
#end
|
|
138
141
|
effect ChimneySmoke {
|
|
@@ -157,29 +160,29 @@ out = normalize(biquad(lp, sweep, cutoff = 2200, q = 1.2) * env_adsr(0.005, 0.1,
|
|
|
157
160
|
|
|
158
161
|
<mesh_dsl_usage>
|
|
159
162
|
- `#mesh <Name> ... #end` defines a local CPU-baked procedural static mesh; reference it as `model = "mesh.Name"` in scene declarations or `Ori.model.mesh.Name` in Weave code (SpawnObject, CreateStaticInstanceBatch). Authoring units are simulation centimeters, Z-up; baked meshes are bottom-center anchored at object origin and their deterministic cm AABB supplies box-collider bounds.
|
|
160
|
-
- `#mesh <Name> destructible: masonry|wood|rock|concrete` bakes a hidden debris chunk set for the model; `obj.ShatterAndDestroy()` then bursts the object into tumbling chunks that bounce, settle, and fade (display-only, no sim collision; without the tag it acts as plain Destroy()). Preview with the preview_destruction tool; destructible mesh names cap at 46 chars.
|
|
161
|
-
- For standard props (crate, barrel, market_stall, ...) AND stock structure pieces the library has as words (wall, tower, watchtower, gate, fence, bridge, stair, shipping_container, ...), PREFER a bare `alias model.<noun>` (see <asset_aliases>): it binds
|
|
162
|
-
- `#mesh` is THE tool for bespoke level structure the play depends on - arena shells, ramps and multi-level platforms at exact sizes, buildings/facades, arches, custom cover - and for any custom shape or exact part control. `mesh_library_search` first (
|
|
163
|
+
- `#mesh <Name> destructible: masonry|wood|rock|concrete [piece_cm]` bakes a hidden debris chunk set for the model; `obj.ShatterAndDestroy()` then bursts the object into tumbling chunks that bounce, settle, and fade (display-only, no sim collision; without the tag it acts as plain Destroy()). The optional number is the target piece size in cm (50..=1000) - e.g. `destructible: concrete 150`; omitted, piece size auto-scales so the model lands near the chunk budget (~2000 pieces), and tiny thin parts (panes, trim) don't bake chunks. Bakes run lazily in the background (tagging many/large meshes is fine). Preview with the preview_destruction tool; destructible mesh names cap at 46 chars.
|
|
164
|
+
- For standard props (crate, barrel, market_stall, ...) AND stock structure pieces the library has as words (wall, tower, watchtower, gate, fence, bridge, stair, shipping_container, ...), PREFER a bare `alias model.<noun>` (see <asset_aliases>): it binds an existing library mesh at load; when none fits, adapt or author one; instance, rotate and `height=`-scale them into layouts. Trees are the exception: prefer a `#tree` species (hero/single) or `#forest` region (woods) - wind sway, LODs, slim per-trunk collision (see <tree_dsl_usage>); `alias model.tree` is a static low-poly prop that box-collides its whole canopy.
|
|
165
|
+
- `#mesh` is THE tool for bespoke level structure the play depends on - arena shells, ramps and multi-level platforms at exact sizes, buildings/facades, arches, custom cover - and for any custom shape or exact part control. `mesh_library_search` first (import/adapt an existing piece), hand-author when nothing fits; walkable ramps/arches need `collision = mesh` (default collider = full AABB); `BuildRoom` (<room_building>) covers plain rectangular rooms.
|
|
163
166
|
- Authoring or editing a `#mesh` body: read the `mesh_dsl` skill first — full language + builtin reference and the preview workflow. Do not guess builtin names or signatures from memory; unknown, duplicate, or wrong-type arguments fail loudly.
|
|
164
167
|
- Lights on meshes: an `emitter("Bulb", at:, color:, intensity:, kind: "point"|"spot", ...)` line in the mesh body bakes a light socket; every placed instance shines from it (lamps, signs, projectors) - no separate light object needed. Syntax in the `mesh_dsl` skill; per-object toggle `Object.SetEmitterLightsEnabled(false)`.
|
|
165
168
|
- Effects on meshes: `particles("<ref>", 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 quoted ref is a local `#particles` block name (case-sensitive) or a marketplace `Ori.effect.<creator>.<name>`; anything else fails validation. Rest-pose like emitter(); prefer loops (fire, smoke, drips). For prop-attached fire/smoke prefer this over hand-placed effect objects.
|
|
166
169
|
- 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.
|
|
167
|
-
- Canonical slot names auto-fill from the built-in material library when the world
|
|
170
|
+
- Canonical slot names auto-fill from the built-in material library when the world does not declare them (name list in <texture_dsl_usage>). Imported library meshes retain private material definitions; restyle them by editing those definitions.
|
|
168
171
|
- 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.
|
|
169
172
|
- 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).
|
|
170
173
|
</mesh_dsl_usage>
|
|
171
174
|
|
|
172
175
|
<tree_dsl_usage>
|
|
173
176
|
- `#tree Name ... #end` (top-level): procedural tree species `tree.Name` for scene objects (`model = "tree.Name"`). Deterministic: trunk + branches become the sim collider; the renderer adds detail, leaf cards, LODs, impostors, and wind sway automatically.
|
|
174
|
-
- Body is integer-only `key: value` lines (all optional; defaults are a curated broadleaf oak, so `seed:` alone gives a good tree). Keys: seed, levels (1-4), children (1-16), rings (whorl only: 0-40 branch rings along the trunk, decoupled from segments; 0 = one per segment - reference firs want ~15-20; members auto-stagger vertically), fill (whorl only: 0-16 short branches between rings - dense conifers), segments (2-8), collider_levels (dense conifers should author 1 - collide with the trunk, not hundreds of branchlets), trunk_height (cm), trunk_radius (cm), length_pct, radius_pct, angle_deg (child pitch from the parent axis; >90 emits below horizontal - with up_bias_pct the branch swoops down then up, the fir/spruce shelf), angle_jitter_deg, up_bias_pct, curve_jitter_pct, trunk_lean_deg (whole-trunk tilt, default 2; the trunk-shape low band), trunk_sweep_pct (one C- or S-arc over the trunk height, default 10; the mid band), trunk_noise_pct (trunk wobble amplitude; 0 = dead-straight leader with curve_jitter_pct branches) + trunk_noise_scale_pct (its wavelength as % of trunk height, 8-100, default 35; small = ragged bark-beat, large = slow bends - the high band), trunk_gnarl_pct (0-100; display-only radial lobe noise on the thick lower trunk - buttress/character silhouette for hero close-ups; collider stays smooth), leaves (frond stations per end branch), leaf_size (cm; mean size of one leaf-cluster card - each card is a baked spray of many leaves, not a single leaf; default 150), leaf_base (cm; no leaf cards below this height - bare forks/scaffolds; leaf_base_fade cm band above it ramps density to full, default 120), leaf_shell_pct (0-100; blend toward smooth per-pixel crown-shell shading - 0 = flat per-card facing, 100 = crown shades as a smooth rounded volume; default 100), leaf_clump_pct (0-100; shifts that shell reference from the whole-crown center toward each level-1 branch clump's own center, so big canopies shade as separate puffy lobes instead of one ball; default 40), leaf_detail_pct (0-300; leafy normal-detail sparkle bumped from the frond texture itself; 0 = smooth shell only; default 200), leaf_ao_pct (0-200; canopy AO strength darkening cards near the trunk column and canopy bottom; 0 = off; default 40), leaf_curl_pct (0-300; how strongly leaf cards bow out of their plane for varied, non-flat silhouettes; 0 = flat cards; default 150), leaf_far_shade_pct (0-150; far-billboard brightness;
|
|
177
|
+
- Body is integer-only `key: value` lines (all optional; defaults are a curated broadleaf oak, so `seed:` alone gives a good tree). Keys: seed, levels (1-4), children (1-16), rings (whorl only: 0-40 branch rings along the trunk, decoupled from segments; 0 = one per segment - reference firs want ~15-20; members auto-stagger vertically), fill (whorl only: 0-16 short branches between rings - dense conifers), segments (2-8), collider_levels (dense conifers should author 1 - collide with the trunk, not hundreds of branchlets), trunk_height (cm), trunk_radius (cm), length_pct, radius_pct, angle_deg (child pitch from the parent axis; >90 emits below horizontal - with up_bias_pct the branch swoops down then up, the fir/spruce shelf), angle_jitter_deg, up_bias_pct, curve_jitter_pct, trunk_lean_deg (whole-trunk tilt, default 2; the trunk-shape low band), trunk_sweep_pct (one C- or S-arc over the trunk height, default 10; the mid band), trunk_noise_pct (trunk wobble amplitude; 0 = dead-straight leader with curve_jitter_pct branches; -1 = the default auto, follows curve_jitter_pct) + trunk_noise_scale_pct (its wavelength as % of trunk height, 8-100, default 35; small = ragged bark-beat, large = slow bends - the high band), trunk_gnarl_pct (0-100; display-only radial lobe noise on the thick lower trunk - buttress/character silhouette for hero close-ups; collider stays smooth), leaves (frond stations per end branch), leaf_size (cm; mean size of one leaf-cluster card - each card is a baked spray of many leaves, not a single leaf; default 150), leaf_base (cm; no leaf cards below this height - bare forks/scaffolds; leaf_base_fade cm band above it ramps density to full, default 120), leaf_shell_pct (0-100; blend toward smooth per-pixel crown-shell shading - 0 = flat per-card facing, 100 = crown shades as a smooth rounded volume; default 100), leaf_normal_up_pct (0-100; bends leaf normals toward straight-up - higher = flatter, brighter, less noisy canopy shading; default 30), far_leaf_normal_up_pct (0-100; extra bend on the far billboard only - raise it when distant forests read dark and patchy; default 0), leaf_clump_pct (0-100; shifts that shell reference from the whole-crown center toward each level-1 branch clump's own center, so big canopies shade as separate puffy lobes instead of one ball; default 40), leaf_detail_pct (0-300; leafy normal-detail sparkle bumped from the frond texture itself; 0 = smooth shell only; default 200), leaf_ao_pct (0-200; canopy AO strength darkening cards near the trunk column and canopy bottom; 0 = off; default 40), leaf_curl_pct (0-300; how strongly leaf cards bow out of their plane for varied, non-flat silhouettes; 0 = flat cards; default 150), leaf_far_shade_pct (0-150; far-billboard leaf brightness; default 100 = matched to the near crown, <100 darkens), far_fullness_pct (0-100; fraction of leaf cards baked into the far billboard - lower = sparser far crown; default 100), far_edge_pct (0-200; far-billboard silhouette cutoff - <100 fuller/softer crown edge, >100 tighter; default 100), far_trunk_pct (0-100; trunk/branch scaffold visibility in the far billboard, 0 = foliage only; default 100; preview far vs near live with the /treelod chat command), droop_pct (tips sag), length_taper_pct (shorter branches higher up; ~70 = conifer cone), root_flare_pct (wider trunk base), wind_pct (0-300; sway response to the global wind - trunk, branches and leaf cards; 0 = rigid, default 100). Appearance keys (display-only; defaults = as authored): leaf_hue_deg / trunk_hue_deg (-180..180), leaf_sat_pct / trunk_sat_pct and leaf_val_pct / trunk_val_pct (0-200, 100 = as authored), leaf_val_var_pct / trunk_val_var_pct (0-100; deterministic per-tree brightness spread, the same tree near and far; defaults 10 / 0), leaf_tint / trunk_tint (#RRGGBB multiply - the only recolor that acts on white or gray art). The far billboard inherits them all; far_leaf_hue_deg / far_leaf_sat_pct / far_leaf_tint and far_trunk_hue_deg / far_trunk_sat_pct / far_trunk_shade_pct (0-150) / far_trunk_tint are extra billboard-only deltas (default = no change).
|
|
175
178
|
- Word keys: `mode: spiral|whorl|colonize` (whorl = rings of branches off a straight central leader - the pine/fir/spruce mode; colonize = space-colonization crown grown to fill a shape), `crown_shape: round|cone|vase` (colonize only), `leaf_mode: broadleaf|needle|weeping|mat|frond` (foliage style; weeping = hanging strand curtain, pair with high droop_pct for willows; frond = one whole-branch ribbon card per branch replacing the branch wood - THE fir/spruce mode, pair with mode: whorl and angle_deg ~95-115; mat = scattered flat shelf mats, a lighter conifer fill).
|
|
176
179
|
- Colonize-only integer keys: points (crown attraction point count; auto-scales with crown size up to 1024, override for extra fine/coarse branching), leader (0-100: how far up the crown the central trunk persists before dissolving into forks - 0 = open broadleaf habit, oaks/beeches fork early; ~50-70 = beech/maple with a trunk partway into the crown; 100 = excurrent conifer/poplar spire), crown_width (cm, 0 = auto), crown_base (crown bottom height cm, 0 = auto; whorl mode also honors it as the lowest branch ring - ground-sweeping firs author ~150), crown_follow_pct (0-100, default 75: how much the crown envelope rides a leaning/swept trunk's top - 100 = crown centered on the bole, 0 = crown stays over the root and limbs reach back, the "leaning toward a clearing" habit).
|
|
177
180
|
- Colonize authored crown shapes: `crown_sphere: x, y, z, r` / `crown_ellipsoid: x, y, z, rx, ry, rz` / `crown_dome: x, y, z_cut, rx, ry, rise` lines (cm, up to 8) grow branches to fill the union of those volumes, overriding crown_shape/crown_width/crown_base. A dome is the upper half of an ellipsoid with a flat cut at z_cut (umbrella/mushroom caps). Keep volumes near/above the trunk; disconnected lobes get bridged by a reaching branch. Colonize branches stay inside their envelope, so droop_pct barely bends them - weeping/cascading silhouettes (willows) need mode: spiral with high droop_pct instead.
|
|
178
181
|
- Authored trunk path (any mode): `trunk_point: x, y, z` lines (cm, up to 8, z strictly ascending) draw the trunk's xy course as a smooth spline through the knots, replacing trunk_lean_deg/trunk_sweep_pct (trunk_noise still layers on top). Above the top knot the offset holds, so put the top knot at trunk_height (or crown_base) for a fully drawn bole; pair with crown volumes + crown_follow_pct 100 for a hero leaning tree. Note: trees in a #forest keep a straight vertical collision capsule - keep heavy lean/sweep/trunk_point species out of forests or accept coarse trunk collision there.
|
|
179
|
-
- Leaf card: `leaf: <TextureName>` body key (or naming the texture `TreeLeaf_<Name>`) replaces the auto-generated frond card; the texture needs `mapping = uv;`, `render_mode = cutout;` + `out.alpha
|
|
182
|
+
- Leaf card: `leaf: <TextureName>` body key (or naming the texture `TreeLeaf_<Name>`) replaces the auto-generated frond card; the texture needs `mapping = uv;`, `render_mode = cutout;` + `out.alpha` (no out.alpha = every card a solid square). `mapping = uv;` is required - cards are UV quads; the triplanar default renders them invisible (unknown or non-uv `leaf:` refs = load error). Author the card as a spray of MANY leaves via `sdf.pinnate` (thin leaflets for needle/frond conifers) or `pattern.foliage`, never one big leaf, with the stem at the bottom edge (v=0) - the card's base sits on the branch. Cluster cards consume only color+alpha; authored `out.normal`/`out.orm` matter only for `leaf_mode: frond` ribbon cards.
|
|
180
183
|
- Bark: `bark: <TextureOrMaterialName>` body key per species (unknown name = load error); bare `TreeBark` (#texture or material) is the shared default for species without one (else built-in bark). Cheap per-species tint: `material PineBark { base = "TreeBark" tint = "#5a4630" }` + `bark: PineBark`.
|
|
181
184
|
- Global wind: `SetWind(DirectionDeg, Strength01, Gustiness01)`; per-species response: `wind_pct`.
|
|
182
|
-
-
|
|
185
|
+
- The editor's Tree adjuster panel lists every key with its engine default, grouped Structure / Trunk / Foliage / Far / Wind (live rebake; Save writes back only edited keys; the sim collider updates on save) - author only the look-defining ones. When the look matters, iterate with the `preview_tree` tool before submitting.
|
|
183
186
|
Species recipes: see <example_tree_species> in <world_description_examples>.
|
|
184
187
|
</tree_dsl_usage>
|
|
185
188
|
|
|
@@ -201,7 +204,8 @@ object Woods1 { model = "forest.PineWoods" position = (0, 0, 500) size = (12000,
|
|
|
201
204
|
|
|
202
205
|
<scatter_dsl_usage>
|
|
203
206
|
- `#scatter Name ... #end` (top-level): scatters ANY model over an object's box region (`model = "scatter.Name"`), exactly like `#forest` placement-wise (same region object, terrain anchoring, z-span band, filters) but display-only: NO collision, plus per-instance color variation. Use for rocks, bushes, props, debris; use `#forest` when trees should collide.
|
|
204
|
-
- Body: `model: <url>` (required; `mesh.<Name>`, `Ori.model.*`, or a market model url) + the `#forest` keys minus `species`; optional integers hue_jitter_deg (0-180), sat_jitter_pct / val_jitter_pct (0-100) tint each instance (multiplies the region object's color; a tint on textured models, not true hue rotation); splat_mask_min_pct / splat_mask_max_pct keep instances only where the `user` mask (SetTerrainSplatMask) under them is inside that percent band (max 30 = off painted roads; min 60 = only on painted ground).
|
|
207
|
+
- Body: `model: <url>` (required; `mesh.<Name>`, `Ori.model.*`, or a market model url) + the `#forest` keys minus `species`; optional integers hue_jitter_deg (0-180), sat_jitter_pct / val_jitter_pct (0-100) tint each instance (multiplies the region object's color; a tint on textured models, not true hue rotation); splat_mask_min_pct / splat_mask_max_pct keep instances only where the `user` mask (SetTerrainSplatMask) under them is inside that percent band (max 30 = off painted roads; min 60 = only on painted ground); z_offset_cm (signed cm added after terrain anchoring; negative sinks props into the ground, e.g. -20 hides a rock's flat base); terrain_normal_align_pct (0-100, default 100) tilts each instance onto the slope under it (100 = local up follows the terrain normal, 0 = always world-up): rocks, debris, roots want 100; anything that must stand upright (posts, signs, bushes) wants 0-30; rotation_min_deg / rotation_max_deg (-360..360, min <= max, default -180/180) bound the per-instance random yaw about that up axis: -20/20 = nearly aligned, 0/0 = no random yaw (all face the region object's forward); `shape: "<svg path data>"` draws the region outline instead of filling the whole box: path data in a 0..100 x 0..100 frame that IS the box (page-up = +Y, (0,0) = the box's -x/+y corner), nested subpaths = holes and islands, instances outside the outline are skipped (display-only; `#forest` stays box-shaped because trunks collide) - a lake shore, a park, a roadside strip as one drawing over one region object.
|
|
208
|
+
- The editor's Scatter adjuster panel (select the region object) lists every key with its default, filter keys as on/off switches (live re-scatter; Save writes back only edited keys) - author only the look-defining ones.
|
|
205
209
|
Example:
|
|
206
210
|
#scatter Boulders
|
|
207
211
|
model: "mesh.Rock"
|
|
@@ -344,7 +348,7 @@ event OnTuneChanged {
|
|
|
344
348
|
- A shared canvas still routes clicks per-player: ClickButton handlers that mutate per-player state must branch on Event.ButtonClicker.
|
|
345
349
|
- Per-player world objects: keep one shared map/board, then use obj.SetRenderVisibleOnlyToPlayerIndex(GetPlayerIndex()) for private meshes/cards/markers. Use obj.SetRenderVisibleToAllPlayers() to make the world object public again (clears only-to AND hidden-for); ownership metadata is not cleared.
|
|
346
350
|
- Inverse: obj.SetRenderHiddenForPlayerIndex(i) hides a shared object from exactly that player, visible to everyone else (e.g. hide the original wall from the player previewing its replacement).
|
|
347
|
-
- Per-player build ghosts: DrawPreviewForPlayer(GetPlayerIndex(), SavedObject.X, pos, rot) each frame — only that player's client renders it (DrawPreview draws on every client).
|
|
351
|
+
- Per-player build ghosts: DrawPreviewForPlayer(GetPlayerIndex(), SavedObject.X, pos, rot) each frame — only that player's client renders it (DrawPreview draws on every client). A see-through cell ghost = a saved display with `opacity = 0.35`, or a wireframe #mesh for a pure outline.
|
|
348
352
|
- This is render/pick/mouse-target privacy, not secret sim state or per-player physics/audio. For private cards/markers, usually also call card.SetCanCollide(false).
|
|
349
353
|
- SetRenderVisibleOnlyToPlayerIndex(i)/SetRenderHiddenForPlayerIndex(i) are a RUNTIME ERROR if no live player has index i — call them from that player's own OnSpawned, never on a hardcoded index from world setup or forever loops.
|
|
350
354
|
- There is NO per-player collision filter: two players' "private" objects at the same XYZ still collide physically. Separate per-player arenas/boards at different world coordinates; render privacy is cosmetic, not the separation mechanism.
|
|
@@ -361,7 +365,7 @@ event OnTuneChanged {
|
|
|
361
365
|
- Never assume a fixed player count or index order (players join/leave).
|
|
362
366
|
- Determinism caveats:
|
|
363
367
|
- Time is sim-time and pause-aware: TimeSecs/TimeTicks freeze on pause and may reset on world reset, so capture your own baseline (StartTime=TimeSecs()); RawTimeSecs/RawTimeTicks is unfrozen raw time.
|
|
364
|
-
- RandomNumber/RandomPosition* are deterministic (seeded per tick + calling object + call index, so repeated or cross-object same-tick calls draw fresh values); inside player input events (key/mouse/action) all Random* calls are seeded by that input edge instead, so the predicted result matches the final one. RandomChancePercent outside input events returns false during client prediction, so there use it only for delay-tolerant side effects (e.g. drops), not moment-to-moment combat. A fresh load always starts at the same tick, so the FIRST draws repeat across sessions (identical opening deck/magazine every load) — mix a per-session value (e.g. TimeTicks() at game start) into anything that must differ between sessions.
|
|
368
|
+
- RandomNumber/RandomPosition* are deterministic (seeded per tick + calling object + call index, so repeated or cross-object same-tick calls draw fresh values); inside player input events (key/mouse/action) all Random* calls are seeded by that input edge instead, so the predicted result matches the final one. RandomChancePercent outside input events returns false during client prediction, so there use it only for delay-tolerant side effects (e.g. drops), not moment-to-moment combat. A fresh load always starts at the same tick, so the FIRST draws repeat across sessions (identical opening deck/magazine every load) — mix a per-session value (e.g. TimeTicks() at game start) into anything that must differ between sessions. List.Shuffle/GetRandomElement(s) and RandomChancePercent (outside input events) draw from ONE persistent stream, separate from RandomNumber's per-call derivation, so that stream repeats its sequence on every fresh load too.
|
|
365
369
|
- Don't rely on cross-object event ordering (OnSpawned order across objects is unspecified).
|
|
366
370
|
- Session APIs (for CUSTOM in-game browsers only - the engine ships a built-in session browser + share/visibility panel for every project; most games need no session code):
|
|
367
371
|
- AdvertiseSession()/StopAdvertisingSession() toggle whether this session is listed in the project's public session list (same switch the host's engine panel sets; last write wins; play-mode entries auto-list - a game that wants private sessions calls StopAdvertisingSession()). Unlisted sessions stay joinable via share link.
|
|
@@ -385,6 +389,7 @@ event OnSpawned {
|
|
|
385
389
|
buddy.SetRenderVisibleOnlyToPlayerIndex(me) // private world mesh/object for this player
|
|
386
390
|
}
|
|
387
391
|
#end
|
|
392
|
+
- A shared button meant to serve the party once has ONE click state: hiding or destroying it in the handler ends it for everyone - track per-player claimed status instead.
|
|
388
393
|
</multiplayer_guidance>
|
|
389
394
|
|
|
390
395
|
<multi_stage_projects>
|
|
@@ -524,6 +529,7 @@ event OnSpawned {
|
|
|
524
529
|
- Bone/pose simcalls (SetBoneRotation family, SetUpperBodyAnimationWeight, SetRenderOffset) reject crowd instances - use a regular object for featured NPCs needing bone-level control.
|
|
525
530
|
- ClimbingCrowdObject: like CrowdObject, but simulated by the deterministic "climbing crowd" step (lean crowd bodies)
|
|
526
531
|
- Prefer it over plain WorldObject for player-chasing enemies in flat first-/third-person worlds.
|
|
532
|
+
- Declare with `climbingCrowd Name : Class { ... }` (scene or `saved` scope); plain `crowd` is the avoidance CrowdObject.
|
|
527
533
|
- Always seeks the nearest player in XY each tick; players are never pushed (climbers always yield)
|
|
528
534
|
- Default speed: 150 cm/s. Use SetDefaultClimbingCrowdSpeed(Speed) to change the default for newly spawned climbers; use Object.SetClimbingCrowdSpeed(Speed) to override an individual climber. Do not use SetPhysicsSpeed.
|
|
529
535
|
- Terrain + static primitive obstacles; supports elevator-like climbing
|
|
@@ -531,7 +537,7 @@ event OnSpawned {
|
|
|
531
537
|
- DisplayObject: like WorldObject but visual-only — no collision, no interaction events (Touched, ClickThisObject, etc. will never fire), doesn’t respond to forces
|
|
532
538
|
- 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.
|
|
533
539
|
- EffectObject: visual effects
|
|
534
|
-
- 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>)
|
|
540
|
+
- 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); falloff is intensity * (1 - d/radius)^2 / (d^2 + 1) with d in metres, against a default sun of 4: intensity 5 lights a surface at 1 m to ~40% of sunlit white, at 2 m ~10%, at 4 m ~1% - a lamp that must read lit at 2 m wants ~40-50, a room-filling wash at 5 m ~300+ with a matching radius; a flat white blob means intensity, not radius, is too high; 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>)
|
|
535
541
|
- 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)
|
|
536
542
|
- diffuseOnlyLight: diffuse-only, flat core with fade_width (cm) fade shell; pointLight keys minus cast_shadow/light_specular_scale
|
|
537
543
|
- areaLight: area light; pointLight keys minus cast_shadow
|
|
@@ -543,7 +549,7 @@ event OnSpawned {
|
|
|
543
549
|
<variable_types>
|
|
544
550
|
- Number — real (integers/decimals/scientific); arithmetic includes % and %= (modulus).
|
|
545
551
|
- Bool — true/false.
|
|
546
|
-
- Text — string; + concatenates and auto-converts Number/Position/Object operands (no .ToText() needed in concat; use it only for a standalone value, e.g. SetText(N.ToText())). Parsing: Text.Word(Index) (0-based whitespace-split word, "" past end), Text.WordCount(), Text.ToNumber() (0 if not numeric). .ToText() renders minimal form ("1", not "1.000").
|
|
552
|
+
- Text — string; + concatenates and auto-converts Number/Position/Object operands (no .ToText() needed in concat; use it only for a standalone value, e.g. SetText(N.ToText())). Parsing: Text.Word(Index) (0-based whitespace-split word, "" past end), Text.WordCount(), Text.Substring(Start, Count), Text.Length(), Text.ToNumber() (0 if not numeric). .ToText() renders minimal form ("1", not "1.000").
|
|
547
553
|
- Object — handle to a world/UI object; may be None
|
|
548
554
|
- Timer — countdown handle; new timers start in Done state.
|
|
549
555
|
- Vector — (X,Y,Z) direction/offset; also used for RGB triples.
|
|
@@ -552,7 +558,7 @@ event OnSpawned {
|
|
|
552
558
|
- 'var X: List<T>' needs no initializer (class scope or local); lists start empty.
|
|
553
559
|
- Bare 'var X: List' infers T from usage; annotate List<T> explicitly when inference reports conflicting evidence.
|
|
554
560
|
- No List<List<T>>. Non-empty literals ([1,2,3]) are const-only: runtime lists start empty then Add, or Resize(n, default).
|
|
555
|
-
- 'const Ids = [10, 20, 30]' (class scope or inside a func; Number/Bool/Text/Vector elements, type inferred) bakes a read-only table into the program: Get/Count/Contains/for-each work, writes are runtime errors. Const tables have zero per-frame snapshot/hash cost — item/monster/config databases belong here, not in runtime lists filled row-by-row at startup.
|
|
561
|
+
- 'const Ids = [10, 20, 30]' (class scope or inside a func; Number/Bool/Text/Vector elements, type inferred) bakes a read-only table into the program: Get/Count/Contains/for-each work, writes are runtime errors. Const tables have zero per-frame snapshot/hash cost — item/monster/config databases belong here, not in runtime lists filled row-by-row at startup. Other classes read a const through a typed cast, (Scene.DbObj as Db).Names.Get(i); the value is inlined, so the receiver must be a plain handle (Scene.X, a param, a local), not a call.
|
|
556
562
|
- Map<Number, T> — keyed store (T: Number | Bool | Text | Object | Func): Set(K, V), Get(K) (missing key is a runtime error), GetOr(K, Default), Has(K), Remove(K)->Bool, Count(), IsEmpty(), Clear(). Keys compare exactly (no fractional truncation) — use integer keys. Replaces hand-rolled bucket/chain index lists for id -> row lookups (entity id -> row, structure id -> data).
|
|
557
563
|
- Func — reference to one of this class's own funcs: 'var F: Func = Func(OnBuy)' (target must return nothing). F.Invoke(Receiver, args...) runs it — Receiver's class must own the func and args must match its params (runtime errors otherwise); Self is the usual receiver. Defaults to None; not usable in List<T> or @persist, and refs reset to None across save/load — re-seed in OnSpawned. Map<Number, Func> is the dispatch table (kind -> behavior func on one manager class) — replaces one-class-per-behavior. A func that itself Invokes refs cannot be referenced with Func(...) (recursion is a compile error).
|
|
558
564
|
- Contains/IndexOf: List<Number|Bool|Vector|Position> and object lists only (not List<Text>/List<Timer>).
|
|
@@ -569,7 +575,7 @@ event OnSpawned {
|
|
|
569
575
|
- Fields: Number | Bool | Vector | Position | Object (plain or class-typed, e.g. 'var M: Monster' — member calls through class-typed fields are validated statically). Max 16 slots; Vector/Position count as 3, Object counts as 1. No Text/Timer/nested-struct fields yet. Object fields default to None (zeroed class-scope structs and Resize-grown list elements included).
|
|
570
576
|
- Construct positionally with one arg per field: 'var S = Stat(100, Vector(1,0,0))'. Read/write fields ('S.Health += 1', 'S.Speed.X = 2') on locals, Self vars, and list elements ('Table.Get(i).Health = 5' writes back); copies are by value ('var C = S' snapshots), so fields on a function's returned struct need a var first.
|
|
571
577
|
- 'var Stats: Stat' without an initializer starts zeroed in any scope, Object fields None (no struct literals at class scope; fill in OnSpawned). Structs work as function params/returns.
|
|
572
|
-
- List<struct> is supported ('var Table: List<Stat>') with Add/Get/Set/RemoveAt/Swap/Shuffle/Resize(count)/Count/IsEmpty/Clear + for-each; not Contains/IndexOf/Pop/Last/GetRandomElement or Resize with fill.
|
|
578
|
+
- List<struct> is supported ('var Table: List<Stat>') with Add/Get/Set/RemoveAt/Swap/Shuffle/Resize(count)/Count/IsEmpty/Clear + for-each; IndexOfField("Field", V)/ContainsField (Number/Bool/Object fields); not Contains/IndexOf/Pop/Last/GetRandomElement or Resize with fill.
|
|
573
579
|
- Lists cap at ~1M elements: an every-frame Add with no Clear/dedupe (e.g. selections, hit logs) reaches the cap in minutes of play and stops the world with CapacityExceeded - clear or bound accumulating lists.
|
|
574
580
|
- No struct operators ('==' included) — compare fields; no scene-clause overrides.
|
|
575
581
|
|
|
@@ -611,6 +617,7 @@ object test : MeleeEnemy { size = (70,70,100), override MaxHP = 100 }
|
|
|
611
617
|
- Basic cube is 100x100x100 cm, sphere 100 cm diameter
|
|
612
618
|
- Basic models: cube, sphere, cylinder, capsule (long axis +Z), cone (apex +Z), wedge (slope rises toward +X)
|
|
613
619
|
- Object position is the BOTTOM center: the object rests its base at position.z (top = position.z + size.z). A ground slab with its top at z=0 is position = (0, 0, -H) size = (X, Y, H).
|
|
620
|
+
- Two same-facing faces on one plane shimmer (z-fight): stacked slabs sharing a top, a plane at floor height, a sign flush in a wall, a prop placed twice. Keep >=1cm between them or give the overlay's material render_mode = decal; validation lists such pairs.
|
|
614
621
|
- Object size is clamped per axis: 50,000 cm for solid objects, 100,000 cm display-only (10,000 cm dynamic). Meshes scale to object size, so oversized objects render SQUASHED — tile large ground/water/road geometry into pieces under the cap.
|
|
615
622
|
- cone/wedge collide as boxes. Walkable ramp = rotated thin cube, e.g. size = (630, 300, 20) rotation = (0, -18, 0) rises toward +X
|
|
616
623
|
- Marketplace/#mesh models also collide as their AABB box: a boat deck, bridge, or house interior is NOT walkable/enterable by default, and interior furniture's box juts far past its real shape, blocking walkways. Declare `collision = mesh` on the object clause (object Boat { model = "..." collision = mesh }) to collide against the model's actual geometry — the right choice for enterable structures AND for furniture players move around. Skinned/animated models keep the box.
|
|
@@ -747,7 +754,7 @@ Applies to all physics types: Dynamic, Static, and Kinematic.
|
|
|
747
754
|
- Use attachments for multi-part assemblies (turret on tank, gun in hand, lamp on wall, effect following a part) instead of per-frame SetPosition/LookAt follow loops in forever.
|
|
748
755
|
- Vehicle/cockpit rigs: ONE mover object drives the assembly and every rigid part (cockpit shell, stick, dash, held prop) attaches to it — hand-computing part positions per frame duplicates the seat math across writers and the parts drift apart. The camera is NOT an object and cannot attach: compute eye/look from the mover's own state variables in the same update that moves it (reading the mover's GetPosition() back returns the pre-physics value, so a camera fed from read-back trails one tick).
|
|
749
756
|
- Children must be collision-free: display/effect/light/marker objects, or call SetCanCollide(false) first. Enforced both ways: AttachTo errors on a collidable child, and SetCanCollide(true) errors while attached (Detach() first). Chains are fine (torso -> arm -> gun); cycles and depth > 16 error.
|
|
750
|
-
- Seats (players riding vehicles/mounts): Car.SeatPlayer(p, "driver") parks a player (user or bot) on that model anchor; Car.SeatPlayerAt(p, "driver", Vector(0,0,60)) is
|
|
757
|
+
- Seats (players riding vehicles/mounts): Car.SeatPlayer(p, "driver") parks a player (user or bot) on that model anchor - a model car without one mints it in its own class: SetModelAnchor(GetModel(), "driver", <seat point = the pan surface the rider sits on, model-local cm: cabin center, driver side, ~50cm above the underbody>, Vector(0,0,0)), once per model; an optional "wheel" anchor at the rim center puts the driver's hands on it; Car.SeatPlayerAt(p, "driver", Vector(0,0,60)) is for primitive-built seats only. The engine suspends the capsule and native controls, the avatar rides the seat, and the default chase camera follows - no per-frame camera or position writes. Drive per frame from Car.SeatOccupant("driver").GetMoveVectorCamera() (bots: SetAIMoveVector); the car's motion stays your kinematic velocity integration. Exit: Car.UnseatPlayer(p) restores physics in place - TeleportTo an exit spot right after for enclosed cabins. Carjacking = UnseatPlayer(victim) then SeatPlayer(thief); locks, seat roles, and reactions are your script vars. Never fake sitting by hiding+teleporting the player; p.SeatedIn() -> Object tells whether p is seated.
|
|
751
758
|
- In OnSpawned prefer the explicit overload or AttachToAnchor: cross-object OnSpawned order is unspecified, so 1-arg AttachTo may capture the parent's pre-placement pose. Use 1-arg AttachTo for runtime pickup of already-placed objects.
|
|
752
759
|
- Local offsets are absolute cm in the parent's local frame, CENTER-to-CENTER: the origin is the parent's center and the offset lands the CHILD's center (NOT the bottom-center pivot GetPosition/#mesh use) - seat a hat by adding half the child's height. Resizing the parent neither rescales nor re-seats mounted children (SetSize also moves the parent's center): re-attach after growth, and prefer ScaleToHeight so the base stays planted.
|
|
753
760
|
- While attached, the child's own move/teleport calls are overridden each tick by the attachment. Attachment state is deterministic sim state (rollback/late-join safe). Destroying the parent detaches children in place (frozen at their last transform, silently): after respawning a parent, re-attach its children.
|
|
@@ -761,7 +768,7 @@ Applies to all physics types: Dynamic, Static, and Kinematic.
|
|
|
761
768
|
</attachments>
|
|
762
769
|
|
|
763
770
|
<easing>
|
|
764
|
-
- EaseIn/EaseOut/EaseInOut/EaseOutBack/EaseOutBounce(T) map linear progress T (0..1, clamped) to eased progress. Pair with Lerp/LerpVector to tween positions, rotations, numbers. UI element offset/size/opacity/color: use the built-in glide overloads (SetUiOffset(X, Y, Secs[, Ease]) etc., see <ui>) instead of a loop.
|
|
771
|
+
- EaseIn/EaseOut/EaseInOut/EaseOutBack/EaseOutBounce(T) map linear progress T (0..1, clamped) to eased progress. Pair with Lerp/LerpVector to tween positions, rotations, numbers. UI element offset/size/opacity/color: use the built-in glide overloads (SetUiOffset(X, Y, Secs[, Ease[, Delay]]) etc., see <ui>) instead of a loop.
|
|
765
772
|
- The tween loop (works for any value; write the exact target at the end):
|
|
766
773
|
var T = 0
|
|
767
774
|
var Start = O.GetPosition()
|
|
@@ -795,7 +802,7 @@ Movement Laws (single-frame vs over-time)
|
|
|
795
802
|
- Arrival at an OBJECT: colliders stop the mover before centers meet, so DistanceTo(target) may never drop below both half-extents (reads as a freeze while Move* keeps firing). Gate on SurfaceGapTo(Target) <= margin instead.
|
|
796
803
|
- Timing & readback: see <frame_and_scheduling_model> for tick order and GetPosition/GetRotation semantics.
|
|
797
804
|
|
|
798
|
-
- Clarification: SnapToGround raycasts downward (-Z) from the object's bottom-center and snaps to the first WorldObject hit (ignores PhysicsObject/PlayerObject/CrowdObject etc.). It overrides any Z offset you set earlier in the same frame. For stacking on tiles/objects, compute Z = baseZ + baseSizeZ/2 + itemSizeZ/2 instead of using SnapToGround. Flat/plane items (rugs, road markings, decals): add ~1cm more — face-on-face at the same height shimmers (z-fights)
|
|
805
|
+
- Clarification: SnapToGround raycasts downward (-Z) from the object's bottom-center and snaps to the first WorldObject hit (ignores PhysicsObject/PlayerObject/CrowdObject etc.). It overrides any Z offset you set earlier in the same frame. For stacking on tiles/objects, compute Z = baseZ + baseSizeZ/2 + itemSizeZ/2 instead of using SnapToGround. Flat/plane items (rugs, road markings, decals): add ~1cm more — face-on-face at the same height shimmers (z-fights).
|
|
799
806
|
</movement_laws>
|
|
800
807
|
|
|
801
808
|
<inputs>
|
|
@@ -843,7 +850,8 @@ Movement Laws (single-frame vs over-time)
|
|
|
843
850
|
- Digits: Key.Num0 .. Key.Num9
|
|
844
851
|
- Mouse: Key.LeftMouseButton, Key.RightMouseButton, Key.MiddleMouseButton
|
|
845
852
|
- Navigation Keys: Key.UpArrow, Key.DownArrow, Key.LeftArrow, Key.RightArrow
|
|
846
|
-
- Control Keys: Key.Tab, Key.Space, Key.Enter, Key.Backspace, Key.LeftShift, Key.RightShift, Key.LeftControl, Key.RightControl, Key.LeftAlt, Key.RightAlt
|
|
853
|
+
- Control Keys: Key.Tab, Key.Space, Key.Enter, Key.Backspace, Key.Escape, Key.LeftShift, Key.RightShift, Key.LeftControl, Key.RightControl, Key.LeftAlt, Key.RightAlt
|
|
854
|
+
- Function Keys: Key.F1 .. Key.F12
|
|
847
855
|
- Symbol Keys: Key.Tilde, Key.Minus, Key.Equals, Key.LeftBracket, Key.RightBracket, Key.Backslash, Key.Semicolon, Key.Quote, Key.Comma, Key.Period, Key.Slash
|
|
848
856
|
</key_codes>
|
|
849
857
|
|
|
@@ -930,15 +938,16 @@ PrintTag(Tag: Number)
|
|
|
930
938
|
PrintDivider()
|
|
931
939
|
SetAutoGameLogOn()
|
|
932
940
|
PlayerPrint(PlayerIndex: Number, Text: Text)
|
|
933
|
-
SetSunIntensity(Intensity: Number) // Default: 4 [global: all clients]
|
|
934
|
-
SetSunSpecularScale(Scale: Number) // Default: 1
|
|
941
|
+
SetSunIntensity(Intensity: Number) // Default: 4. Sunlit white ~ Intensity/pi pre-tonemap; above ~8 the tonemap shoulder flattens gains (12 and 18 look alike) - lift a dark scene with SetExposure, fill shadows with SetSkyLightIntensity [global: all clients]
|
|
942
|
+
SetSunSpecularScale(Scale: Number) // Default: 1 [global: all clients]
|
|
935
943
|
SetSunRotation(Rotation: Number) // Default: 10. Azimuth, degrees from +X toward +Y; shadows fall toward Rotation+180 [global: all clients]
|
|
936
944
|
SetSunTilt(Tilt: Number) // Default: 46. Elevation above the horizon, degrees (90 = overhead) [global: all clients]
|
|
945
|
+
SetSnowCover(Amount: Number) // Default: 0. Snow cover 0..1 on props and characters: sky-exposed upward faces blend to snow and take snow lighting; terrain keeps its own layers; emissive, glass and snow_cover = "off" materials stay bare [global: all clients]
|
|
937
946
|
SetSkybox(Skybox: Object)
|
|
938
|
-
SetSkyboxHorizonTilt(AngleDegrees: Number) // Default: 0
|
|
939
|
-
SetSkyboxRotation(RotationDegrees: Number) // Default: 0
|
|
947
|
+
SetSkyboxHorizonTilt(AngleDegrees: Number) // Default: 0 [global: all clients]
|
|
948
|
+
SetSkyboxRotation(RotationDegrees: Number) // Default: 0 [global: all clients]
|
|
940
949
|
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
|
|
941
|
-
SetSkyboxSunVisible(Visible: Bool)
|
|
950
|
+
SetSkyboxSunVisible(Visible: Bool) [global: all clients]
|
|
942
951
|
SetSkyboxTint(Color: Vector) [global: all clients]
|
|
943
952
|
SetSkyboxSaturation(Saturation: Number) // Default: 1. With procedural sky, sky grade calls also re-tint the ambient lighting (IBL) [global: all clients]
|
|
944
953
|
SetSkyboxExposure(ExposureStops: Number) // Default: 0 [global: all clients]
|
|
@@ -946,32 +955,32 @@ SetSkyLightIntensity(Intensity: Number) // Default: 2 [global: all clients]
|
|
|
946
955
|
SetSkyLightColor(Color: Vector) [global: all clients]
|
|
947
956
|
SetSkyLightSaturation(Saturation: Number) // Default: 1 [global: all clients]
|
|
948
957
|
SetBloomThreshold(Threshold: Number) // Default: 2 [global: all clients]
|
|
949
|
-
SetBloomSoftKnee(SoftKnee: Number) // Default: 0.5
|
|
958
|
+
SetBloomSoftKnee(SoftKnee: Number) // Default: 0.5 [global: all clients]
|
|
950
959
|
SetBloomIntensity(Intensity: Number) // Default: 0.15 [global: all clients]
|
|
951
|
-
SetBloomClampValue(Clamp: Number) // Default: 1
|
|
960
|
+
SetBloomClampValue(Clamp: Number) // Default: 1 [global: all clients]
|
|
952
961
|
SetSsaoIntensity(Intensity01: Number) // Default: 1 [global: all clients]
|
|
953
962
|
SetSsaoDistance(DistanceMeters: Number) // Default: 0.5 [global: all clients]
|
|
954
963
|
SetSsrLow()
|
|
955
964
|
SetSsrHigh()
|
|
956
|
-
SetSsrOff()
|
|
957
|
-
SetSsrRoughnessBlurMultiplier(Multiplier: Number) // Default: 2
|
|
958
|
-
SetSsrRoughnessMipClamp(LowerMip: Number, UpperMip: Number) // Default: 0, 0
|
|
959
|
-
SetSsrIntensity(Intensity0To10: Number) // Default: 1
|
|
965
|
+
SetSsrOff() [global: all clients]
|
|
966
|
+
SetSsrRoughnessBlurMultiplier(Multiplier: Number) // Default: 2 [global: all clients]
|
|
967
|
+
SetSsrRoughnessMipClamp(LowerMip: Number, UpperMip: Number) // Default: 0, 0 [global: all clients]
|
|
968
|
+
SetSsrIntensity(Intensity0To10: Number) // Default: 1 [global: all clients]
|
|
960
969
|
SetShadowBlurRadius(Radius: Number) // Default: 2.8 [global: all clients]
|
|
961
|
-
SetLocalShadowBlurRadius(Radius: Number) // Default: 12
|
|
962
|
-
SetShadowDepthBiasConstant(Units: Number) // Default: 1
|
|
963
|
-
SetShadowDepthBiasSlopeScale(Scale: Number) // Default: 2.5
|
|
970
|
+
SetLocalShadowBlurRadius(Radius: Number) // Default: 12 [global: all clients]
|
|
971
|
+
SetShadowDepthBiasConstant(Units: Number) // Default: 1 [global: all clients]
|
|
972
|
+
SetShadowDepthBiasSlopeScale(Scale: Number) // Default: 2.5 [global: all clients]
|
|
964
973
|
SetShadowOpacity(Opacity01: Number) // Default: 1 [global: all clients]
|
|
965
|
-
SetStaticLodTransitions(Lod1Size: Number, Lod2Size: Number, Lod3Size: Number) // Default: 0.18, 0.07, 0.025
|
|
966
|
-
SetStaticLodShadowTransitions(Lod1Size: Number, Lod2Size: Number, Lod3Size: Number) // LOD thresholds for meshes drawn into sun-shadow maps, as the caster's fraction of the active cascade's coverage box (NOT camera screen units - far cascades cover more ground, so casters coarsen there naturally). Lower if a shadow silhouette looks low-poly or pops; raise to cheapen shadows. Default: 0.35, 0.18, 0.08
|
|
974
|
+
SetStaticLodTransitions(Lod1Size: Number, Lod2Size: Number, Lod3Size: Number) // Default: 0.18, 0.07, 0.025 [global: all clients]
|
|
975
|
+
SetStaticLodShadowTransitions(Lod1Size: Number, Lod2Size: Number, Lod3Size: Number) // LOD thresholds for meshes drawn into sun-shadow maps, as the caster's fraction of the active cascade's coverage box (NOT camera screen units - far cascades cover more ground, so casters coarsen there naturally). Lower if a shadow silhouette looks low-poly or pops; raise to cheapen shadows. Default: 0.35, 0.18, 0.08 [global: all clients]
|
|
967
976
|
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]
|
|
968
977
|
SetSaturation(Saturation: Number) // Saturation multiplier. Default: 1 = neutral; 0 = grayscale, 2 = vivid [global: all clients]
|
|
969
978
|
SetExposure(Exposure: Number) // EV stops, pre-tonemap: +1 = twice as bright, -1 = half. Default: 0 [global: all clients]
|
|
970
979
|
SetShadowLift(Amount: Number) // Default: 2; 0 = off [global: all clients]
|
|
971
980
|
SetShadowLiftThreshold(Threshold: Number) // Default: 0.06 [global: all clients]
|
|
972
|
-
SetSmaaEdgesThreshold(Threshold01: Number) // Default: 0.01
|
|
973
|
-
SetAdaptiveRenderQualityEnabled(Enabled: Bool) // Default: true. Renderer may temporarily drop SSR/SSAO/bloom on slow frames; false pins full quality
|
|
974
|
-
SetGlobalMipBias(Bias: Number) // Default: 0. Mobile wasm applies its startup bias only; changing this later may not rebuild already-uploaded textures.
|
|
981
|
+
SetSmaaEdgesThreshold(Threshold01: Number) // Default: 0.01 [global: all clients]
|
|
982
|
+
SetAdaptiveRenderQualityEnabled(Enabled: Bool) // Default: true. Renderer may temporarily drop SSR/SSAO/bloom on slow frames; false pins full quality [global: all clients]
|
|
983
|
+
SetGlobalMipBias(Bias: Number) // Default: 0. Mobile wasm applies its startup bias only; changing this later may not rebuild already-uploaded textures. [global: all clients]
|
|
975
984
|
SetVignetteStrength(Strength: Number) // Default: 0 [global: all clients]
|
|
976
985
|
SetVignetteRadius(Radius: Number) // Default: 0.75 [global: all clients]
|
|
977
986
|
SetVignetteSoftness(Softness: Number) // Default: 0.25 [global: all clients]
|
|
@@ -979,8 +988,8 @@ SetVignetteColor(Color: Vector) [global: all clients]
|
|
|
979
988
|
SetDefaultClimbingCrowdSpeed(Speed: Number)
|
|
980
989
|
SetClimbingCrowdPaused(IsPaused: Bool) // Freeze climbingCrowd step (movement + depenetration/climb).
|
|
981
990
|
SetClimbingCrowdSolveSteps(Steps: Number)
|
|
982
|
-
SetAllLocalShadowsEnabled(Enabled: Bool)
|
|
983
|
-
SetAllDecalsEnabled(Enabled: Bool)
|
|
991
|
+
SetAllLocalShadowsEnabled(Enabled: Bool) [global: all clients]
|
|
992
|
+
SetAllDecalsEnabled(Enabled: Bool) [global: all clients]
|
|
984
993
|
SetGravity(Gravity: Number)
|
|
985
994
|
SetTerminalVelocityZ(MaxFallSpeed: Number)
|
|
986
995
|
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]
|
|
@@ -989,10 +998,10 @@ SetHeightFogEnabled(Enabled: Bool) [global: all clients]
|
|
|
989
998
|
SetHeightFogTop(Top: Number) // Default: 50. Meters [global: all clients]
|
|
990
999
|
SetHeightFogBottom(Bottom: Number) // Default: 0. Meters [global: all clients]
|
|
991
1000
|
SetHeightFogSoftness(Softness: Number) // Default: 1 [global: all clients]
|
|
992
|
-
SetGpuCullingDistance(DistanceMeters: Number) // Default: 0 (distance culling off)
|
|
993
|
-
SetFrustumCulling(Enabled: Bool)
|
|
994
|
-
SetFrustumCullingMargin(MarginMeters: Number) // Default: 0
|
|
995
|
-
SetDecalCullingDistanceM(DistanceMeters: Number) // Default: 0
|
|
1001
|
+
SetGpuCullingDistance(DistanceMeters: Number) // Default: 0 (distance culling off) [global: all clients]
|
|
1002
|
+
SetFrustumCulling(Enabled: Bool) [global: all clients]
|
|
1003
|
+
SetFrustumCullingMargin(MarginMeters: Number) // Default: 0 [global: all clients]
|
|
1004
|
+
SetDecalCullingDistanceM(DistanceMeters: Number) // Default: 0 [global: all clients]
|
|
996
1005
|
SetGrassSpacingCm(SpacingCm: Number) // Default: 0 (auto) [global: all clients]
|
|
997
1006
|
SetGrassTerrainActiveDistanceM(DistanceMeters: Number) // Default: 140 [global: all clients]
|
|
998
1007
|
SetGrassCullDistanceM(DistanceMeters: Number) // Default: 140 [global: all clients]
|
|
@@ -1008,7 +1017,7 @@ SetAssetSubmeshSaturation(ModelAsset: Object, SubmeshIndex: Number, Saturation:
|
|
|
1008
1017
|
SetAssetSubmeshBrightness(ModelAsset: Object, SubmeshIndex: Number, Brightness: Number) // Gain: 1 = neutral
|
|
1009
1018
|
SetAssetSubmeshContrast(ModelAsset: Object, SubmeshIndex: Number, Contrast: Number) // Multiplier around mid-gray: 1 = neutral, 0 = flat gray. Use only when the user asks for it specifically; Tint/Brightness/Saturation cover normal fitting
|
|
1010
1019
|
SetAssetSubmeshTint(ModelAsset: Object, SubmeshIndex: Number, TintRGB: Vector)
|
|
1011
|
-
SetAssetSubmeshEmissionIntensity(ModelAsset: Object, SubmeshIndex: Number, Intensity: Number) // Linear glow
|
|
1020
|
+
SetAssetSubmeshEmissionIntensity(ModelAsset: Object, SubmeshIndex: Number, Intensity: Number) // Linear glow for this submesh, same ladder as SetEmissionIntensity; composes with object emission
|
|
1012
1021
|
SetAssetSubmeshMinRoughness(ModelAsset: Object, SubmeshIndex: Number, MinRoughness: Number)
|
|
1013
1022
|
SetAssetSubmeshRoughnessSmoothStepRemap(ModelAsset: Object, SubmeshIndex: Number, Enabled: Bool)
|
|
1014
1023
|
SetAssetSubmeshNormalStrength(ModelAsset: Object, SubmeshIndex: Number, Strength: Number)
|
|
@@ -1023,7 +1032,7 @@ ClearAssetSubmeshMaterial(ModelAsset: Object, SubmeshIndex: Number) // Clears ex
|
|
|
1023
1032
|
SetAssetSubmeshFur(ModelAsset: Object, SubmeshIndex: Number, LengthCm: Number, Density: Number) // Soft shell fur on a rigged model's submesh, keeping its textures: LengthCm 0..20 cm (0 = off), Density = relative strand fineness 0.1..8 (0 = default 1). Asset-scoped (all instances share it); skinned models only; real overdraw cost - hero creatures
|
|
1024
1033
|
SetAssetSubmeshFurMask(ModelAsset: Object, SubmeshIndex: Number, Mask: Object) // Per-texel fur length over a SetAssetSubmeshFur submesh: Mask = Image.X in the model's UV space (fur_mask_gen bakes one as Ori.projimg.<handle>; or any Ori.image.<user>.<name>), R x LengthCm: 0 = bare, 1 = full; None clears
|
|
1025
1034
|
SetMaterialParameterNumber(MaterialAsset: Object, Slot: Number, Value: Number)
|
|
1026
|
-
SetMaterialParameterTexture(MaterialAsset: Object, Slot: Number, ImageAsset: Object)
|
|
1035
|
+
SetMaterialParameterTexture(MaterialAsset: Object, Slot: Number, ImageAsset: Object) // Bind an Image asset into the material's texN WGSL slot (Slot 0..16; None clears). A model's own imported maps bind via Ori.modeltex.<creator>.<name>.<color|normal|orm> imports
|
|
1027
1036
|
GetMaterialParameterNumber(MaterialAsset: Object, Slot: Number) -> Number
|
|
1028
1037
|
GetMaterialParameterTexture(MaterialAsset: Object, Slot: Number) -> Object
|
|
1029
1038
|
SetAnimationAssetSpeedFactor(AnimationAsset: Object, SpeedFactor: Number)
|
|
@@ -1084,8 +1093,8 @@ Position.ShiftLeft(Distance: Number, LeftOfObject: Object) -> Position
|
|
|
1084
1093
|
Position.ShiftRight(Distance: Number, RightOfObject: Object) -> Position
|
|
1085
1094
|
Position.ShiftForward(Distance: Number, ForwardOfObject: Object) -> Position
|
|
1086
1095
|
Position.ShiftBackward(Distance: Number, BackwardOfObject: Object) -> Position
|
|
1087
|
-
Position.SnapToTile2D(GridSize: Number, Origin: Position) -> Position
|
|
1088
|
-
Position.SnapToVoxel(GridSize: Number, Origin: Position) -> Position
|
|
1096
|
+
Position.SnapToTile2D(GridSize: Number, Origin: Position) -> Position // Center of the GridSize tile containing this point in XY (Z unchanged)
|
|
1097
|
+
Position.SnapToVoxel(GridSize: Number, Origin: Position) -> Position // Center of the GridSize cell containing this point (cells span [k*GridSize, (k+1)*GridSize) per axis from Origin) - the cell key VoxelGet/VoxelSet read; snap `hit - Direction.GetNormal()` for the cell to place on
|
|
1089
1098
|
Position.HasObjectAtPoint() -> Bool
|
|
1090
1099
|
Position.HasObjectAtPointWithTag(Tag: Number) -> Bool
|
|
1091
1100
|
GetObjectByIndex(Index: Number) -> Object
|
|
@@ -1396,8 +1405,8 @@ SpawnAtTile(SavedObject: Object, TileXYZ: Vector) -> Object
|
|
|
1396
1405
|
Object.TeleportToTile(TileX: Number, TileY: Number)
|
|
1397
1406
|
Object.TeleportToTile(TileX: Number, TileY: Number, TileZ: Number)
|
|
1398
1407
|
Object.TeleportToTile(TileXYZ: Vector)
|
|
1399
|
-
Object.SetRotation(Rotation: Vector) // Rotates about GetPosition() (bottom-center pivot for mesh objects). To spin about the middle: SetRotation(R) then SetCenterPosition(C) with C the fixed world center; any other hinge point: SetRotationWithPivot
|
|
1400
|
-
Object.SetRotation(X: Number, Y: Number, Z: Number) // Rotates about GetPosition() (bottom-center pivot for mesh objects). To spin about the middle: SetRotation(R) then SetCenterPosition(C) with C the fixed world center; any other hinge point: SetRotationWithPivot
|
|
1408
|
+
Object.SetRotation(Rotation: Vector) // Euler degrees X = roll, Y = pitch, Z = yaw, applied X then Y then Z about WORLD axes (R = Rz*Ry*Rx, same as Vector.RotateByEuler(Z, Y, X)); a facing/turn goes in Z. Rotates about GetPosition() (bottom-center pivot for mesh objects). To spin about the middle: SetRotation(R) then SetCenterPosition(C) with C the fixed world center; any other hinge point: SetRotationWithPivot
|
|
1409
|
+
Object.SetRotation(X: Number, Y: Number, Z: Number) // Euler degrees X = roll, Y = pitch, Z = yaw, applied X then Y then Z about WORLD axes (R = Rz*Ry*Rx, same as Vector.RotateByEuler(Z, Y, X)); a facing/turn goes in Z. Rotates about GetPosition() (bottom-center pivot for mesh objects). To spin about the middle: SetRotation(R) then SetCenterPosition(C) with C the fixed world center; any other hinge point: SetRotationWithPivot
|
|
1401
1410
|
Object.SetGroupRotationWithPivot(Pivot: AnyBasicType, Rotation: Vector)
|
|
1402
1411
|
Object.LookAtGroupWithPivot(Pivot: AnyBasicType, Target: AnyBasicType)
|
|
1403
1412
|
Object.SetRotationWithPivot(Pivot: Position, Rotation: Vector) // Part swings around its middle instead of its mount (wing root, tail base, door edge) -> rigid-rotate about world-space Pivot: sets Rotation and moves GetPosition accordingly. The position orbit composes from the CURRENT pose each call, so keep this the part's SOLE mover - interleaving another per-frame position writer compounds drift (for per-frame driving prefer SetRotation + SetCenterPosition). Rejects gravity/force receivers. Group receivers: SetGroupRotationWithPivot
|
|
@@ -1430,7 +1439,7 @@ Object.SetWaterColorMixRange(ShallowCm: Number, DeepCm: Number) // Depth range f
|
|
|
1430
1439
|
Object.SetWaterTransparency(Clarity: Number) // 1 = clear (full refraction), 0 = opaque surface.
|
|
1431
1440
|
Object.SetEmissionColor(RGB: Vector) // Glow tint; unset/near-black = glows in the object's own color
|
|
1432
1441
|
Object.SetEmissionColor(R: Number, G: Number, B: Number) // Glow tint; unset/near-black = glows in the object's own color
|
|
1433
|
-
Object.SetEmissionIntensity(Intensity: Number) // Linear glow: 0
|
|
1442
|
+
Object.SetEmissionIntensity(Intensity: Number) // Linear glow, 0 = off: 0.3-0.5 = tinted glow that keeps its colour, 1 = as bright as a sunlit white surface, 2 = pastel, 4+ reads white (bloom carries the tint), 8+ only for sub-pixel LEDs / sun discs
|
|
1434
1443
|
Object.SetLightIntensity(Intensity: Number)
|
|
1435
1444
|
Object.SetLightFadeWidth(FadeWidthCm: Number) // diffuseOnlyLight only (edge fade band; default 30, clamped to the light radius)
|
|
1436
1445
|
Object.SetLightCastShadow(Enabled: Bool)
|
|
@@ -1487,8 +1496,12 @@ Object.SetLocalPlacementGhostMode(Mode: Number) // PlayerObject only. 0 = single
|
|
|
1487
1496
|
Object.DisableLocalPlacementGhost() // PlayerObject only. Hides the local build ghost
|
|
1488
1497
|
Object.SetLocalPlacementGhostAnchor(GroundPos: Position) // PlayerObject only. Pin the mode-1/2 preview start to a world ground position (replaces the left-drag start while set): click-move-click roads - click 1 sets the anchor, the ghost previews anchor->cursor with no button held; commit + Clear on click 2 stay in script. Rejects invalid positions; Enable/Disable also clear it
|
|
1489
1498
|
Object.ClearLocalPlacementGhostAnchor() // PlayerObject only. Back to left-drag anchoring
|
|
1490
|
-
|
|
1491
|
-
|
|
1499
|
+
FieldStamp(FieldName: Text, Position: Position, RadiusCm: Number, Strength: Number) // Press a mark into a #fieldmap canvas this frame (display-only; see <field_maps>). Negative Strength erases
|
|
1500
|
+
FieldStampBoot(FieldName: Text, Position: Position, Facing: Vector, LengthCm: Number, Strength: Number, Side: Number) // Oriented boot print (heel, toe, sole tread) pressed into a #fieldmap: Facing = heading vector, LengthCm ~28, Side alternates -1/1 per step; needs <= 2.5 cm per texel for the tread to read (resolution 1024 with window_m <= 24). Round stamp: FieldStamp
|
|
1501
|
+
FieldStampCapsule(FieldName: Text, From: Position, To: Position, RadiusCm: Number, Strength: Number) // Flat-floored segment press for continuous furrows: From = last frame's position, To = now; one call per moving frame, no disc scallops. Rim as FieldStamp
|
|
1502
|
+
SetFieldMaterial(FieldName: Text, Material: Object) // Custom #fieldmap kernel: Material whose #shader defines ori_field_update (see <field_maps>). None restores the default stamp/heal kernel
|
|
1503
|
+
Object.SeatPlayer(Target: Object, AnchorName: Text) -> Bool // Park Target player (user or SpawnAIPlayer bot) on this object's named model anchor: the capsule suspends (collision/gravity/native controls) and the avatar rides the anchor until UnseatPlayer. False if the seat is occupied or Target is already seated/attached or in editor mode. Input reads keep flowing while seated - drive the vehicle from the occupant's GetMoveVectorCamera()/IsActionPressedByThisPlayer. The rider auto-plays .sit, seated ON the anchor point (the sit clip lifts the hips a pelvis height above it). Model vehicles without a driver socket: SetModelAnchor(GetModel(), "driver", <seat point = the pan surface, model-root local cm: cabin center, driver side, ~50cm above the underbody>, Vector(0,0,0)) once per model (all instances share it), then SeatPlayer; a "wheel" anchor at the rim center puts the driver's hands on it
|
|
1504
|
+
Object.SeatPlayerAt(Target: Object, SeatName: Text, Offset: Vector) -> Bool // SeatPlayer for objects without model anchors. SeatName is the seat key SeatOccupant queries; Offset (cm, local axes, rotates with it) is from this object's TOP-FACE CENTER - Vector(0,0,0) seats the rider on top (glutes on the surface), facing this object's +X with knees ~46cm forward. For PRIMITIVE-BUILT seats only (a cushion block). Never on a model vehicle - its top face is the roof; seat models with SetModelAnchor + SeatPlayer
|
|
1492
1505
|
Object.UnseatPlayer(Target: Object) -> Bool // Release a seated player at the seat's current world position, physics restored per their player mode (TeleportTo an exit spot right after for enclosed vehicles). False if Target is not seated on this object
|
|
1493
1506
|
Object.SeatOccupant(SeatName: Text) -> Object // Player seated on this object's named seat, or a None-like Object (check Exists())
|
|
1494
1507
|
Object.SeatedIn() -> Object // Object this player is seated on, or a None-like Object (check Exists())
|
|
@@ -1496,8 +1509,8 @@ TileGridRefreshFromTerrainRect(Grid: List, X1: Number, Y1: Number, X2: Number, Y
|
|
|
1496
1509
|
TileGridDebugOverlay(Grid: List, Enabled: Bool)
|
|
1497
1510
|
SpawnDecal(Material: Object, Position: Position, RotationEuler: Vector, Size: Vector) -> Object // Projects onto geometry inside its oriented box along local -Z (down at rotation 0); Size z = projection depth cm. Bullet holes/stains/scorch marks. No engine pool: keep spawned decals in a List and Destroy the oldest past a few hundred
|
|
1498
1511
|
SetScreenShader(Material: Object) // Fullscreen screen effect (film grain, color grade, distortion, damage flash): a #shader material applied after tonemap/AA; fragment reads ctx.color/ctx.depth. None clears. Animate via SetMaterialParameterNumber; see shader_dsl skill
|
|
1499
|
-
SetVolumetricLightIntensity(Percent: Number) // Sun shafts / god rays (raymarched vs the sun's shadows). Default: 0 (off); ~40 = subtle atmosphere, 100+ = dramatic alley/doorway shafts. Reads best with a low sun + occluding geometry
|
|
1500
|
-
SetVolumetricLightDensity(Percent: Number) // Haze thickness the shafts scatter in, percent of baseline. Default: 100; lower = crisper thinner shafts, higher = foggier
|
|
1512
|
+
SetVolumetricLightIntensity(Percent: Number) // Sun shafts / god rays (raymarched vs the sun's shadows). Default: 0 (off); ~40 = subtle atmosphere, 100+ = dramatic alley/doorway shafts. Reads best with a low sun + occluding geometry [global: all clients]
|
|
1513
|
+
SetVolumetricLightDensity(Percent: Number) // Haze thickness the shafts scatter in, percent of baseline. Default: 100; lower = crisper thinner shafts, higher = foggier [global: all clients]
|
|
1501
1514
|
Object.EnableLocalWeaponView(Offset: Position, RotationDegrees: Vector, Scale: Number, FovDegrees: Number) // EnableLocalWeaponView + own weapon FOV: FovDegrees 0 = follow camera; ~50-70 = classic FPS viewmodel that ignores ADS zoom and never clips walls
|
|
1502
1515
|
SetSoundVolume(Sound: Object, Volume: Number) // Live per-asset volume (1 = as authored): retunes every instance already playing, loops included, and every later play; the per-play PlaySound volume multiplies on top. 0 mutes but keeps loops running - StopSound to end them
|
|
1503
1516
|
FadeOutSound(Sound: Object, Seconds: Number) // Ramps this sound's playing instances to silence over Seconds, then stops them; queued plays drop immediately, plays started after the call are unaffected. Music/ambience handoffs - StopSound cuts instantly
|
|
@@ -1533,13 +1546,13 @@ GetGravity() -> Number
|
|
|
1533
1546
|
PersistGetNumber(Player: Object, Key: Text) -> Number
|
|
1534
1547
|
PersistSetNumber(Player: Object, Key: Text, Value: Number)
|
|
1535
1548
|
PersistAddNumber(Player: Object, Key: Text, Delta: Number)
|
|
1536
|
-
StatsEmit(Metric: Text, Key1: Text, Key2: Number, Value: Number) // run_orders grading probe: emit each graded metric once per second (zeros included); expects read the last sample at or before their frame, optionally key-scoped as <metric>[<Key1>]. Key2 is a free tag, not matched
|
|
1549
|
+
StatsEmit(Metric: Text, Key1: Text, Key2: Number, Value: Number) // run_orders grading probe: emit each graded metric once per second (zeros included); expects read the last sample at or before their frame, optionally key-scoped as <metric>[<Key1>]. Key2 is a free tag, not matched. Every object running the call emits: with mock players each player instance emits its own sample and the expect reads the last one, so key per-player metrics by player index (Key1)
|
|
1537
1550
|
RefreshStaticBaseline() // Call once at the end of heavy static-scene init; non-moving objects then skip per-frame display CPU (a later manipulation opts that object out).
|
|
1538
1551
|
RestartGame() // Reloads the WHOLE project (fresh load flow; discards the user's unsaved manual editor edits). Hard New Game only - pair with PersistClear(). Round/match resets: reset positions/scores in code instead.
|
|
1539
1552
|
AnyBasicType.NearestPlayerNonSpectator() -> Object
|
|
1540
|
-
SetSsrRoughnessFade(StartRoughness: Number, EndRoughness: Number) // Default: 0.68, 0.7
|
|
1541
|
-
SetSsrRayFade(NearFadePower: Number, FarFadePower: Number) // Default: 0.08, 0.8
|
|
1542
|
-
SetSkyboxHue(HueDegrees: Number) // Default: 0
|
|
1553
|
+
SetSsrRoughnessFade(StartRoughness: Number, EndRoughness: Number) // Default: 0.68, 0.7 [global: all clients]
|
|
1554
|
+
SetSsrRayFade(NearFadePower: Number, FarFadePower: Number) // Default: 0.08, 0.8 [global: all clients]
|
|
1555
|
+
SetSkyboxHue(HueDegrees: Number) // Default: 0 [global: all clients]
|
|
1543
1556
|
SetSkyboxContrast(Contrast: Number) // Contrast multiplier. Default: 1 = neutral [global: all clients]
|
|
1544
1557
|
Hash2(X: Number, Y: Number, Seed: Number) -> Number // Deterministic [0,1): constant within each integer X/Y cell (see <procedural_generation>)
|
|
1545
1558
|
ValueNoise2(X: Number, Y: Number, Seed: Number) -> Number // Deterministic smooth noise [0,1), X/Y in cell units
|
|
@@ -1598,11 +1611,11 @@ Object.SetEmitting(IsOn: Bool) // EffectObject only. false: stop spawning new pa
|
|
|
1598
1611
|
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).
|
|
1599
1612
|
Object.DestroyImmediate() // EffectObject only. Destroys the emitter and hard-clears its live particles instantly (no dying tail).
|
|
1600
1613
|
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)
|
|
1601
|
-
SetSkyboxCloudCoverage(Coverage: Number) // Procedural sky only (no SetSkybox asset). Default: 0.
|
|
1614
|
+
SetSkyboxCloudCoverage(Coverage: Number) // Procedural sky only (no SetSkybox asset). Default: 0.15; 0 = clear sky, 1 = overcast [global: all clients]
|
|
1602
1615
|
SetSkyboxHaze(Haze: Number) // Procedural sky only. Default: 0.5; 0.3 = crisp alpine air, 2-3 = hazy horizon [global: all clients]
|
|
1603
1616
|
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]
|
|
1604
|
-
SetSkyboxCloudDetail(Detail: Number) // Procedural sky only. Cloud fractal detail. Default: 1; 0 = soft blobs, 2 = max wispy detail
|
|
1605
|
-
SetSkyboxCloudScale(Scale: Number) // Procedural sky only. Cloud pattern size. Default: 1; 0.5 = big clouds, 2 = many small clouds
|
|
1617
|
+
SetSkyboxCloudDetail(Detail: Number) // Procedural sky only. Cloud fractal detail. Default: 1; 0 = soft blobs, 2 = max wispy detail [global: all clients]
|
|
1618
|
+
SetSkyboxCloudScale(Scale: Number) // Procedural sky only. Cloud pattern size. Default: 1; 0.5 = big clouds, 2 = many small clouds [global: all clients]
|
|
1606
1619
|
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]
|
|
1607
1620
|
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
|
|
1608
1621
|
SetSkyBillboardDirection(Slot: Number, RotationDegrees: Number, TiltDegrees: Number) // Where in the sky (same convention as SetSunRotation/SetSunTilt). Default: 0, 45
|
|
@@ -1611,7 +1624,7 @@ SetSkyBillboardColor(Slot: Number, Color: Vector) // Tint. Default: (1, 1, 1)
|
|
|
1611
1624
|
SetSkyBillboardIntensity(Slot: Number, Intensity: Number) // Default: 1; >1 glows (HDR bloom)
|
|
1612
1625
|
SetSkyBillboardRoll(Slot: Number, RollDegrees: Number) // Rotation around the view direction. Default: 0
|
|
1613
1626
|
SetSkyBillboardAdditive(Slot: Number, IsAdditive: Bool) // true = additive glow blend (galaxy/gate), false = alpha over sky (moon). Default: false
|
|
1614
|
-
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
|
|
1627
|
+
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. Grid (DATA/heights) terrains only: a SpawnTerrainRecipe terrain has no baked splat texels, so the call is a silent no-op there - paint recipe ground with SetTerrainSurfaceWeightsMaterial, or sample the block into a grid (TerrainHeightsFromTerrain) first
|
|
1615
1628
|
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]
|
|
1616
1629
|
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
|
|
1617
1630
|
Object.SetHoverSPBarMaterial(Material: Object) // Same as SetHoverHPBarMaterial for the hover SP bar
|
|
@@ -1665,7 +1678,8 @@ SetGrassSizeVariationPercent(Percent: Number) // Global per-tuft/per-clump heigh
|
|
|
1665
1678
|
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]
|
|
1666
1679
|
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]
|
|
1667
1680
|
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]
|
|
1668
|
-
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;
|
|
1681
|
+
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; blade count is SetGrassBladeDensityPercent [global: all clients]
|
|
1682
|
+
SetGrassBladeDensityPercent(Percent: Number) // Built-in tuft cards: percent of each tuft's blades that stand (100 = default, clamped 10..100); lower = blades farther apart, wispier. Width is SetGrassBladeWidthPercent [global: all clients]
|
|
1669
1683
|
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
|
|
1670
1684
|
ItemName(Item: Object) -> Text // Item def's display name (Item.X handle); "" if not an item
|
|
1671
1685
|
ItemTip(Item: Object) -> Text // Item def's tooltip text; "" if not an item
|
|
@@ -1702,16 +1716,16 @@ Text.Length() -> Number // Character count (chars, not bytes - Thai etc. count p
|
|
|
1702
1716
|
Text.Substring(Start: Number, Count: Number) -> Text // Chars [Start, Start+Count), 0-based, clamped to the text; negative Start or Count <= 0 -> empty Text.
|
|
1703
1717
|
Text.Contains(Needle: Text) -> Bool // True when the text contains Needle (case-sensitive; empty Needle -> true).
|
|
1704
1718
|
Text.Replace(From: Text, To: Text) -> Text // Every occurrence of From replaced by To; empty From returns the text unchanged.
|
|
1705
|
-
SetOcclusionCulling(Enabled: Bool) // Default:
|
|
1719
|
+
SetOcclusionCulling(Enabled: Bool) // Default: true (Hi-Z occlusion culling on static and skinned draws; false disables) [global: all clients]
|
|
1706
1720
|
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)
|
|
1707
1721
|
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]
|
|
1708
1722
|
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
|
|
1709
|
-
SetTerrainDisplayExtension(RadiusM: Number) // Optional render-distance override for recipe terrains (SpawnTerrainRecipe defaults to 8 km; DATA terrains built with TerrainHeightsFromTerrain render the extension beyond their grid, display-only). RadiusM 0 = off. Pair with SetCameraFarDistanceM to actually see far terrain
|
|
1710
|
-
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)
|
|
1723
|
+
SetTerrainDisplayExtension(RadiusM: Number) // Optional render-distance override for recipe terrains (SpawnTerrainRecipe defaults to 8 km; DATA terrains built with TerrainHeightsFromTerrain render the extension beyond their grid, display-only). RadiusM 0 = off. Pair with SetCameraFarDistanceM to actually see far terrain [global: all clients]
|
|
1724
|
+
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) [global: all clients]
|
|
1711
1725
|
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
|
|
1712
1726
|
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
|
|
1713
1727
|
SetDefaultFloatingTextFont(Font: Object) // World default font for SpawnFloatingText/SpawnDamageNumber (e.g. Ori.font.google.Lobster); None reverts to built-in
|
|
1714
|
-
SetWaterEnabled(Enabled: Bool
|
|
1728
|
+
SetWaterEnabled(Enabled: Bool) // THE main water: global displaced ocean surface (Gerstner waves) at the SetWaterSeaLevelCm 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]
|
|
1715
1729
|
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]
|
|
1716
1730
|
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]
|
|
1717
1731
|
TerrainHeightsFromTerrain(Heights: List, RidgesOut: List, SamplesX: Number, SamplesY: Number, CellSizeCm: Number) // Bake the world's #terrain recipe block (recipe + modifier rows; runtime digs excluded) into a bounded Heights grid (gradient base -> height mask -> erosion; errors without a block) - for hand-editing the result with TerrainHeights* ops before SpawnTerrainFromHeights. For plain recipe ground prefer SpawnTerrainRecipe (no bake). 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)
|
|
@@ -1727,7 +1741,7 @@ Object.SetCharacterOverlapIgnoreTag(Tag: Number, IsOn: Bool) // This character's
|
|
|
1727
1741
|
Object.SetDefaultPlayerControlsEnabled(IsOn: Bool) // Weave2 only, player receiver. true: attach the built-in default player controls (WASD camera-relative move + jump) alongside this class — the one-liner for '#class player' hooks that don't code their own movement. false: detach them (freeze for cutscenes; classless-world players can be frozen from any class). Idempotent
|
|
1728
1742
|
Object.AttachTo(Parent: Object) // Rigidly ride Parent from the CURRENT relative pose (re-baked from Parent's post-physics transform every tick; overrides this object's own moves). Child must be collision-free: display/effect/light/marker objects, or SetCanCollide(false) first. Chains allowed (arm -> gun); cycles error. Replaces per-frame SetPosition follow loops. Order-sensitive in OnSpawned (parent may not be placed yet) - prefer the 3-arg overload there
|
|
1729
1743
|
Object.AttachTo(Parent: Object, LocalPosition: Position, LocalRotation: Vector) // Explicit-mount overload: LocalPosition (absolute cm) and LocalRotation (euler degrees) in Parent's local frame; safe in OnSpawned. The frame runs CENTER-to-CENTER (not the bottom-center pivot GetPosition/#mesh use): seat a child by adding half ITS height to the offset. Offsets don't rescale when Parent's size changes - re-attach after growth
|
|
1730
|
-
Object.AttachToAnchor(Parent: Object, AnchorName: Text) // AttachTo at a named model anchor of Parent's mesh (e.g. "muzzle", "grip"); an anchor missing on Parent's own mesh falls back to the EQUIPPED weapon's anchors (child then follows the held weapon, FP viewmodel included); errors when neither carries it (anchors resolve after asset import). The anchor's axis is its local +Z but object/effect forward is local +X - directional effects on an anchor need a LocalRotation (usually RotY +-90). The mount point follows the parent's scale at attach time (where the socket visually sits); captured offsets don't re-follow LATER parent rescales. A `bone:`-bound socket anchor makes the child visually ride that bone's animation (sim pose stays rest)
|
|
1744
|
+
Object.AttachToAnchor(Parent: Object, AnchorName: Text) // AttachTo at a named model anchor of Parent's mesh (e.g. "muzzle", "grip"); an anchor missing on Parent's own mesh falls back to the EQUIPPED weapon's anchors (child then follows the held weapon, FP viewmodel included); errors when neither carries it (anchors resolve after asset import). The anchor's axis is its local +Z but object/effect forward is local +X - directional effects on an anchor need a LocalRotation (usually RotY +-90). The mount point follows the parent's scale at attach time (where the socket visually sits); captured offsets don't re-follow LATER parent rescales. A `bone:`-bound socket anchor makes the child visually ride that bone's animation (sim pose stays rest). The child's CENTER lands on the anchor (not its bottom-center pivot, not a grip socket); to mount by one of the CHILD's sockets use the 3-arg overload
|
|
1731
1745
|
Object.Detach() // Remove this object's attachment; it keeps its current world transform. Refused for seated players (UnseatPlayer restores their physics)
|
|
1732
1746
|
Object.GetAttachParent() -> Object // Attachment parent, or None-like non-existing Object when not attached (check with Exists())
|
|
1733
1747
|
EaseIn(T: Number) -> Number
|
|
@@ -1740,7 +1754,7 @@ Object.RemoveTag(Tag: Number) // Clear one tag from this object (AddTag's invers
|
|
|
1740
1754
|
Object.AttachToPositionOnly(Parent: Object) // AttachTo variant that follows Parent's POSITION only (captures the current offset in Parent's local frame, so it still swings with Parent's rotation) while this object's own rotation stays script-driven (SetRotation/LookAt keep working). For children that aim independently: beam FX, turret heads, billboards
|
|
1741
1755
|
SetWaterChurnEffect(Effect: Object) // Replace the built-in bow-spray churn mist that trails fast swimmers/waders world-wide. Pass an Effect asset. Visual only; the built-in mist is used until this is called
|
|
1742
1756
|
SetWaterFootstepEffect(Effect: Object) // Replace the built-in shallow-water footstep splash (expanding ring + puffs + droplets) world-wide. Pass an Effect asset. Visual only; the built-in is used until this is called
|
|
1743
|
-
Object.SetWaterFlow(SpeedMps: Number, ForcedFall: Bool) // Water-object only. Stream/fall flow: SpeedMps (0 = still; quantized 0.025, max 3.175) advects refraction+foam along the mesh's world local +X axis - rotate the mesh to steer. ForcedFall=true
|
|
1757
|
+
Object.SetWaterFlow(SpeedMps: Number, ForcedFall: Bool) // Water-object only. Stream/fall flow: SpeedMps (0 = still; quantized 0.025, max 3.175) advects refraction+foam along the mesh's world local +X axis - rotate the mesh to steer. ForcedFall=true is the only way to get the falling-water (waterfall) look - steep and rotated meshes stay still water until you ask
|
|
1744
1758
|
Vector.Dot(Other: Vector) -> Number // Dot product (Number). 0 = perpendicular; with unit vectors, 1 = same direction, -1 = opposite
|
|
1745
1759
|
Vector.Cross(Other: Vector) -> Vector // Cross product (Vector), right-handed: X.Cross(Y) = Z. Perpendicular to both inputs
|
|
1746
1760
|
Vector.RotateByEuler(Yaw: Number, Pitch: Number, Roll: Number) -> Vector // Rotate this vector by euler degrees, standard ZYX order: yaw about Z, then pitch about Y, then roll about X (Z-up). Replaces hand-rolled rotation matrices
|
|
@@ -1795,7 +1809,7 @@ Object.RemoveInstance(Index: Number) // Batch only. Swap-remove: the LAST instan
|
|
|
1795
1809
|
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]
|
|
1796
1810
|
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.
|
|
1797
1811
|
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.
|
|
1798
|
-
SetSkyboxCloudType(Type: Number) // Procedural sky only. Cloud vertical form. Default: 0.
|
|
1812
|
+
SetSkyboxCloudType(Type: Number) // Procedural sky only. Cloud vertical form. Default: 0.4; 0 = flat haze layer, 1 = towering cumulus [global: all clients]
|
|
1799
1813
|
CreateStaticInstanceBatch(Model: Object, Origin: Position) -> Object // Display-only STATIC scatter batch (see <procedural_generation>); Model: Ori.model.* (basics like Ori.model.cone work) or Ori.alias.model.* - mesh models ONLY (effects/images/spawned Objects are rejected at runtime). Max 128 live per world - Destroy() frees. Never mutate per frame - each edit (SetBatchOrigin included) re-uploads the whole batch. Sway/shimmer: vertex #shader on the model's material; instances that truly move: objects or #particles
|
|
1800
1814
|
GetRayHitPart(Position: Position, Direction: Vector, Tag: Number) -> Text // Tag filters to objects WITH that tag; 0 is a real tag index, NOT "no filter" — use the 2-arg overload for unfiltered rays. Names the hit volume posed by the target's current animation: "head"/"torso"/"pelvis"/"upper_arm_l"/"forearm_r"/"thigh_l"/"shin_r"/...; "" on miss, rigless target, or a hit outside every volume (treat as a plain body hit) — gate damage on GetRayHitObject, use the part for multipliers. The caster's own body never blocks or names its rays (whole GetRayHit* family, like RaycastObject).
|
|
1801
1815
|
GetRayHitPart(Position: Position, Direction: Vector) -> Text // Unfiltered twin: same part names and "" semantics as GetRayHitPart.
|
|
@@ -1847,6 +1861,8 @@ TileGridBakeCrowdObstacles(Grid: List)
|
|
|
1847
1861
|
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>
|
|
1848
1862
|
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)
|
|
1849
1863
|
SetWaterMurkDensity(Density: Number) // Scales underwater-camera murk: 1 = default, 0 = crystal clear (underwater/side-view games), max 4. [global: all clients]
|
|
1864
|
+
SetWaterSeaLevelCm(SeaLevelCm: Number) // Ocean sea level (world Z cm). Hand-tuned constants belong in its #adjuster knob line; call this only to move the level at runtime (tides/floods). Default: 0 [global: all clients]
|
|
1865
|
+
Object.SetWaterShader(Material: Object) // Water-object only (SetIsWater). This mesh's own water shading: a #shader Material whose body defines fn shade_water (same fork contract as SetWaterShader); its mat.params4 are that material's SetMaterialParameterNumber slots. None = back to the global SetWaterShader / engine water. Ocean and voxel water take only the global override
|
|
1850
1866
|
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
|
|
1851
1867
|
TileGridFindPath4NextTo(Grid: List, StartX: Number, StartY: Number, GoalX: Number, GoalY: Number) -> List
|
|
1852
1868
|
TileGridFindPath8NextTo(Grid: List, StartX: Number, StartY: Number, GoalX: Number, GoalY: Number) -> List
|
|
@@ -1870,10 +1886,13 @@ VoxelSetHeightBox(Min: Position, Max: Position, Height: Number) -> Number // Vox
|
|
|
1870
1886
|
Object.MoveUiToFront() // Moves the element last among its siblings = draws on top (inside a vStack/hStack/grid it also takes the last layout slot). Z-order otherwise stays declaration order
|
|
1871
1887
|
Object.SetUiOffset(X: Number, Y: Number, Seconds: Number) // Glides to the target over Seconds (EaseInOut). Same-property call replaces the running glide; the instant 2-arg call cancels it. SetUiSize/SetUiOpacity/SetUiColor have the same overloads
|
|
1872
1888
|
Object.SetUiOffset(X: Number, Y: Number, Seconds: Number, Ease: Number) // Ease 0=linear 1=in 2=out 3=in-out 4=out-back 5=out-bounce (offset/size/opacity glides)
|
|
1889
|
+
Object.SetUiOffset(X: Number, Y: Number, Seconds: Number, Ease: Number, Delay: Number) // Delay: seconds before it starts; queues behind a running glide on the same property (one queued glide per property; SetUiSize/SetUiOpacity/SetUiRotation have the same form)
|
|
1873
1890
|
Object.SetUiSize(Width: Number, Height: Number, Seconds: Number)
|
|
1874
1891
|
Object.SetUiSize(Width: Number, Height: Number, Seconds: Number, Ease: Number)
|
|
1892
|
+
Object.SetUiSize(Width: Number, Height: Number, Seconds: Number, Ease: Number, Delay: Number)
|
|
1875
1893
|
Object.SetUiOpacity(Opacity01: Number, Seconds: Number)
|
|
1876
1894
|
Object.SetUiOpacity(Opacity01: Number, Seconds: Number, Ease: Number)
|
|
1895
|
+
Object.SetUiOpacity(Opacity01: Number, Seconds: Number, Ease: Number, Delay: Number)
|
|
1877
1896
|
Object.SetUiColor(Color: Vector, Seconds: Number) // Glides rgb over Seconds (in-out; alpha untouched; no Ease arg - it would collide with the SetUiColor(r, g, b) form)
|
|
1878
1897
|
Object.GetUiOffsetX() -> Number // Current offset in base units (mid-glide = the in-flight value); GetUiSizeX/Y same for size
|
|
1879
1898
|
Object.GetUiOffsetY() -> Number
|
|
@@ -1882,7 +1901,11 @@ Object.GetUiSizeY() -> Number
|
|
|
1882
1901
|
Object.SetUiRotation(Degrees: Number) // Spins the element AND its subtree around the element's rect center (degrees, +CW). Fanned card hands, dials, compasses. Hit-testing follows; clipping stays the screen-AABB scissor. Same glide overloads as SetUiOffset
|
|
1883
1902
|
Object.SetUiRotation(Degrees: Number, Seconds: Number)
|
|
1884
1903
|
Object.SetUiRotation(Degrees: Number, Seconds: Number, Ease: Number)
|
|
1904
|
+
Object.SetUiRotation(Degrees: Number, Seconds: Number, Ease: Number, Delay: Number)
|
|
1885
1905
|
Object.GetUiRotation() -> Number // Current rotation in degrees (mid-glide = in-flight value)
|
|
1906
|
+
Object.SetUiBorder(Width: Number, Color: Vector) // Runtime border (base units + rgb); width 0 clears
|
|
1907
|
+
Object.SetUiCornerRadius(Radius: Number) // Runtime corner radius (base units)
|
|
1908
|
+
Object.GetUiName() -> Text // The element's own name; count copies are <Name>0..N-1
|
|
1886
1909
|
TileGridCreateFromTerrain(TilesX: Number, TilesY: Number, OriginTile: Vector, MaxSlope01: Number, MaxStepCm: Number) -> List
|
|
1887
1910
|
TileGridRegionAt(Grid: List, X: Number, Y: Number) -> Number // FromTerrain grids: region id of the tile (0 = unwalkable); equal ids = reachable from each other; ids link only across explored chunks, so settle a different id with TileGridIsReachable
|
|
1888
1911
|
Object.SetCameraRollThisFrame(RollDegrees: Number) // One-frame roll of the camera about its view axis (degrees, + = clockwise; call every frame to hold, decays to 0 like the other ThisFrame overrides). Composes with every camera mode. Display-only. NOTE: cursor picking and world-anchored UI stay roll-unaware - off-center clicks skew while rolled; fine for tilt/shake/lean.
|
|
@@ -1908,11 +1931,14 @@ GetWaterAmountRect(X1: Number, Y1: Number, X2: Number, Y2: Number) -> Number //
|
|
|
1908
1931
|
SetWaterEvaporation(CmPerSecond: Number) // World evaporation rate in cm of depth per second (default 0 = water is permanent); also clears the thin damp films flowing water leaves behind
|
|
1909
1932
|
AddWaterSource(X: Number, Y: Number, CmPerSecond: Number) // Plants a permanent spring at the point: pours CmPerSecond of depth into that cell every tick until removed. Feed a slope for a river, a basin for a filling lake; pair with SetWaterEvaporation so the world reaches a steady state
|
|
1910
1933
|
RemoveWaterSourceAt(X: Number, Y: Number) // Removes any springs in the cell at the point
|
|
1911
|
-
SetWaterShader(Material: Object) // Replace ALL water surface shading (placed water, voxel water tiles, ocean) with a #shader material whose body defines the full fn shade_water - fork the stock source (read_shader Ori.shader.builtin.water_default), never write from scratch. None restores engine water. mat.params4 works via SetMaterialParameterNumber; material texture slots not yet. See shader_dsl skill
|
|
1934
|
+
SetWaterShader(Material: Object) // Replace ALL water surface shading (placed water, voxel water tiles, ocean) with a #shader material whose body defines the full fn shade_water - fork the stock source (read_shader Ori.shader.builtin.water_default), never write from scratch. None restores engine water. mat.params4 works via SetMaterialParameterNumber; material texture slots not yet. Per placed-water mesh: Object.SetWaterShader. See shader_dsl skill
|
|
1912
1935
|
Object.MoveAlongTileFlowContinuous(Field: List, Grid: List, Speed: Number) -> Bool
|
|
1913
1936
|
Object.SetRenderHiddenForPlayerIndex(PlayerIndex: Number) // Inverse: render/pick HIDDEN for exactly this player index, visible to everyone else (shared object with a private replacement preview); also sets owner metadata
|
|
1914
|
-
DrawPreviewForPlayer(PlayerIndex: Number, SavedObject: Object, Position: Position, Rotation: Vector) // Same ghost draw, rendered only on PlayerIndex's client (per-player build previews); an index with no live player draws nowhere
|
|
1915
|
-
DrawPreviewForPlayerWithSizeAndColor(PlayerIndex: Number, SavedObject: Object, Position: Position, Rotation: Vector, Size: Vector, Color: Vector) // Same ghost draw, rendered only on PlayerIndex's client (per-player build previews); an index with no live player draws nowhere
|
|
1937
|
+
DrawPreviewForPlayer(PlayerIndex: Number, SavedObject: Object, Position: Position, Rotation: Vector) // Same ghost draw, rendered only on PlayerIndex's client (per-player build previews); an index with no live player draws nowhere. Draws the saved objects with their own materials and alpha (alpha < 1 = dithered ghost, no shadow); WithSizeAndColor tints them
|
|
1938
|
+
DrawPreviewForPlayerWithSizeAndColor(PlayerIndex: Number, SavedObject: Object, Position: Position, Rotation: Vector, Size: Vector, Color: Vector) // Same ghost draw, rendered only on PlayerIndex's client (per-player build previews); an index with no live player draws nowhere. Draws the saved objects with their own materials and alpha (alpha < 1 = dithered ghost, no shadow); WithSizeAndColor tints them
|
|
1939
|
+
SetWaterCausticIntensity(Scale: Number) // Scales the caustic light ripples on ground under the ocean: 1 = default, 0 = off, max 3. Knob-able (Find > Water). [global: all clients]
|
|
1940
|
+
SetBodylessMoveDeferred(Deferred: Bool) // Rollout switch, call once in OnSpawned: true = objects WITHOUT a physics body (display/UI markers) apply Move*Continuous* at the next physics step exactly like body-backed movers, so a marker and a player driven by identical calls stay aligned (same-tick GetPosition reads pre-move for both). Default false = legacy immediate translate.
|
|
1941
|
+
SetDLSS5(Enabled: Bool) // Default: false. Toggles the host-configured ONNX scene model in browser builds with TAAU; unsupported clients keep ordinary rendering. No NVIDIA DLSS 5 model is bundled
|
|
1916
1942
|
|
|
1917
1943
|
</built_in_function_list>
|
|
1918
1944
|
|
|
@@ -1921,7 +1947,7 @@ DrawPreviewForPlayerWithSizeAndColor(PlayerIndex: Number, SavedObject: Object, P
|
|
|
1921
1947
|
- X/Y are in cell units: scale world coords down (e.g. Fbm2(pos.X / 800, pos.Y / 800, 4, 7)); features repeat at integer-cell scale. Use a different Seed per layer (trees vs rocks).
|
|
1922
1948
|
- SpawnTerrainFromHeights spawns a collidable terrain heightfield from code (DATA exception lane - default ground is the #terrain recipe block, see <terrain_generation>); heights are row-major (iy * SamplesX + ix), in cm relative to Position.Z. Terrain XY is centered on Position.
|
|
1923
1949
|
- terrain.GetTerrainHeightAt(X, Y) returns the world-space surface Z at world (X, Y) (bilinear); errors if the caller has no heightfield or (X, Y) is outside it.
|
|
1924
|
-
- Terrain grass: every terrain grows sparse built-in grass automatically; grass_visible = false / terrain.SetTerrainGrassVisible(false) removes it entirely (deserts, cities). The ground under the blades is the terrain's own splat/material — style it with `#terrain_splat` rules or terrain layers. Set from code via terrain.SetTerrainGrass / terrain.SetTerrainGrassWeightmap / terrain.SetTerrainGrassHeightCm / terrain.SetTerrainGrassStyle / terrain.SetTerrainGrassVisible (all per-terrain), or declaratively on terrain blocks (grass_model = "mesh.X", grass_material = "material.X", grass_weightmap = "image.X" or a #texture color, grass_height_cm = 28, grass_visible = true/false, grass_style = "blades"). No model = built-in grass: cheap alpha-cut tuft cards by default, or geometry blades via SetTerrainGrassStyle(1) (heavier, best with SetGrassSpacingCm 8..15 for dense hero fields). Custom #mesh blade budget: tiny tuft (<=100 verts), single material slot, bottom-anchored at Z=0; blade size comes from authoring the mesh at the right cm size, then grass_height_cm rescales it (28 = as-authored). Global tuning calls: SetGrassSpacingCm, SetGrassTerrainActiveDistanceM, SetGrassCullDistanceM, SetGrassFadeDistancePercent, SetGrassFarThinningPower; look calls: SetGrassRootColor, SetGrassTipColor, SetGrassBrightnessVariationPercent, SetGrassSizeVariationPercent, SetGrassHeightMinCm, SetGrassHeightMaxCm, SetGrassBladeWidthPercent, SetGrassWavePeriodCm, SetGrassWindStrengthCm, SetGrassWindSpeedPercent.
|
|
1950
|
+
- Terrain grass: every terrain grows sparse built-in grass automatically; grass_visible = false / terrain.SetTerrainGrassVisible(false) removes it entirely (deserts, cities). The ground under the blades is the terrain's own splat/material — style it with `#terrain_splat` rules or terrain layers. Set from code via terrain.SetTerrainGrass / terrain.SetTerrainGrassWeightmap / terrain.SetTerrainGrassHeightCm / terrain.SetTerrainGrassStyle / terrain.SetTerrainGrassVisible (all per-terrain), or declaratively on terrain blocks (grass_model = "mesh.X", grass_material = "material.X", grass_weightmap = "image.X" or a #texture color, grass_height_cm = 28, grass_visible = true/false, grass_style = "blades"). No model = built-in grass: cheap alpha-cut tuft cards by default, or geometry blades via SetTerrainGrassStyle(1) (heavier, best with SetGrassSpacingCm 8..15 for dense hero fields). Custom #mesh blade budget: tiny tuft (<=100 verts), single material slot, bottom-anchored at Z=0; blade size comes from authoring the mesh at the right cm size, then grass_height_cm rescales it (28 = as-authored). Global tuning calls: SetGrassSpacingCm, SetGrassTerrainActiveDistanceM, SetGrassCullDistanceM, SetGrassFadeDistancePercent, SetGrassFarThinningPower; look calls: SetGrassRootColor, SetGrassTipColor, SetGrassBrightnessVariationPercent, SetGrassSizeVariationPercent, SetGrassHeightMinCm, SetGrassHeightMaxCm, SetGrassBladeWidthPercent, SetGrassBladeDensityPercent, SetGrassWavePeriodCm, SetGrassWindStrengthCm, SetGrassWindSpeedPercent.
|
|
1925
1951
|
- The same noise is available in #shader WGSL: ori_hash2(x, y, seed), ori_value_noise2(x, y, seed), ori_fbm2(x, y, octaves, seed) (f32; seed/octaves u32/i32), ori_hash2_cell(cx, cy, seed) -> u32. Matches the Weave functions exactly at integer lattice points, so sim placement and shader visuals can share one layout.
|
|
1926
1952
|
Example (hills + deterministic tree scatter):
|
|
1927
1953
|
#class WorldGen
|
|
@@ -1989,6 +2015,9 @@ height[, seed]` - signed relief composed into the base BEFORE erosion, so gullie
|
|
|
1989
2015
|
through them like native terrain (flats/carves apply after and win locally).
|
|
1990
2016
|
Line landform: `ridge_path = width, height, x0, y0, x1, y1, ...` - a noise-varied crest
|
|
1991
2017
|
along the polyline (mountain ranges), eroded like other landforms; `smooth` applies too.
|
|
2018
|
+
`landform_blend = max` (header key; default add): overlapping landforms and ridges keep the
|
|
2019
|
+
highest relief (deepest for craters) instead of summing - stack shapes without deforming
|
|
2020
|
+
ones that already read right.
|
|
1992
2021
|
Layer rows (same grammar/cap): `noise = height_m, size_m, octaves, gain, seed[, mode]` -
|
|
1993
2022
|
additive base-noise layer; stack several sizes for multi-scale relief (continents + hills +
|
|
1994
2023
|
detail). mode = TerrainHeightsNoise's table (0 fbm, 1 ridged, 2 billow, 3 voronoi, 5 spike
|
|
@@ -2030,10 +2059,15 @@ VoxelSet / VoxelFillBox / VoxelFillSphere edit blocks (Id 0 = air, N = N-th surf
|
|
|
2030
2059
|
reads one; height tools overwrite only the span they move, so caves below stay. Without
|
|
2031
2060
|
overhangs the block calls are errors. RaycastPosition hits block faces: hit +
|
|
2032
2061
|
Direction.GetNormal() is inside the block, hit - Direction.GetNormal() is the cell to place on.
|
|
2033
|
-
|
|
2062
|
+
Cells span [k*GridSize, (k+1)*GridSize) from Origin; SnapToVoxel returns the cell CENTER (the VoxelGet/VoxelSet key); GroundHeightAtXY is block-snapped.
|
|
2063
|
+
Same session-overlay rules (TerrainOverlayClear resets). Block art: a top-level
|
|
2064
|
+
`#terrain_surfaces <Name> ... #end` block holds up to 8 `surface = <albedo>, <normal>, <tiling_m>[, <orm>[, <grass01>]]`
|
|
2065
|
+
lines with UNQUOTED urls (`baked.<Texture>.color/.normal/.orm` for #texture bakes); block ids and
|
|
2066
|
+
block_strata numbers are its 1-based line order; bind it with terrain.SetTerrainSurfaces("<Name>").
|
|
2067
|
+
Layers resample into one fixed 1024 px array (512 on web); a `filter = nearest` bake keeps hard texels there too.
|
|
2034
2068
|
- 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 spawning the terrain in the same event.
|
|
2035
2069
|
- 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>).
|
|
2036
|
-
- Water: sea/lakes at one level -> SetWaterEnabled(true
|
|
2070
|
+
- Water: sea/lakes at one level -> SetWaterEnabled(true) + SetWaterSeaLevelCm(seaLevelCm); pools/streams/falls at other heights -> flat SetIsWater(true) objects (SetWaterFlow steers rivers/falls).
|
|
2037
2071
|
|
|
2038
2072
|
DATA exception lane - TerrainHeights* ops on a heights List -> SpawnTerrainFromHeights
|
|
2039
2073
|
(bounded baked grid). Use ONLY when the look needs grid-global ops (routed drainage,
|
|
@@ -2086,6 +2120,43 @@ Two terrain display types:
|
|
|
2086
2120
|
Grass density likewise: SetTerrainGrassSpawnMaterial with a custom spawn compute #shader.
|
|
2087
2121
|
</terrain_generation>
|
|
2088
2122
|
|
|
2123
|
+
<field_maps>
|
|
2124
|
+
#fieldmap <Name> ... #end (top level): a persistent GPU data map over the world around
|
|
2125
|
+
the camera, stamped from scripts and evolved per frame - carved snow/sand/mud trails,
|
|
2126
|
+
footprints, scorch marks, wetness, crushed grass, gust fields. Display-only: gameplay
|
|
2127
|
+
can never read it back (spatial logic belongs in TileGrid state).
|
|
2128
|
+
Keys (all optional - a bare block is a working stamp-accumulate map): resolution = 256
|
|
2129
|
+
(pow2 64..1024), window_m = 120 (world window following the camera), format = rgba8 |
|
|
2130
|
+
rgba16f, heal_seconds = 0 (default kernel: stamps fade back over this; 0 = permanent).
|
|
2131
|
+
Max 2 per world; starts at zero.
|
|
2132
|
+
FieldStamp(Name, Position, RadiusCm, Strength): press one mark this frame (cap 64/frame,
|
|
2133
|
+
nearest camera win; negative Strength erases). Calling it every frame per moving entity
|
|
2134
|
+
is the intended use. FieldStampCapsule(Name, From, To, RadiusCm, Strength): the same as a
|
|
2135
|
+
flat-floored segment (From = last frame's position) - continuous furrows without disc
|
|
2136
|
+
scallops.
|
|
2137
|
+
The default kernel needs no shader (max-accumulate into r, g = the pushed-up rim just
|
|
2138
|
+
outside each press, b = seconds since the last press; walls settle only for their first
|
|
2139
|
+
seconds, heal refills). Custom dynamics
|
|
2140
|
+
(ripples, spread, wind advection): SetFieldMaterial(Name, Material.M) - M's #shader body
|
|
2141
|
+
defines fn ori_field_update(ctx: OriFieldCtx) -> vec4<f32> (whole-function hook like
|
|
2142
|
+
surface weights, no own bindings; fork the stock body: read_shader
|
|
2143
|
+
Ori.shader.builtin.fieldmap_default). ctx: prev (vec4, zero on texels new to the window),
|
|
2144
|
+
world_pos (render XZ meters), uv, texel, dt_s, time_s; u_field.params4 = the material's
|
|
2145
|
+
SetMaterialParameterNumber slots; u_field.heal_per_s = the block's heal rate. Helpers:
|
|
2146
|
+
ori_field_stamp_press(ctx.world_pos) (x = press sum, y = rim band outside the presses;
|
|
2147
|
+
ori_field_stamp_sum = .x), ori_field_prev_load(texel) (toroidal neighbor read). The kernel
|
|
2148
|
+
owns all dynamics.
|
|
2149
|
+
Sample it anywhere: bind Ori.image.engine.fieldmap.<name> into a material texture slot
|
|
2150
|
+
(material { texN = } or SetMaterialParameterTexture; terrain materials: slots 0-12) and
|
|
2151
|
+
read it in any #shader: uv = ctx.world_pos.xz / window_m (sampler wraps;
|
|
2152
|
+
textureSampleLevel in @vertex; keep window_m as a shader const matching the block).
|
|
2153
|
+
Ground dents: @vertex ctx.world_pos.y += g * rim_m - r * depth_m; normal via
|
|
2154
|
+
ori_height_to_normal_w, crisp walls via ori_relief_march, a shadow side via
|
|
2155
|
+
ori_relief_shadow into out.orm.x. Debug: show the live map in a UI image
|
|
2156
|
+
(image = "ori.image.engine.fieldmap.<name>"). See <example_snow_trails>.
|
|
2157
|
+
Off on the Minimal quality tier (map freezes at zero - design looks to degrade).
|
|
2158
|
+
</field_maps>
|
|
2159
|
+
|
|
2089
2160
|
<procedural_generation_batches>
|
|
2090
2161
|
- InstanceBatch: thousands of decorative copies of one model as ONE display object (pebbles, rubble, grass tufts). Instances have no physics/logic/picking and are invisible to the editor - never clickable, movable, or saved there; the layout lives in this code (edit by index via SetInstance/RemoveInstance, or ClearInstances + re-add). Identical static meshes already render as one instanced draw either way - a batch saves per-object sim/load cost (spawn, rollback state, join checkpoints), not draw calls. Copies a human should hand-place or that need any interactivity: SpawnObject. Drifting petals/leaves/debris: #particles mesh components, not a batch. Animated look on scatter (sway/shimmer): vertex #shader on the model's material - never per-frame batch edits (SetBatchOrigin included), and batch handles reject Object.* calls like SetRenderOffset.
|
|
2091
2162
|
- Batches outlive their creator; only Destroy() frees a slot (128 live max). One batch per model kind, edited in place - don't create per region or per round.
|
|
@@ -2112,12 +2183,12 @@ for i in 0..2000 {
|
|
|
2112
2183
|
- Only one instance of each event_type+event_options is allowed per class. Duplicates are a compile error.
|
|
2113
2184
|
- Spawn timing: SpawnObject/SpawnAtTile/etc. queue OnPreSpawn/OnSpawned for next tick. The returned object is valid immediately (SpawnObject doesn't fail / doesn't return None), but its spawn events haven't run yet.
|
|
2114
2185
|
- OnPreSpawn runs once per instance, all before the first OnSpawned; spawn order across objects is unspecified and may defer - do inter-object setup in an explicit build step or a later tick.
|
|
2115
|
-
- GameCommand fires
|
|
2186
|
+
- GameCommand fires once per live instance of every class that declares it when a user sends a command text message (chat /cmd, or headless .order lines, which arrive as player 0). Event.Text is the raw command line, Event.Sender the sending player's object: `if Event.Sender != Self { return }` passes only in that player's own player-class handler - never guard a manager/HUD handler on it. Parse Text yourself (e.g. "build house 3 4").
|
|
2116
2187
|
- OnWorldReady fires once per load (again after RestartGame) when every scene object's OnSpawned has STARTED (run to its first yield), spilled load batches included. Poll IsWorldReady() for spawn/placement code that depends on procedurally built ground or rooms (terrain, BuildRoom) instead of Wait() timers; a handler that Wait()s mid-body may still be mid-flight at ready.
|
|
2117
2188
|
- OnPlayerLeft fires on the leaver's player object the moment IsConnected() flips false (the body stays ~90s for reconnect; OnDestroy only at grace expiry): clear SetHoverText labels / roster rows here. OnPlayerReconnected fires when the SAME body resumes within the grace; a post-grace rejoin is a fresh spawn (OnSpawned).
|
|
2118
2189
|
- LeftClickThisWorld/RightClickThisWorld fire only when no UI consumed the click; Event.ClickObject (None on miss)/ClickPosition/ClickGroundPosition are the click-frame hit - point-and-click worlds use these, not raw mouse events plus IsMouseOnUi guards.
|
|
2119
2190
|
- Event.MousePosition/MouseDownPosition are in the 1600x900 base screen space (same space as UI rects and WorldToScreenPosition); Event.MouseViewportSize is the real viewport for letterbox math.
|
|
2120
|
-
- Broadcast events without ByThisPlayer (LeftClickThisWorld, LeftMouseClick, ...) run once per instance of every class declaring them - with N players a player-class handler runs N times per click; guard non-idempotent handlers with `if Event.Presser != Self { return }` or use the ByThisPlayer variant.
|
|
2191
|
+
- Broadcast events without ByThisPlayer (LeftClickThisWorld, LeftMouseClick, GameCommand, ...) run once per instance of every class declaring them - with N players a player-class handler runs N times per click; guard non-idempotent handlers with `if Event.Presser != Self { return }` or use the ByThisPlayer variant.
|
|
2121
2192
|
</events>
|
|
2122
2193
|
<event_list>
|
|
2123
2194
|
event OnPreSpawn
|
|
@@ -2326,7 +2397,7 @@ event ActionInvokedByThisPlayer[Primary]
|
|
|
2326
2397
|
- Inventories/hotbars/chests: see <inventory> — item clauses + BindInventory give a fully engine-synced slot UI.
|
|
2327
2398
|
- Minimap: image = "ori.image.engine.minimap" = auto-refreshing top-down snapshot of the largest terrain across its XY bounds (terrain only). Blips = child frames placed via GetTerrainBoundsMin/Max; clicks map back to world XY with Event.ClickFraction.
|
|
2328
2399
|
- ui object tags for world description: screenCanvas/worldCanvas/frame/textLabel/button; elements nest
|
|
2329
|
-
- Element handles in script: scene-declared elements resolve as Scene.X; children of a SpawnCanvas canvas via canvas.FindChildUI("Name")
|
|
2400
|
+
- Element handles in script: scene-declared elements resolve as Scene.X; children of a SpawnCanvas canvas via canvas.FindChildUI("Name"); GetUiName() returns an element's own name (count copies: <Name>0..N-1).
|
|
2330
2401
|
- Spawning saved UI at runtime: canvas-root saved block -> SpawnCanvas(SavedObject.X, pos); element-root block (frame/textLabel/button...) -> SpawnChildUI(SavedObject.X, ParentUI). SpawnObject rejects both.
|
|
2331
2402
|
- worldCanvas = screenCanvas anchored to a world position (position = (x, y, z)): children use the same base-unit offsets around the projected anchor and keep constant on-screen size (nameplates, above-object markers); draws under screenCanvas; move the canvas object to follow things
|
|
2332
2403
|
|
|
@@ -2347,22 +2418,23 @@ event ActionInvokedByThisPlayer[Primary]
|
|
|
2347
2418
|
- frame = plain/absolute container (no auto-layout). Use it for screen-anchored HUD corners and for elements you reposition at runtime via SetUiOffset. A frame/grid without `size` inherits the parent's size. Position a child by ONE of: offset; anchor; insets.
|
|
2348
2419
|
- anchor = (x, y): pin the element to a spot on the parent (x=left|center|right, y=top|center|bottom). It also sets the pivot to match, so anchor=(center,center) centers, anchor=(center,bottom) makes a bottom bar, anchor=(right,bottom) a corner. `offset` still nudges, always in raw screen units (+x right, +y down) regardless of anchor - from a bottom anchor, inward is negative y. Decouple with pivot=(x,y) (or anchor_x/y + pivot_x/y) when the element's own pivot must differ from the parent attach point.
|
|
2349
2420
|
- inset = N | (x, y): pin all four edges so the child fills parent - inset (per-side: inset_left/right/top/bottom; icon in a button: inset=10). Differs from margin (child's outer spacing in a stack/grid) and padding (container's inner inset for ALL children); a button is not a container - inset the child, don't pad the button.
|
|
2350
|
-
- cover = screen (frame): rect = the player's FULL real window instead of the centered 1600x900 base box - backdrops/vignettes reach wide-monitor edges. Children anchor inside normally (a cover-wrapped HUD hugs true corners). Owned screen canvases only.
|
|
2421
|
+
- cover = screen (frame): rect = the player's FULL real window instead of the centered 1600x900 base box - backdrops/vignettes reach wide-monitor edges. Children anchor inside normally (a cover-wrapped HUD hugs true corners). Owned screen canvases only. A cover root is a plain frame: set color=#00000000 or it paints the screen black.
|
|
2351
2422
|
- visible = false starts any element hidden (there is no `hidden` field); SetVisible(true) reveals it - same flag.
|
|
2352
2423
|
- 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).
|
|
2353
2424
|
- 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.
|
|
2354
2425
|
- Scrollable container: clip_to_bounds=true + block_input=true, then SetUiScrollOffset(X, Y) shifts children by -offset (rect/clip stay; readback GetUiScrollOffsetX/Y). Wire OnMouseScroll (Event.ScrollDelta, positive = up) to adjust Y; wheel over blocking UI does not zoom. Authored start: scroll_offset = (x, y).
|
|
2355
|
-
- 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).
|
|
2426
|
+
- 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). Runtime: SetUiBorder(Width, Color) (width 0 clears) and SetUiCornerRadius(R); gradients and hover_* stay authoring-only.
|
|
2356
2427
|
- progressBar: color = fill, background_color = track; fill ratio via SetProgress(Value, MaxValue).
|
|
2357
|
-
- Animate UI: SetUiOffset/SetUiSize/SetUiOpacity(..., Secs[, Ease]) and SetUiColor(Color, Secs) glide to the target (Ease 0-5 = linear/in/out/in-out(default)/out-back/out-bounce; color always in-out); a same-property call replaces the glide, the instant call cancels it. Pop idiom: instant call, then the glide overload in the same frame - the glide starts FROM the instant value (snap-then-ease, no timer state). MoveUiToFront() = draw on top of siblings. Never hand-roll per-frame Lerp loops for UI.
|
|
2428
|
+
- Animate UI: SetUiOffset/SetUiSize/SetUiOpacity(..., Secs[, Ease]) and SetUiColor(Color, Secs) glide to the target (Ease 0-5 = linear/in/out/in-out(default)/out-back/out-bounce; color always in-out); a same-property call replaces the glide, the instant call cancels it. Pop idiom: instant call, then the glide overload in the same frame - the glide starts FROM the instant value (snap-then-ease, no timer state). MoveUiToFront() = draw on top of siblings. Never hand-roll per-frame Lerp loops for UI. Delay (4th/5th arg on the Ease forms) = seconds before the glide starts; a delayed glide queues behind a running one on the same property (fade in, then a delayed fade out = a banner); an instant set cancels both. SetUiColor has no Ease/Delay form.
|
|
2358
2429
|
- hover_color/hover_offset = (x, y)/hover_scale/hover_secs: viewer-local hover styling, applied instantly by the viewing client - the element (or nearest styled ancestor) shifts, scales around its center, tints toward hover_color and draws on top; sim and hit tests unchanged, touch inert. Gameplay logic still polls IsMouseOnUi.
|
|
2359
|
-
- rotation = deg (any element; SetUiRotation(Deg[, Secs[, Ease]]), GetUiRotation): spins the element AND its subtree around its center, +CW - card fans, dials, compasses. Hit-testing follows; clipping stays the screen-AABB scissor.
|
|
2430
|
+
- rotation = deg (any element; SetUiRotation(Deg[, Secs[, Ease[, Delay]]]), GetUiRotation): spins the element AND its subtree around its center, +CW - card fans, dials, compasses. Hit-testing follows; clipping stays the screen-AABB scissor.
|
|
2360
2431
|
- count = N (2..=256, canvas child elements): parse-time repeat - the element + its subtree expand into N copies <Name>0..<Name>N-1 (frame Slot { count = 9 } -> Slot0..Slot8). Use for marker/gauge/slot pools; copies stack until positioned via SetUiOffset; resolve via Panel.FindChildUI("Slot" + i). Counts nest. An attached class (frame Card : CardSlot { count = 10 }) instantiates per copy - each copy gets its own class instance.
|
|
2361
2432
|
- 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.
|
|
2362
2433
|
- image sheet = (cols, rows) + optional fps = N (default 8): the image is a sprite-sheet frame grid, auto-playing row-major at fps (display-side). SetUiSheetRange(A, B) loops frames A..B inclusive (idle/walk stances); SetUiSheetOnce(A, B) plays A..B once then returns to the standing loop/hold (attacks, hits — no Wait bookkeeping); SetUiSheetFrame(I) holds frame I. Frames 0-based; excludes nine_slice + corner_radius. flip_x = true mirrors the drawn image horizontally (face left without regenerating art).
|
|
2363
|
-
- frame/vStack/hStack/grid also accept image = "image.*" as a background fill (drawn over color/border, under children; nine_slice applies). material = "M" runs a custom #shader on the element - animated glow/shine/dissolve (contract: shader_dsl skill, UI section).
|
|
2434
|
+
- frame/vStack/hStack/grid also accept image = "image.*" as a background fill (drawn over color/border, under children; nine_slice applies). material = "M" runs a custom #shader on the element - animated glow/shine/dissolve (contract: shader_dsl skill, UI section). image also accepts material = "M" (the art becomes tex0); sheet/nine_slice/flip_x are ignored there.
|
|
2435
|
+
- image = "baked.<Name>.color" draws a #texture bake or a #svg drawing as UI art (same form for item icons; a #svg keeps its viewBox aspect - size the element to match); texture.<Name>.color is the #particles form and draws nothing here.
|
|
2364
2436
|
- 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.
|
|
2365
|
-
- UI text covers Latin-1 plus common symbol blocks (punctuation – — … •, arrows, geometric shapes ◆●▶, misc symbols ★♦⚙, dingbats ✦✔) in every font; other scripts (Thai, CJK, Cyrillic) need a font that covers them (font=/SetFont/SetDefaultFont). Characters a font lacks draw as a box and fail validation; emoji never render; Thai marks stack approximately (unshaped). Icons still look best as image assets.
|
|
2437
|
+
- UI text covers Latin-1 plus common symbol blocks (punctuation – — … •, arrows, geometric shapes ◆●▶, misc symbols ★♦⚙, dingbats ✦✔) in every font; other scripts (Thai, CJK, Cyrillic) need a font that covers them (font=/SetFont/SetDefaultFont). Characters a font lacks draw as a box and fail validation; emoji never render; Thai marks stack approximately (unshaped). Icons still look best as image assets or #svg drawings.
|
|
2366
2438
|
- 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).
|
|
2367
2439
|
- Colors accept optional 8-digit hex alpha (e.g. #3A3A3AFF) in addition to #RRGGBB and (r,g,b).
|
|
2368
2440
|
- Two-stop gradients: gradient(colorA, colorB[, angle_deg]) (linear; angle 0 = top->bottom, 90 = left->right) or radial(inner, outer) (center->corners). ONLY on frame/vStack/hStack/grid `color` (fill) and on `border_color` of frame-like UI — NOT on button/textLabel colors (wrap the button in a gradient frame instead).
|
|
@@ -2380,7 +2452,7 @@ event ActionInvokedByThisPlayer[Primary]
|
|
|
2380
2452
|
<inventory>
|
|
2381
2453
|
- Weave2-only engine inventory system. ALWAYS prefer it over hand-rolled slot vars/slot buttons for hotbars, backpacks, chests, sell-targets.
|
|
2382
2454
|
- Define item types as top-level clauses (placeable like `object`): item hoe { name="Hoe" tip="Till soil." icon="image.<owner>.<name>" tint=(0.7,0.7,0.9) stack=99 value=2 }
|
|
2383
|
-
All properties optional; defaults: name = declared name, tip "", no icon, tint white, stack 1, value 0. icon is a QUOTED image url string. Duplicate item names = load error.
|
|
2455
|
+
All properties optional; defaults: name = declared name, tip "", no icon, tint white, stack 1, value 0. icon is a QUOTED image url string (`image.*`, `alias.image.*`, or a #texture bake `baked.<Texture>.color`; `texture.*` is the particle form and draws nothing here). Duplicate item names = load error.
|
|
2384
2456
|
- Item.<declname> is a compile-time item handle (opaque Object; unknown name = link error). Read def properties anywhere: ItemName(i)/ItemTip(i) -> Text, ItemIcon(i) -> Object, ItemTint(i) -> Vector, ItemStack(i)/ItemValue(i) -> Number.
|
|
2385
2457
|
- var inv = CreateInventory(Slots) (1..128): deterministic container owned by the calling object (owner despawn frees it). Make inventories per player (player OnSpawned). Methods on the handle:
|
|
2386
2458
|
inv.AddItem(item, n) -> overflow Number (fills existing stacks first; 0 = all fit) | inv.RemoveItem(item, n) -> Bool (exact-or-nothing) | inv.CountOf(item)
|
|
@@ -2427,19 +2499,19 @@ event InventoryDropOnWorld {
|
|
|
2427
2499
|
- use the function PlayAnimationOnRepeat to loop animations like run forever
|
|
2428
2500
|
- PlayAnimationOnRepeat(Ori.anim.default.goblin.run)
|
|
2429
2501
|
- PlayAnimation(Ori.anim.default.goblin.attack)
|
|
2430
|
-
- a marketplace model's own clips: Ori.anim.<creator>.<model>.<clip> (e.g. Ori.anim.vk7t7mestuxl_5378.murlocfishgi.attack); clip names are exact-case; a world `#clip Name on model.<creator>.<model>` block (canonical bone names) adds or shadows one for this world
|
|
2502
|
+
- a marketplace model's own clips: Ori.anim.<creator>.<model>.<clip> (e.g. Ori.anim.vk7t7mestuxl_5378.murlocfishgi.attack); clip names are exact-case; a world `#clip Name on model.<creator>.<model>` block (canonical bone names: Root, Spine, Torso, Neck, Head, Scapula/UpperArm/Forearm/Hand, Thigh/Shin/Foot/Toe with L/R suffixes, e.g. UpperArmR) adds or shadows one for this world
|
|
2431
2503
|
- Timing a clip to a moment (hand/bat/racket meeting a ball): call PlayAnimationHittingContactIn(Anim, ContactPercent, SecondsUntilContact) every frame - it returns false and does nothing while still too early, then fires rate-scaled so ContactPercent lands exactly on contact, and refuses to restart a clip it already started (no 'started' guard var needed). GetAnimationLeadSeconds tells how early it can fire. Never derive a trigger delay from GetAnimationDuration by hand.
|
|
2432
2504
|
|
|
2433
|
-
-
|
|
2505
|
+
- Compatible humanoid rigs can play `Ori.anim.canon.Name` and mapped humanoid clips through display-only retargeting. Library imports check the target rig and pin the selected motion.
|
|
2434
2506
|
- `#clip Name on model.<creator>.<name>` registers Ori.anim.<creator>.<name>.Name for that store model; canon/model clip bodies are authored on the canonical template rig's bones — clips for a richer custom rig belong on its rigged #mesh
|
|
2435
2507
|
|
|
2436
2508
|
- Autoplay Animations are turned on by default for mesh-backed objects (players, crowds, physics/world objects) whose mesh has a default `.idle` animation asset (anim.<mesh>.idle)
|
|
2437
|
-
- the clip is picked automatically: .idle when still, .run when moving (falling back to .walk), .jumpHover when airborne; camera-locked players also use .runBack/.runLeft/.runRight by movement direction
|
|
2509
|
+
- the clip is picked automatically: .idle when still, .run when moving (falling back to .walk), .jumpHover when airborne, .sit when seated (SeatPlayer; a model's own .sit beats the built-in canonical sit - the seat point is the contact surface and the sit clip's root offset lifts the hips a pelvis height above it, canon +5cm scaled per rig; author own sit clips with offset: (0, 0, 5)); camera-locked players also use .runBack/.runLeft/.runRight by movement direction
|
|
2438
2510
|
- using PlayAnimation will stop these animations until the animation is finished
|
|
2439
2511
|
- DisableAutoMoveAnimations() to turn this off - durable (survives SetModel and late-downloading market clips); a script-posed prop whose model ships humanoid clips (market props can) also needs one StopAnimation() to drop an already-applied clip
|
|
2440
|
-
- Rigged humanoid models (store characters or DSL rigs) that ship no `.idle` clip idle/walk/run (jumpHover airborne) with the built-in canonical clips automatically (display-only retarget); models with their own clips always use them
|
|
2512
|
+
- Rigged humanoid models (store characters or DSL rigs) that ship no `.idle` clip idle/walk/run/sit (jumpHover airborne) with the built-in canonical clips automatically (display-only retarget); models with their own clips always use them
|
|
2441
2513
|
- Custom/procedural character: author ONE rigged #mesh (bone(...) joints + optional idle/walk #clips, standard bone names — see the humanoid example in the mesh skill) and SetModel it; auto move-animations then drive it. AttachTo assembly is for props/machines (turret, arm -> gun), not walking bodies
|
|
2442
|
-
- Procedural bone layer on any bone(...) rig (display-only, max 16 bones): SetBoneRotation(Mix) replaces/blends a joint over the playing clip, BoneLookAt aims one at a world point, PlayUpperBodyAnimation layers a clip over the base walk. Rotations act in each bone's LOCAL REST frame: imported-rig joint axes rarely match world axes (probe one bone with a small test rotation), and mirrored L/R bones usually need SAME-signed values for opposite swings. Head-track + breathe over auto-walk:
|
|
2514
|
+
- Procedural bone layer on any bone(...) rig (display-only, max 16 bones): SetBoneRotation(Mix) replaces/blends a joint over the playing clip, BoneLookAt aims one at a world point, PlayUpperBodyAnimation layers a clip over the base walk. Rotations act in each bone's LOCAL REST frame: imported-rig joint axes rarely match world axes (probe one bone with a small test rotation), and mirrored L/R bones usually need SAME-signed values for opposite swings (SetBoneRotation on imported rigs only; canonical #clip keys mirror with OPPOSITE X/Z, same Y). Head-track + breathe over auto-walk:
|
|
2443
2515
|
forever {
|
|
2444
2516
|
BoneLookAt("Head", Friend.GetCenterPosition(), 55, 240)
|
|
2445
2517
|
SetBoneRotationMix("Torso", Vector(0, 2, 0), 1, 0.7, 1) // additive lean; alternate targets on a timer to breathe
|
|
@@ -3418,7 +3490,7 @@ event OnSpawned {
|
|
|
3418
3490
|
SetFogEndDistance(2800)
|
|
3419
3491
|
SetSunTilt(33)
|
|
3420
3492
|
SetSunRotation(35)
|
|
3421
|
-
SetWaterEnabled(true
|
|
3493
|
+
SetWaterEnabled(true)
|
|
3422
3494
|
SetWaterWaves(5, 800, 0.3, 0, 100)
|
|
3423
3495
|
}
|
|
3424
3496
|
#end
|
|
@@ -3729,6 +3801,232 @@ saved StyledHud {
|
|
|
3729
3801
|
</example_saved_block_font>
|
|
3730
3802
|
|
|
3731
3803
|
|
|
3804
|
+
<example_snow_trails>
|
|
3805
|
+
// snow_trails: a snowy mountain where walking presses real boot prints into the snow -
|
|
3806
|
+
// the #fieldmap dynamic-canvas primitive end to end (see <field_maps>).
|
|
3807
|
+
// Pattern notes:
|
|
3808
|
+
// - #fieldmap SnowTrails runs the DEFAULT kernel (no shader needed): FieldStampBoot presses
|
|
3809
|
+
// an oriented heel+toe print with a sole tread into r once per stride, the snow it pushed
|
|
3810
|
+
// aside piles up in g just outside the outline, walls settle for a few seconds then hold,
|
|
3811
|
+
// heal_seconds refills them like fresh snowfall. Prints want <= 2.5 cm per texel for the
|
|
3812
|
+
// tread to read: 1024 texels over a 24 m window (2.3 cm). The other pattern - a per-frame
|
|
3813
|
+
// round FieldStamp trench - wants a 100 m window instead.
|
|
3814
|
+
// Custom dynamics (ripples, spread): SetFieldMaterial + fork read_shader
|
|
3815
|
+
// Ori.shader.builtin.fieldmap_default.
|
|
3816
|
+
// - The ground samples the map as a plain texture: material tex3 =
|
|
3817
|
+
// "Ori.image.engine.fieldmap.snowtrails", uv = world_xz_m / WINDOW_M (keep WINDOW_M as
|
|
3818
|
+
// a shader const matching the block; the material sampler wraps, matching the map's
|
|
3819
|
+
// toroidal window). @vertex sinks the dent and raises the rim; the fragment walks the eye
|
|
3820
|
+
// ray through the print (ori_relief_march: near-camera terrain quads are 12.5 cm and a
|
|
3821
|
+
// print is 28 cm, so the fragment still has to carry the wall), re-derives the normal from
|
|
3822
|
+
// both channels (ori_height_to_normal_w), shades the floor beside the sun-facing wall
|
|
3823
|
+
// (ori_relief_shadow into occlusion) and tints the compacted snow - lightly: snow floors
|
|
3824
|
+
// stay bright (the engine snow class floors its ambient occlusion for the same reason).
|
|
3825
|
+
// - Snow clods: a #mesh lump as a "mesh" particle component with groundBounce, a burst of a
|
|
3826
|
+
// few per stride kicked off the print rim. A continuous furrow (wading) is one
|
|
3827
|
+
// FieldStampCapsule per moving frame from last frame's position instead of boot prints.
|
|
3828
|
+
// - Lighting recipe for snow: a warm low sun with a blue sky fill - snow shadows are lit by
|
|
3829
|
+
// the sky, so they read blue against the warm sunlit side.
|
|
3830
|
+
// - Debug trick: show the live map in a UI image (image = "ori.image.engine.fieldmap.snowtrails").
|
|
3831
|
+
|
|
3832
|
+
#terrain SnowMountain
|
|
3833
|
+
mound_height_m = 260
|
|
3834
|
+
mound_size_m = 420
|
|
3835
|
+
#end
|
|
3836
|
+
|
|
3837
|
+
#fieldmap SnowTrails
|
|
3838
|
+
resolution = 1024
|
|
3839
|
+
window_m = 24
|
|
3840
|
+
heal_seconds = 300
|
|
3841
|
+
#end
|
|
3842
|
+
|
|
3843
|
+
#shader SnowGround
|
|
3844
|
+
@module {
|
|
3845
|
+
const WINDOW_M: f32 = 24.0; // = #fieldmap window_m
|
|
3846
|
+
const TEXEL_UV: f32 = 1.0 / 1024.0; // = 1 / #fieldmap resolution
|
|
3847
|
+
const TRAIL_DEPTH_M: f32 = 0.12; // print depth (map r = 1)
|
|
3848
|
+
const RIM_M: f32 = 0.03; // pushed-up rim height (map g = 1)
|
|
3849
|
+
// Chewed snow: world noise breaks the map values up so print edges and rims read as
|
|
3850
|
+
// churned crystals, not clean cuts. One fn keeps VS and FS in exact agreement.
|
|
3851
|
+
fn chew(wp: vec2<f32>) -> f32 {
|
|
3852
|
+
return 0.8 + 0.4 * ori_fbm2(wp.x * 5.0, wp.y * 5.0, 2, 21u);
|
|
3853
|
+
}
|
|
3854
|
+
// Print relief in meters: the dent (r, eased so lip and floor round off like packed
|
|
3855
|
+
// snow) sinks, the rim (g) rises and crumbles a little harder.
|
|
3856
|
+
fn relief_at(duv: vec2<f32>, wp: vec2<f32>) -> f32 {
|
|
3857
|
+
let m = textureSampleLevel(tex3, tex_sampler, duv, 0.0);
|
|
3858
|
+
let c = chew(wp);
|
|
3859
|
+
let sink = m.r * m.r * (3.0 - 2.0 * m.r);
|
|
3860
|
+
return m.g * RIM_M * (0.75 + 0.5 * c) - sink * TRAIL_DEPTH_M * c;
|
|
3861
|
+
}
|
|
3862
|
+
// Untouched-snow relief: broad wind sastrugi + fine ripple, shading-only (finite
|
|
3863
|
+
// differences of this feed the fragment normal - vast flat white reads CG-sterile).
|
|
3864
|
+
fn snow_h(wp: vec2<f32>) -> f32 {
|
|
3865
|
+
return ori_fbm2(wp.x * 0.055, wp.y * 0.055, 3, 5u) * 2.2
|
|
3866
|
+
+ ori_fbm2(wp.x * 0.85, wp.y * 0.85, 2, 9u) * 0.16;
|
|
3867
|
+
}
|
|
3868
|
+
}
|
|
3869
|
+
@vertex {
|
|
3870
|
+
ctx.world_pos.y += relief_at(ctx.world_pos.xz / WINDOW_M, ctx.world_pos.xz);
|
|
3871
|
+
}
|
|
3872
|
+
let vdir = normalize(u_camera.camera_position - ctx.world_pos);
|
|
3873
|
+
// Parallax: walk the eye ray through the print (8 steps + bisection) so walls keep their
|
|
3874
|
+
// depth between terrain vertices; the map stores depth, so the sample slides away from the eye.
|
|
3875
|
+
let uv0 = ctx.world_pos.xz / WINDOW_M;
|
|
3876
|
+
let ray = vdir.xz / max(vdir.y, 0.25) / WINDOW_M;
|
|
3877
|
+
let duv = ori_relief_march(tex3, tex_sampler, uv0, ray, TRAIL_DEPTH_M, 8);
|
|
3878
|
+
let m = textureSampleLevel(tex3, tex_sampler, duv, 0.0);
|
|
3879
|
+
let trail = m.r * chew(ctx.world_pos.xz);
|
|
3880
|
+
let rim = m.g;
|
|
3881
|
+
// Print relief before the color: dent + rim normal in one weighted call (r = depth, g = rim)
|
|
3882
|
+
// and how steep the wall is here - walls and tread ridges are where a print reads as deep.
|
|
3883
|
+
let dent_n = ori_height_to_normal_w(tex3, tex_sampler, duv, TEXEL_UV, WINDOW_M / 1024.0,
|
|
3884
|
+
vec4<f32>(-TRAIL_DEPTH_M, RIM_M, 0.0, 0.0));
|
|
3885
|
+
let wall = clamp(length(dent_n.xz) * 1.6, 0.0, 1.0);
|
|
3886
|
+
// Horizon shadow toward the sun: the sun-facing wall shades the floor beside it. Carried in
|
|
3887
|
+
// occlusion (the engine snow class takes half of it out of the direct sun as well).
|
|
3888
|
+
let sun = u_camera.sun_direction.xyz;
|
|
3889
|
+
let sun_uv = -sun.xz / max(-sun.y, 0.05) / WINDOW_M;
|
|
3890
|
+
let lit = ori_relief_shadow(tex3, tex_sampler, duv, sun_uv, TRAIL_DEPTH_M, 6);
|
|
3891
|
+
// Bright, faintly blue snow with fine grain; pressed prints read as compacted, icy blue.
|
|
3892
|
+
let grain = ori_fbm2(ctx.world_pos.x * 3.0, ctx.world_pos.z * 3.0, 3, 11u);
|
|
3893
|
+
var snow = vec3<f32>(0.90, 0.93, 0.98) * (0.92 + grain * 0.1);
|
|
3894
|
+
// Compacted snow stays bright: snow scatters light back into its own cavities, so the floor
|
|
3895
|
+
// only cools a little toward icy blue. Shape comes from the normal and the rim, not from albedo.
|
|
3896
|
+
snow = mix(snow, vec3<f32>(0.72, 0.80, 0.94), trail * 0.45);
|
|
3897
|
+
snow *= 1.0 - wall * 0.03 * trail;
|
|
3898
|
+
// The rim is loose pushed powder: a touch brighter and warmer where it catches the sun.
|
|
3899
|
+
snow += vec3<f32>(0.06, 0.055, 0.04) * rim;
|
|
3900
|
+
// (No hand-rolled sparkle: `lighting = "snow"` on the material brings engine wrap
|
|
3901
|
+
// lighting, backscatter, grain and ice glints - albedo/normal/roughness stay this shader's job.)
|
|
3902
|
+
out.base_color = vec4<f32>(snow, 1.0);
|
|
3903
|
+
// Normals: dune/ripple relief on open snow, the print dent + rim, and crumbled-chunk jitter
|
|
3904
|
+
// on the rim, all as finite-difference perturbations of the terrain normal.
|
|
3905
|
+
let e = 0.35;
|
|
3906
|
+
let shx = snow_h(ctx.world_pos.xz + vec2<f32>(e, 0.0)) - snow_h(ctx.world_pos.xz - vec2<f32>(e, 0.0));
|
|
3907
|
+
let shz = snow_h(ctx.world_pos.xz + vec2<f32>(0.0, e)) - snow_h(ctx.world_pos.xz - vec2<f32>(0.0, e));
|
|
3908
|
+
let chunk = vec2<f32>(ori_fbm2(ctx.world_pos.x * 9.0, ctx.world_pos.z * 9.0, 2, 31u),
|
|
3909
|
+
ori_fbm2(ctx.world_pos.x * 9.0 + 9.0, ctx.world_pos.z * 9.0, 2, 37u)) - vec2<f32>(0.5);
|
|
3910
|
+
out.world_normal = normalize(ctx.normal
|
|
3911
|
+
+ (dent_n - vec3<f32>(0.0, 1.0, 0.0)) * 1.3
|
|
3912
|
+
+ vec3<f32>(chunk.x, 0.0, chunk.y) * rim * 0.3
|
|
3913
|
+
+ vec3<f32>(-shx, 0.0, -shz) * (0.30 * (1.0 - trail)));
|
|
3914
|
+
// Grazing sheen: fresh powder throws a soft low-sun sparkle band at glancing angles.
|
|
3915
|
+
let fres = pow(1.0 - clamp(dot(out.world_normal, vdir), 0.0, 1.0), 3.0);
|
|
3916
|
+
let rough = mix(mix(0.55, 0.30, fres * (1.0 - trail)), 0.22, trail);
|
|
3917
|
+
// Occlusion: a light touch on the floor (snow refills its cavities with scattered light),
|
|
3918
|
+
// the shadow side loses some sun; the engine snow class takes part of it out of direct light.
|
|
3919
|
+
out.orm = vec4<f32>(clamp(1.0 - trail * 0.12, 0.0, 1.0) * mix(0.85, 1.0, lit), rough, 0.0, 0.0);
|
|
3920
|
+
#end
|
|
3921
|
+
|
|
3922
|
+
material SnowGroundMat {
|
|
3923
|
+
shader = "SnowGround"
|
|
3924
|
+
tex3 = "Ori.image.engine.fieldmap.snowtrails"
|
|
3925
|
+
lighting = "snow" // engine snow response: wrapped terminator, backscatter, grain, glints
|
|
3926
|
+
}
|
|
3927
|
+
|
|
3928
|
+
// Snow clods: a small lump (3 cm, "Snow" material) thrown as lit mesh particles that bounce
|
|
3929
|
+
// and settle on the ground - a few per stride off the print rim.
|
|
3930
|
+
#mesh SnowClod
|
|
3931
|
+
let base = scale(sphere(r: 3, segments: 6, material: "Snow"), (1.3, 0.8, 1.0));
|
|
3932
|
+
out.geo = displace(base, amount: 1.2, seed: 7);
|
|
3933
|
+
#end
|
|
3934
|
+
|
|
3935
|
+
#particles SnowClods
|
|
3936
|
+
[
|
|
3937
|
+
{ "type": "mesh", "particleMeshName": "mesh.SnowClod", "boundingBoxSize": [1.6, 1.6, 1.0], "boundingBoxCenter": [0, 0, 0.3], "burstParticleCount": 5, "spawnRate": 0, "duration": 0.1, "isLooping": 0, "lifeTimeRange": [1.2, 2.0], "emitterShapeType": "sphere", "shapeStyle": "volume", "shapeInOut": "out", "radius": 0.08, "speedRange": [0.6, 1.6], "spreadAngle": [180, 60], "sizeConstant": 0.05, "opacitySequence": [[0, 1.0], [0.8, 1.0], [1, 0.0]], "accelerationVector": [0, 0, -9.8], "drag": 0.0, "groundBounce": 0.25, "tumbleSpeedRange": [120, 480] }
|
|
3938
|
+
]
|
|
3939
|
+
#end
|
|
3940
|
+
|
|
3941
|
+
#class WorldGen
|
|
3942
|
+
event OnSpawned {
|
|
3943
|
+
// 100cm tiles: finest terrain quads ~25cm, so print rims displace cleanly.
|
|
3944
|
+
var terrain = SpawnTerrainRecipe(100, Origin())
|
|
3945
|
+
terrain.SetTerrainMaterial(Material.SnowGroundMat)
|
|
3946
|
+
terrain.SetTerrainGrassVisible(false) // bare snow - no meadow over the slopes
|
|
3947
|
+
// Snow lighting: a warm low sun (print walls and rims throw the shadows that sell the
|
|
3948
|
+
// relief) against a blue sky fill - snow shadows are sky-lit, so they read blue.
|
|
3949
|
+
SetSunTilt(18)
|
|
3950
|
+
SetSunRotation(120)
|
|
3951
|
+
SetSunColor(1.0, 0.94, 0.86)
|
|
3952
|
+
SetSunIntensity(3.6)
|
|
3953
|
+
SetSkyLightIntensity(2.0)
|
|
3954
|
+
SetSkyLightColor(Vector(0.80, 0.88, 1.0))
|
|
3955
|
+
SetFogEndDistance(2600)
|
|
3956
|
+
SetCameraFarDistanceM(3000)
|
|
3957
|
+
}
|
|
3958
|
+
#end
|
|
3959
|
+
|
|
3960
|
+
#class player
|
|
3961
|
+
event OnSpawned {
|
|
3962
|
+
// Spawn on the highest crest within ~50m so the slide lasts.
|
|
3963
|
+
var bestX = 0
|
|
3964
|
+
var bestY = 0
|
|
3965
|
+
var bestH = GroundHeightAtXY(0, 0)
|
|
3966
|
+
var probes: List<Number> = []
|
|
3967
|
+
probes.Add(5000); probes.Add(0); probes.Add(0 - 5000); probes.Add(0)
|
|
3968
|
+
probes.Add(0); probes.Add(5000); probes.Add(0); probes.Add(0 - 5000)
|
|
3969
|
+
probes.Add(3500); probes.Add(3500); probes.Add(0 - 3500); probes.Add(3500)
|
|
3970
|
+
probes.Add(3500); probes.Add(0 - 3500); probes.Add(0 - 3500); probes.Add(0 - 3500)
|
|
3971
|
+
for i in 0..8 {
|
|
3972
|
+
var x = probes.Get(i * 2)
|
|
3973
|
+
var y = probes.Get(i * 2 + 1)
|
|
3974
|
+
var h = GroundHeightAtXY(x, y)
|
|
3975
|
+
if h > bestH {
|
|
3976
|
+
bestH = h
|
|
3977
|
+
bestX = x
|
|
3978
|
+
bestY = y
|
|
3979
|
+
}
|
|
3980
|
+
}
|
|
3981
|
+
TeleportTo(Position(bestX, bestY, bestH + 200))
|
|
3982
|
+
var moving = false
|
|
3983
|
+
var stepDist = 0
|
|
3984
|
+
var lastPos = GetPosition()
|
|
3985
|
+
var side = 1
|
|
3986
|
+
forever {
|
|
3987
|
+
// Plain camera-relative walking; one print per 62 cm stride, alternating feet, offset
|
|
3988
|
+
// 11 cm to each side. No autonomous steering of any kind - the character does only
|
|
3989
|
+
// what the player does.
|
|
3990
|
+
var steer = GetMoveVectorCamera()
|
|
3991
|
+
if steer.Length() > 0.1 {
|
|
3992
|
+
MoveInDirectionContinuouslyFacing(steer, 700)
|
|
3993
|
+
var p = GetPosition()
|
|
3994
|
+
stepDist = stepDist + p.DistanceTo(lastPos)
|
|
3995
|
+
lastPos = p
|
|
3996
|
+
if stepDist >= 62 {
|
|
3997
|
+
stepDist = 0
|
|
3998
|
+
side = 0 - side
|
|
3999
|
+
var r = GetDirectionRight()
|
|
4000
|
+
var foot = Position(p.X + r.X * 11 * side, p.Y + r.Y * 11 * side, p.Z)
|
|
4001
|
+
FieldStampBoot("SnowTrails", foot, GetFacingDirection(), 28, 1, side)
|
|
4002
|
+
// A few clods kicked off the rim of the print that just landed.
|
|
4003
|
+
SpawnEffectWithAutoDestroy(Ori.effect.SnowClods, Position(foot.X, foot.Y, foot.Z + 4))
|
|
4004
|
+
}
|
|
4005
|
+
if not moving {
|
|
4006
|
+
moving = true
|
|
4007
|
+
// Feet sink a little into the powder while wading (display-only).
|
|
4008
|
+
SetRenderOffset(Vector(0, 0, 0 - 6), Vector(0, 0, 0), 1)
|
|
4009
|
+
}
|
|
4010
|
+
} else {
|
|
4011
|
+
if moving {
|
|
4012
|
+
moving = false
|
|
4013
|
+
SetRenderOffset(Vector(0, 0, 0), Vector(0, 0, 0), 1)
|
|
4014
|
+
}
|
|
4015
|
+
}
|
|
4016
|
+
}
|
|
4017
|
+
}
|
|
4018
|
+
event ActionDownByThisPlayer[Jump] {
|
|
4019
|
+
if IsOnGround() {
|
|
4020
|
+
Jump(1100)
|
|
4021
|
+
}
|
|
4022
|
+
}
|
|
4023
|
+
#end
|
|
4024
|
+
|
|
4025
|
+
display WorldGenObj : WorldGen { visible = false }
|
|
4026
|
+
|
|
4027
|
+
</example_snow_trails>
|
|
4028
|
+
|
|
4029
|
+
|
|
3732
4030
|
<example_stardew_valley>
|
|
3733
4031
|
// Stardew-like Farming Prototype: engine inventory (item clauses + BindInventory hotbar with
|
|
3734
4032
|
// engine-side drag/swap), tools, crops, resources, drops, selling, energy/day cycle.
|
|
@@ -4519,286 +4817,286 @@ Drag items out of slots to sell or drop them"""
|
|
|
4519
4817
|
|
|
4520
4818
|
|
|
4521
4819
|
<example_texture_dsl_desert_forest_demo>
|
|
4522
|
-
// Procedural texture DSL demo: semi-realistic desert wall + forest ground.
|
|
4523
|
-
|
|
4524
|
-
#texture DesertWall
|
|
4525
|
-
tile_m = 2.0;
|
|
4526
|
-
let tile = pattern.tile(uv * vec2(6.0, 4.0), mortar: 0.065, seed: 3);
|
|
4527
|
-
let warp = noise.vec2(uv * 3.0, seed: 11, period: 3) * 0.18;
|
|
4528
|
-
let cells = pattern.voronoi(uv * vec2(12.0, 8.0) + warp, jitter: 0.82, seed: 7, period: vec2(12.0, 8.0));
|
|
4529
|
-
let cracks = stroke(cells.edge, width: 0.055, aa: 0.012);
|
|
4530
|
-
let grain = noise.ridged(uv * 72.0, octaves: 3, seed: 19, period: 72);
|
|
4531
|
-
let broad = noise.fbm(uv * vec2(6.0, 4.0), octaves: 4, seed: 23, period: vec2(6.0, 4.0));
|
|
4532
|
-
let chips = smoothstep(0.65, 0.95, noise.ridged(uv * 36.0, octaves: 3, seed: 29, period: 36)) * (1.0 - smoothstep(0.02, 0.18, tile.edge));
|
|
4533
|
-
let dust = levels(noise.fbm(uv * 5.0 + warp, octaves: 4, seed: 31, period: 5), black: 0.28, white: 0.86, gamma: 1.35);
|
|
4534
|
-
let block = contrast(sat(broad * 0.65 + grain * 0.25 + rand(tile.id, seed: 5) * 0.10), amount: 1.25, pivot: 0.45);
|
|
4535
|
-
let height = mix(-0.045, 0.11 + grain * 0.018 - chips * 0.06, tile.mask) - cracks * 0.07;
|
|
4536
|
-
let stone = ramp(block, [0.0: color("#7d664a"), 0.35: color("#a8875a"), 0.75: color("#c9a66f"), 1.0: color("#ead19c")]);
|
|
4537
|
-
let mortar = color("#75614b") * mix(0.82, 1.08, broad);
|
|
4538
|
-
out.color = mix(mortar, stone, tile.mask) * mix(0.82, 1.06, dust) - cracks * 0.12;
|
|
4539
|
-
out.normal = normal_from_height(height, strength: 1.05);
|
|
4540
|
-
out.orm = orm(occlusion: ao_from_height(height, radius: 2.5), roughness: mix(0.94, 0.82, tile.mask) + dust * 0.03, metallic: 0.0);
|
|
4541
|
-
#end
|
|
4542
|
-
|
|
4543
|
-
#texture ForestGround
|
|
4544
|
-
tile_m = 3.0;
|
|
4545
|
-
let p = uv * vec2(8.0, 8.0);
|
|
4546
|
-
let warp = noise.vec2(uv * 2.0, seed: 41, period: 2) * 0.25;
|
|
4547
|
-
let soil = levels(noise.fbm(p + warp, octaves: 4, seed: 43, period: vec2(8.0, 8.0)), black: 0.18, white: 0.88, gamma: 1.2);
|
|
4548
|
-
let stones = pattern.voronoi(uv * vec2(7.0, 7.0) + warp * 0.6, jitter: 0.78, seed: 47, period: vec2(7.0, 7.0));
|
|
4549
|
-
let stone_shape = 1.0 - smoothstep(0.34, 0.47, stones.dist + noise.fbm(stones.local * 4.0, octaves: 2, seed: 53) * 0.08);
|
|
4550
|
-
let cell_guard = smoothstep(0.025, 0.07, stones.edge);
|
|
4551
|
-
let stone_mask = stone_shape * cell_guard;
|
|
4552
|
-
let moss = levels(noise.fbm(uv * vec2(5.0, 5.0) + warp * 1.4, octaves: 4, seed: 59, period: 5) + (1.0 - stone_mask) * 0.25, black: 0.44, white: 0.92, gamma: 0.85);
|
|
4553
|
-
let wet = contrast(noise.fbm(uv * 3.0 + warp, octaves: 3, seed: 61, period: 3), amount: 1.55, pivot: 0.48);
|
|
4554
|
-
let height = soil * 0.045 + moss * 0.035 + sat(1.0 - stones.dist * 2.1) * stone_mask * 0.10 - (1.0 - soil) * 0.025;
|
|
4555
|
-
let soil_color = ramp(soil, [0.0: color("#211912"), 0.45: color("#3b2b1d"), 1.0: color("#6c5538")]);
|
|
4556
|
-
let moss_color = ramp(moss, [0.0: color("#26351d"), 0.55: color("#43622d"), 1.0: color("#7f9b55")]);
|
|
4557
|
-
let stone_color = ramp(rand(stones.id, seed: 67), [0.0: color("#3e4039"), 0.5: color("#68675b"), 1.0: color("#918a78")]);
|
|
4558
|
-
out.color = mix(mix(soil_color, moss_color, moss * 0.82), stone_color, stone_mask * 0.75);
|
|
4559
|
-
out.normal = normal_from_height(height, strength: 0.95);
|
|
4560
|
-
out.orm = orm(occlusion: ao_from_height(height, radius: 2.0), roughness: mix(0.92, 0.58, wet), metallic: 0.0);
|
|
4561
|
-
#end
|
|
4562
|
-
|
|
4563
|
-
object desert_wall {
|
|
4564
|
-
model = "cube"
|
|
4565
|
-
material = "DesertWall"
|
|
4566
|
-
position = (0, -240, 160)
|
|
4567
|
-
size = (700, 40, 320)
|
|
4568
|
-
}
|
|
4569
|
-
|
|
4570
|
-
object forest_ground {
|
|
4571
|
-
model = "cube"
|
|
4572
|
-
material = "ForestGround"
|
|
4573
|
-
position = (0, 180, -20)
|
|
4574
|
-
size = (900, 520, 40)
|
|
4575
|
-
}
|
|
4820
|
+
// Procedural texture DSL demo: semi-realistic desert wall + forest ground.
|
|
4821
|
+
|
|
4822
|
+
#texture DesertWall
|
|
4823
|
+
tile_m = 2.0;
|
|
4824
|
+
let tile = pattern.tile(uv * vec2(6.0, 4.0), mortar: 0.065, seed: 3);
|
|
4825
|
+
let warp = noise.vec2(uv * 3.0, seed: 11, period: 3) * 0.18;
|
|
4826
|
+
let cells = pattern.voronoi(uv * vec2(12.0, 8.0) + warp, jitter: 0.82, seed: 7, period: vec2(12.0, 8.0));
|
|
4827
|
+
let cracks = stroke(cells.edge, width: 0.055, aa: 0.012);
|
|
4828
|
+
let grain = noise.ridged(uv * 72.0, octaves: 3, seed: 19, period: 72);
|
|
4829
|
+
let broad = noise.fbm(uv * vec2(6.0, 4.0), octaves: 4, seed: 23, period: vec2(6.0, 4.0));
|
|
4830
|
+
let chips = smoothstep(0.65, 0.95, noise.ridged(uv * 36.0, octaves: 3, seed: 29, period: 36)) * (1.0 - smoothstep(0.02, 0.18, tile.edge));
|
|
4831
|
+
let dust = levels(noise.fbm(uv * 5.0 + warp, octaves: 4, seed: 31, period: 5), black: 0.28, white: 0.86, gamma: 1.35);
|
|
4832
|
+
let block = contrast(sat(broad * 0.65 + grain * 0.25 + rand(tile.id, seed: 5) * 0.10), amount: 1.25, pivot: 0.45);
|
|
4833
|
+
let height = mix(-0.045, 0.11 + grain * 0.018 - chips * 0.06, tile.mask) - cracks * 0.07;
|
|
4834
|
+
let stone = ramp(block, [0.0: color("#7d664a"), 0.35: color("#a8875a"), 0.75: color("#c9a66f"), 1.0: color("#ead19c")]);
|
|
4835
|
+
let mortar = color("#75614b") * mix(0.82, 1.08, broad);
|
|
4836
|
+
out.color = mix(mortar, stone, tile.mask) * mix(0.82, 1.06, dust) - cracks * 0.12;
|
|
4837
|
+
out.normal = normal_from_height(height, strength: 1.05);
|
|
4838
|
+
out.orm = orm(occlusion: ao_from_height(height, radius: 2.5), roughness: mix(0.94, 0.82, tile.mask) + dust * 0.03, metallic: 0.0);
|
|
4839
|
+
#end
|
|
4840
|
+
|
|
4841
|
+
#texture ForestGround
|
|
4842
|
+
tile_m = 3.0;
|
|
4843
|
+
let p = uv * vec2(8.0, 8.0);
|
|
4844
|
+
let warp = noise.vec2(uv * 2.0, seed: 41, period: 2) * 0.25;
|
|
4845
|
+
let soil = levels(noise.fbm(p + warp, octaves: 4, seed: 43, period: vec2(8.0, 8.0)), black: 0.18, white: 0.88, gamma: 1.2);
|
|
4846
|
+
let stones = pattern.voronoi(uv * vec2(7.0, 7.0) + warp * 0.6, jitter: 0.78, seed: 47, period: vec2(7.0, 7.0));
|
|
4847
|
+
let stone_shape = 1.0 - smoothstep(0.34, 0.47, stones.dist + noise.fbm(stones.local * 4.0, octaves: 2, seed: 53) * 0.08);
|
|
4848
|
+
let cell_guard = smoothstep(0.025, 0.07, stones.edge);
|
|
4849
|
+
let stone_mask = stone_shape * cell_guard;
|
|
4850
|
+
let moss = levels(noise.fbm(uv * vec2(5.0, 5.0) + warp * 1.4, octaves: 4, seed: 59, period: 5) + (1.0 - stone_mask) * 0.25, black: 0.44, white: 0.92, gamma: 0.85);
|
|
4851
|
+
let wet = contrast(noise.fbm(uv * 3.0 + warp, octaves: 3, seed: 61, period: 3), amount: 1.55, pivot: 0.48);
|
|
4852
|
+
let height = soil * 0.045 + moss * 0.035 + sat(1.0 - stones.dist * 2.1) * stone_mask * 0.10 - (1.0 - soil) * 0.025;
|
|
4853
|
+
let soil_color = ramp(soil, [0.0: color("#211912"), 0.45: color("#3b2b1d"), 1.0: color("#6c5538")]);
|
|
4854
|
+
let moss_color = ramp(moss, [0.0: color("#26351d"), 0.55: color("#43622d"), 1.0: color("#7f9b55")]);
|
|
4855
|
+
let stone_color = ramp(rand(stones.id, seed: 67), [0.0: color("#3e4039"), 0.5: color("#68675b"), 1.0: color("#918a78")]);
|
|
4856
|
+
out.color = mix(mix(soil_color, moss_color, moss * 0.82), stone_color, stone_mask * 0.75);
|
|
4857
|
+
out.normal = normal_from_height(height, strength: 0.95);
|
|
4858
|
+
out.orm = orm(occlusion: ao_from_height(height, radius: 2.0), roughness: mix(0.92, 0.58, wet), metallic: 0.0);
|
|
4859
|
+
#end
|
|
4860
|
+
|
|
4861
|
+
object desert_wall {
|
|
4862
|
+
model = "cube"
|
|
4863
|
+
material = "DesertWall"
|
|
4864
|
+
position = (0, -240, 160)
|
|
4865
|
+
size = (700, 40, 320)
|
|
4866
|
+
}
|
|
4867
|
+
|
|
4868
|
+
object forest_ground {
|
|
4869
|
+
model = "cube"
|
|
4870
|
+
material = "ForestGround"
|
|
4871
|
+
position = (0, 180, -20)
|
|
4872
|
+
size = (900, 520, 40)
|
|
4873
|
+
}
|
|
4576
4874
|
|
|
4577
4875
|
</example_texture_dsl_desert_forest_demo>
|
|
4578
4876
|
|
|
4579
4877
|
|
|
4580
4878
|
<example_texture_dsl_grunge_demo>
|
|
4581
|
-
// Procedural texture DSL demo: scalar mask morphology for grunge and worn painted metal.
|
|
4582
|
-
|
|
4583
|
-
#texture GrungeMask
|
|
4584
|
-
tile_m = 1.5;
|
|
4585
|
-
wrap = repeat;
|
|
4586
|
-
let p = uv * vec2(8.0, 8.0);
|
|
4587
|
-
let warp = noise.vec2(uv * vec2(3.0, 3.0), seed: 71, period: 3) * 0.35;
|
|
4588
|
-
let cloudy = levels(noise.fbm(p + warp, octaves: 5, seed: 73, period: vec2(8.0, 8.0)), black: 0.24, white: 0.82, gamma: 1.18);
|
|
4589
|
-
let pepper = levels(noise.ridged(uv * vec2(72.0, 72.0), octaves: 3, seed: 79, period: 72), black: 0.58, white: 0.94, gamma: 0.75);
|
|
4590
|
-
let streak = levels(noise.ridged(vec2(uv.x * 160.0, uv.y * 5.0), octaves: 2, seed: 83, period: vec2(160.0, 5.0)), black: 0.66, white: 0.93, gamma: 0.65);
|
|
4591
|
-
let pits = dilate(erode(sat(cloudy * 0.62 + pepper * 0.32 + streak * 0.22), radius: 1.0), radius: 1.5);
|
|
4592
|
-
let softened = blur(pits, radius: 1.25);
|
|
4593
|
-
out.color = vec3(softened, softened, softened);
|
|
4594
|
-
out.normal = normal_from_height(softened * 0.05, strength: 0.45);
|
|
4595
|
-
out.orm = orm(occlusion: 1.0 - softened * 0.18, roughness: mix(0.55, 0.95, softened), metallic: 0.0);
|
|
4596
|
-
#end
|
|
4597
|
-
|
|
4598
|
-
#texture WornPaintedMetal
|
|
4599
|
-
tile_m = 1.0;
|
|
4600
|
-
wrap = repeat;
|
|
4601
|
-
let p = uv * vec2(10.0, 10.0);
|
|
4602
|
-
let warp = noise.vec2(uv * vec2(4.0, 4.0), seed: 89, period: 4) * 0.28;
|
|
4603
|
-
let broad = noise.fbm(uv * vec2(5.0, 5.0) + warp, octaves: 4, seed: 97, period: 5);
|
|
4604
|
-
let cells = pattern.voronoi(uv * vec2(14.0, 14.0) + warp * 0.5, jitter: 0.74, seed: 101, period: 14);
|
|
4605
|
-
let crack = stroke(cells.edge, width: 0.035, aa: 0.010);
|
|
4606
|
-
let scratch = levels(noise.ridged(vec2(uv.x * 180.0, uv.y * 7.0), octaves: 2, seed: 103, period: vec2(180.0, 7.0)), black: 0.68, white: 0.96, gamma: 0.72);
|
|
4607
|
-
let chip_seed = levels(noise.ridged(p + warp, octaves: 4, seed: 107, period: 10), black: 0.62, white: 0.92, gamma: 0.85);
|
|
4608
|
-
let raw_wear = sat(chip_seed * 0.70 + scratch * 0.32 + crack * 0.55 - broad * 0.18);
|
|
4609
|
-
let wear = blur(dilate(erode(raw_wear, radius: 0.75), radius: 2.0), radius: 0.75);
|
|
4610
|
-
let rust = levels(noise.fbm(uv * vec2(18.0, 18.0) + warp, octaves: 3, seed: 109, period: 18), black: 0.30, white: 0.90, gamma: 1.35);
|
|
4611
|
-
let paint = color("#275f6f") * mix(0.70, 1.15, broad);
|
|
4612
|
-
let exposed = mix(color("#6f7473"), color("#8c4a24"), rust * 0.55);
|
|
4613
|
-
let height = broad * 0.035 - wear * 0.070 + scratch * 0.018;
|
|
4614
|
-
out.color = mix(paint, exposed, wear);
|
|
4615
|
-
out.normal = normal_from_height(height, strength: 0.95);
|
|
4616
|
-
out.orm = orm(occlusion: ao_from_height(height, radius: 2.0), roughness: mix(0.62, 0.92, wear), metallic: mix(0.02, 0.70, wear * (1.0 - rust * 0.55)));
|
|
4617
|
-
#end
|
|
4618
|
-
|
|
4619
|
-
object grunge_panel {
|
|
4620
|
-
model = "cube"
|
|
4621
|
-
material = "GrungeMask"
|
|
4622
|
-
position = (-260, 0, 80)
|
|
4623
|
-
size = (260, 40, 180)
|
|
4624
|
-
}
|
|
4625
|
-
|
|
4626
|
-
object worn_painted_metal_panel {
|
|
4627
|
-
model = "cube"
|
|
4628
|
-
material = "WornPaintedMetal"
|
|
4629
|
-
position = (180, 0, 80)
|
|
4630
|
-
size = (360, 40, 220)
|
|
4631
|
-
}
|
|
4879
|
+
// Procedural texture DSL demo: scalar mask morphology for grunge and worn painted metal.
|
|
4880
|
+
|
|
4881
|
+
#texture GrungeMask
|
|
4882
|
+
tile_m = 1.5;
|
|
4883
|
+
wrap = repeat;
|
|
4884
|
+
let p = uv * vec2(8.0, 8.0);
|
|
4885
|
+
let warp = noise.vec2(uv * vec2(3.0, 3.0), seed: 71, period: 3) * 0.35;
|
|
4886
|
+
let cloudy = levels(noise.fbm(p + warp, octaves: 5, seed: 73, period: vec2(8.0, 8.0)), black: 0.24, white: 0.82, gamma: 1.18);
|
|
4887
|
+
let pepper = levels(noise.ridged(uv * vec2(72.0, 72.0), octaves: 3, seed: 79, period: 72), black: 0.58, white: 0.94, gamma: 0.75);
|
|
4888
|
+
let streak = levels(noise.ridged(vec2(uv.x * 160.0, uv.y * 5.0), octaves: 2, seed: 83, period: vec2(160.0, 5.0)), black: 0.66, white: 0.93, gamma: 0.65);
|
|
4889
|
+
let pits = dilate(erode(sat(cloudy * 0.62 + pepper * 0.32 + streak * 0.22), radius: 1.0), radius: 1.5);
|
|
4890
|
+
let softened = blur(pits, radius: 1.25);
|
|
4891
|
+
out.color = vec3(softened, softened, softened);
|
|
4892
|
+
out.normal = normal_from_height(softened * 0.05, strength: 0.45);
|
|
4893
|
+
out.orm = orm(occlusion: 1.0 - softened * 0.18, roughness: mix(0.55, 0.95, softened), metallic: 0.0);
|
|
4894
|
+
#end
|
|
4895
|
+
|
|
4896
|
+
#texture WornPaintedMetal
|
|
4897
|
+
tile_m = 1.0;
|
|
4898
|
+
wrap = repeat;
|
|
4899
|
+
let p = uv * vec2(10.0, 10.0);
|
|
4900
|
+
let warp = noise.vec2(uv * vec2(4.0, 4.0), seed: 89, period: 4) * 0.28;
|
|
4901
|
+
let broad = noise.fbm(uv * vec2(5.0, 5.0) + warp, octaves: 4, seed: 97, period: 5);
|
|
4902
|
+
let cells = pattern.voronoi(uv * vec2(14.0, 14.0) + warp * 0.5, jitter: 0.74, seed: 101, period: 14);
|
|
4903
|
+
let crack = stroke(cells.edge, width: 0.035, aa: 0.010);
|
|
4904
|
+
let scratch = levels(noise.ridged(vec2(uv.x * 180.0, uv.y * 7.0), octaves: 2, seed: 103, period: vec2(180.0, 7.0)), black: 0.68, white: 0.96, gamma: 0.72);
|
|
4905
|
+
let chip_seed = levels(noise.ridged(p + warp, octaves: 4, seed: 107, period: 10), black: 0.62, white: 0.92, gamma: 0.85);
|
|
4906
|
+
let raw_wear = sat(chip_seed * 0.70 + scratch * 0.32 + crack * 0.55 - broad * 0.18);
|
|
4907
|
+
let wear = blur(dilate(erode(raw_wear, radius: 0.75), radius: 2.0), radius: 0.75);
|
|
4908
|
+
let rust = levels(noise.fbm(uv * vec2(18.0, 18.0) + warp, octaves: 3, seed: 109, period: 18), black: 0.30, white: 0.90, gamma: 1.35);
|
|
4909
|
+
let paint = color("#275f6f") * mix(0.70, 1.15, broad);
|
|
4910
|
+
let exposed = mix(color("#6f7473"), color("#8c4a24"), rust * 0.55);
|
|
4911
|
+
let height = broad * 0.035 - wear * 0.070 + scratch * 0.018;
|
|
4912
|
+
out.color = mix(paint, exposed, wear);
|
|
4913
|
+
out.normal = normal_from_height(height, strength: 0.95);
|
|
4914
|
+
out.orm = orm(occlusion: ao_from_height(height, radius: 2.0), roughness: mix(0.62, 0.92, wear), metallic: mix(0.02, 0.70, wear * (1.0 - rust * 0.55)));
|
|
4915
|
+
#end
|
|
4916
|
+
|
|
4917
|
+
object grunge_panel {
|
|
4918
|
+
model = "cube"
|
|
4919
|
+
material = "GrungeMask"
|
|
4920
|
+
position = (-260, 0, 80)
|
|
4921
|
+
size = (260, 40, 180)
|
|
4922
|
+
}
|
|
4923
|
+
|
|
4924
|
+
object worn_painted_metal_panel {
|
|
4925
|
+
model = "cube"
|
|
4926
|
+
material = "WornPaintedMetal"
|
|
4927
|
+
position = (180, 0, 80)
|
|
4928
|
+
size = (360, 40, 220)
|
|
4929
|
+
}
|
|
4632
4930
|
|
|
4633
4931
|
</example_texture_dsl_grunge_demo>
|
|
4634
4932
|
|
|
4635
4933
|
|
|
4636
4934
|
<example_tree_species>
|
|
4637
|
-
// Curated #tree species gallery. Each recipe is a reference worth copying as a
|
|
4638
|
-
// starting point for that habit; keep the shape keys, adjust seed/size per scene.
|
|
4639
|
-
// Iterate look changes with preview_tree and watch the foliage_coverage stat.
|
|
4640
|
-
|
|
4641
|
-
// European beech: broad asymmetric dome from four overlapping crown lobes, a
|
|
4642
|
-
// trunk that persists partway into the crown (leader) then dissolves into forks,
|
|
4643
|
-
// slender bole, dense cluster cards.
|
|
4644
|
-
#tree Beech
|
|
4645
|
-
seed: 27
|
|
4646
|
-
mode: colonize
|
|
4647
|
-
leader: 62
|
|
4648
|
-
levels: 4
|
|
4649
|
-
children: 7
|
|
4650
|
-
segments: 7
|
|
4651
|
-
trunk_height: 1250
|
|
4652
|
-
trunk_radius: 34
|
|
4653
|
-
points: 1024
|
|
4654
|
-
length_pct: 76
|
|
4655
|
-
radius_pct: 46
|
|
4656
|
-
angle_deg: 46
|
|
4657
|
-
angle_jitter_deg: 20
|
|
4658
|
-
up_bias_pct: 26
|
|
4659
|
-
curve_jitter_pct: 16
|
|
4660
|
-
trunk_noise_pct: 4
|
|
4661
|
-
trunk_lean_deg: 3 // gentle bands: beeches curve, they don't lean hard
|
|
4662
|
-
trunk_sweep_pct: 16
|
|
4663
|
-
trunk_noise_scale_pct: 30 // wavelength as % of height: slow bends, not bark-beat raggedness
|
|
4664
|
-
leaves: 12
|
|
4665
|
-
leaf_size: 178
|
|
4666
|
-
droop_pct: 8
|
|
4667
|
-
root_flare_pct: 34
|
|
4668
|
-
crown_ellipsoid: 0, 0, 1020, 620, 590, 510
|
|
4669
|
-
crown_ellipsoid: -250, 80, 960, 400, 370, 360
|
|
4670
|
-
crown_ellipsoid: 240, -100, 1060, 420, 390, 400
|
|
4671
|
-
crown_ellipsoid: 40, 50, 1380, 380, 350, 300
|
|
4672
|
-
#end
|
|
4673
|
-
|
|
4674
|
-
// Grand open-grown oak: a dominant central trunk visible deep into the tiered
|
|
4675
|
-
// crown, three low limb masses ~120 degrees apart in plan (every viewing angle
|
|
4676
|
-
// shows a reaching limb - lobes on one axis collapse to a blob from the thin
|
|
4677
|
-
// side), offset upper lobes, real sky gaps. An irregular ellipsoid stack, not
|
|
4678
|
-
// one sphere. Open crowns like this read ~35-45% coverage; gaps are the character.
|
|
4679
|
-
#tree Oak
|
|
4680
|
-
seed: 5
|
|
4681
|
-
mode: colonize
|
|
4682
|
-
leader: 35
|
|
4683
|
-
levels: 4
|
|
4684
|
-
children: 6
|
|
4685
|
-
segments: 7
|
|
4686
|
-
trunk_height: 950
|
|
4687
|
-
trunk_radius: 44
|
|
4688
|
-
points: 1024
|
|
4689
|
-
length_pct: 80
|
|
4690
|
-
radius_pct: 52
|
|
4691
|
-
angle_deg: 55
|
|
4692
|
-
angle_jitter_deg: 28
|
|
4693
|
-
up_bias_pct: 22
|
|
4694
|
-
curve_jitter_pct: 26
|
|
4695
|
-
trunk_noise_pct: 7
|
|
4696
|
-
trunk_lean_deg: 5 // low bands: a real oak is never a plumb pole
|
|
4697
|
-
trunk_sweep_pct: 20 // one slow arc; seed picks C vs S
|
|
4698
|
-
trunk_gnarl_pct: 40 // lobed lower-bole silhouette for hero close-ups (display-only)
|
|
4699
|
-
leaves: 13
|
|
4700
|
-
leaf_size: 190
|
|
4701
|
-
droop_pct: 12
|
|
4702
|
-
root_flare_pct: 45
|
|
4703
|
-
crown_ellipsoid: 0, 0, 1120, 700, 660, 560
|
|
4704
|
-
crown_ellipsoid: 435, 115, 930, 480, 430, 340
|
|
4705
|
-
crown_ellipsoid: -320, 320, 900, 470, 420, 330
|
|
4706
|
-
crown_ellipsoid: -115, -435, 1000, 450, 410, 350
|
|
4707
|
-
crown_ellipsoid: -200, -190, 1500, 450, 410, 340
|
|
4708
|
-
crown_ellipsoid: 230, 180, 1620, 390, 360, 300
|
|
4709
|
-
#end
|
|
4710
|
-
|
|
4711
|
-
// Fir: the dense layered conifer - whorl rings of downswept shelf branches
|
|
4712
|
-
// (angle_deg > 90 + up_bias swoop) rendered as whole-branch frond ribbons,
|
|
4713
|
-
// clear bole below crown_base, trunk-only collider. crown_base ~120 instead
|
|
4714
|
-
// gives the ground-sweeping park look.
|
|
4715
|
-
#tree Fir
|
|
4716
|
-
seed: 11
|
|
4717
|
-
mode: whorl
|
|
4718
|
-
leaf_mode: frond
|
|
4719
|
-
levels: 2
|
|
4720
|
-
children: 12
|
|
4721
|
-
rings: 30
|
|
4722
|
-
fill: 10
|
|
4723
|
-
segments: 8
|
|
4724
|
-
trunk_height: 1400
|
|
4725
|
-
trunk_radius: 22
|
|
4726
|
-
trunk_noise_pct: 2
|
|
4727
|
-
trunk_lean_deg: 1 // conifer spires stand near-plumb; kill the default lean/sweep
|
|
4728
|
-
trunk_sweep_pct: 3
|
|
4729
|
-
curve_jitter_pct: 5
|
|
4730
|
-
angle_deg: 106
|
|
4731
|
-
up_bias_pct: 8
|
|
4732
|
-
length_pct: 18
|
|
4733
|
-
length_taper_pct: 70
|
|
4734
|
-
droop_pct: 34
|
|
4735
|
-
leaf_size: 200
|
|
4736
|
-
root_flare_pct: 25
|
|
4737
|
-
crown_base: 300
|
|
4738
|
-
collider_levels: 1
|
|
4739
|
-
#end
|
|
4740
|
-
|
|
4741
|
-
// Weeping willow: spiral limbs arch up (up_bias) then cascade (droop) carrying
|
|
4742
|
-
// gravity-hung strand curtains (leaf_mode weeping). Long falls come from
|
|
4743
|
-
// leaf_size (the curtain card side, cm) - ~300 reaches near the ground from a
|
|
4744
|
-
// stout mid-height fork.
|
|
4745
|
-
#tree Willow
|
|
4746
|
-
seed: 9
|
|
4747
|
-
mode: spiral
|
|
4748
|
-
leaf_mode: weeping
|
|
4749
|
-
levels: 3
|
|
4750
|
-
children: 10
|
|
4751
|
-
segments: 8
|
|
4752
|
-
trunk_height: 750
|
|
4753
|
-
trunk_radius: 46
|
|
4754
|
-
length_pct: 82
|
|
4755
|
-
radius_pct: 50
|
|
4756
|
-
angle_deg: 40
|
|
4757
|
-
angle_jitter_deg: 18
|
|
4758
|
-
up_bias_pct: 34
|
|
4759
|
-
curve_jitter_pct: 18
|
|
4760
|
-
trunk_noise_pct: 5
|
|
4761
|
-
trunk_lean_deg: 4
|
|
4762
|
-
trunk_sweep_pct: 25 // waterside willows arc; pairs with the cascading crown
|
|
4763
|
-
droop_pct: 85
|
|
4764
|
-
leaves: 20
|
|
4765
|
-
leaf_size: 300
|
|
4766
|
-
root_flare_pct: 48
|
|
4767
|
-
#end
|
|
4768
|
-
|
|
4769
|
-
// Umbrella-thorn acacia: crown_dome mushroom cap on a bare fanning scaffold. The
|
|
4770
|
-
// short trunk + high cap forces colonize to bridge with long limbs; the TWO bare
|
|
4771
|
-
// guide ellipsoids make them diverge early and fork again mid-way (a lone
|
|
4772
|
-
// overhead cap pulls one straight vertical reach instead - attraction averages
|
|
4773
|
-
// out). children raises the forks per node. leaf_base at the dome cut with a
|
|
4774
|
-
// short fade keeps every guide bare and the cap underside crisp and flat.
|
|
4775
|
-
#tree Acacia
|
|
4776
|
-
seed: 4
|
|
4777
|
-
mode: colonize
|
|
4778
|
-
children: 7
|
|
4779
|
-
trunk_height: 260
|
|
4780
|
-
trunk_radius: 36
|
|
4781
|
-
points: 1024
|
|
4782
|
-
length_pct: 80
|
|
4783
|
-
radius_pct: 60
|
|
4784
|
-
curve_jitter_pct: 18
|
|
4785
|
-
trunk_noise_pct: 6
|
|
4786
|
-
trunk_lean_deg: 8 // savanna wind-shaped bole; crown_follow keeps the cap on it
|
|
4787
|
-
leaves: 13
|
|
4788
|
-
leaf_size: 185
|
|
4789
|
-
leaf_base: 740
|
|
4790
|
-
leaf_base_fade: 60
|
|
4791
|
-
root_flare_pct: 35
|
|
4792
|
-
crown_ellipsoid: 0, 0, 520, 300, 300, 160
|
|
4793
|
-
crown_ellipsoid: 0, 0, 690, 460, 460, 90
|
|
4794
|
-
crown_dome: 0, 0, 750, 800, 800, 360
|
|
4795
|
-
#end
|
|
4796
|
-
|
|
4797
|
-
object Beech1 { model = "tree.Beech" position = (0, 0, 0) }
|
|
4798
|
-
object Oak1 { model = "tree.Oak" position = (2200, 0, 0) }
|
|
4799
|
-
object Fir1 { model = "tree.Fir" position = (4000, 0, 0) }
|
|
4800
|
-
object Willow1 { model = "tree.Willow" position = (5800, 0, 0) }
|
|
4801
|
-
object Acacia1 { model = "tree.Acacia" position = (8000, 0, 0) }
|
|
4935
|
+
// Curated #tree species gallery. Each recipe is a reference worth copying as a
|
|
4936
|
+
// starting point for that habit; keep the shape keys, adjust seed/size per scene.
|
|
4937
|
+
// Iterate look changes with preview_tree and watch the foliage_coverage stat.
|
|
4938
|
+
|
|
4939
|
+
// European beech: broad asymmetric dome from four overlapping crown lobes, a
|
|
4940
|
+
// trunk that persists partway into the crown (leader) then dissolves into forks,
|
|
4941
|
+
// slender bole, dense cluster cards.
|
|
4942
|
+
#tree Beech
|
|
4943
|
+
seed: 27
|
|
4944
|
+
mode: colonize
|
|
4945
|
+
leader: 62
|
|
4946
|
+
levels: 4
|
|
4947
|
+
children: 7
|
|
4948
|
+
segments: 7
|
|
4949
|
+
trunk_height: 1250
|
|
4950
|
+
trunk_radius: 34
|
|
4951
|
+
points: 1024
|
|
4952
|
+
length_pct: 76
|
|
4953
|
+
radius_pct: 46
|
|
4954
|
+
angle_deg: 46
|
|
4955
|
+
angle_jitter_deg: 20
|
|
4956
|
+
up_bias_pct: 26
|
|
4957
|
+
curve_jitter_pct: 16
|
|
4958
|
+
trunk_noise_pct: 4
|
|
4959
|
+
trunk_lean_deg: 3 // gentle bands: beeches curve, they don't lean hard
|
|
4960
|
+
trunk_sweep_pct: 16
|
|
4961
|
+
trunk_noise_scale_pct: 30 // wavelength as % of height: slow bends, not bark-beat raggedness
|
|
4962
|
+
leaves: 12
|
|
4963
|
+
leaf_size: 178
|
|
4964
|
+
droop_pct: 8
|
|
4965
|
+
root_flare_pct: 34
|
|
4966
|
+
crown_ellipsoid: 0, 0, 1020, 620, 590, 510
|
|
4967
|
+
crown_ellipsoid: -250, 80, 960, 400, 370, 360
|
|
4968
|
+
crown_ellipsoid: 240, -100, 1060, 420, 390, 400
|
|
4969
|
+
crown_ellipsoid: 40, 50, 1380, 380, 350, 300
|
|
4970
|
+
#end
|
|
4971
|
+
|
|
4972
|
+
// Grand open-grown oak: a dominant central trunk visible deep into the tiered
|
|
4973
|
+
// crown, three low limb masses ~120 degrees apart in plan (every viewing angle
|
|
4974
|
+
// shows a reaching limb - lobes on one axis collapse to a blob from the thin
|
|
4975
|
+
// side), offset upper lobes, real sky gaps. An irregular ellipsoid stack, not
|
|
4976
|
+
// one sphere. Open crowns like this read ~35-45% coverage; gaps are the character.
|
|
4977
|
+
#tree Oak
|
|
4978
|
+
seed: 5
|
|
4979
|
+
mode: colonize
|
|
4980
|
+
leader: 35
|
|
4981
|
+
levels: 4
|
|
4982
|
+
children: 6
|
|
4983
|
+
segments: 7
|
|
4984
|
+
trunk_height: 950
|
|
4985
|
+
trunk_radius: 44
|
|
4986
|
+
points: 1024
|
|
4987
|
+
length_pct: 80
|
|
4988
|
+
radius_pct: 52
|
|
4989
|
+
angle_deg: 55
|
|
4990
|
+
angle_jitter_deg: 28
|
|
4991
|
+
up_bias_pct: 22
|
|
4992
|
+
curve_jitter_pct: 26
|
|
4993
|
+
trunk_noise_pct: 7
|
|
4994
|
+
trunk_lean_deg: 5 // low bands: a real oak is never a plumb pole
|
|
4995
|
+
trunk_sweep_pct: 20 // one slow arc; seed picks C vs S
|
|
4996
|
+
trunk_gnarl_pct: 40 // lobed lower-bole silhouette for hero close-ups (display-only)
|
|
4997
|
+
leaves: 13
|
|
4998
|
+
leaf_size: 190
|
|
4999
|
+
droop_pct: 12
|
|
5000
|
+
root_flare_pct: 45
|
|
5001
|
+
crown_ellipsoid: 0, 0, 1120, 700, 660, 560
|
|
5002
|
+
crown_ellipsoid: 435, 115, 930, 480, 430, 340
|
|
5003
|
+
crown_ellipsoid: -320, 320, 900, 470, 420, 330
|
|
5004
|
+
crown_ellipsoid: -115, -435, 1000, 450, 410, 350
|
|
5005
|
+
crown_ellipsoid: -200, -190, 1500, 450, 410, 340
|
|
5006
|
+
crown_ellipsoid: 230, 180, 1620, 390, 360, 300
|
|
5007
|
+
#end
|
|
5008
|
+
|
|
5009
|
+
// Fir: the dense layered conifer - whorl rings of downswept shelf branches
|
|
5010
|
+
// (angle_deg > 90 + up_bias swoop) rendered as whole-branch frond ribbons,
|
|
5011
|
+
// clear bole below crown_base, trunk-only collider. crown_base ~120 instead
|
|
5012
|
+
// gives the ground-sweeping park look.
|
|
5013
|
+
#tree Fir
|
|
5014
|
+
seed: 11
|
|
5015
|
+
mode: whorl
|
|
5016
|
+
leaf_mode: frond
|
|
5017
|
+
levels: 2
|
|
5018
|
+
children: 12
|
|
5019
|
+
rings: 30
|
|
5020
|
+
fill: 10
|
|
5021
|
+
segments: 8
|
|
5022
|
+
trunk_height: 1400
|
|
5023
|
+
trunk_radius: 22
|
|
5024
|
+
trunk_noise_pct: 2
|
|
5025
|
+
trunk_lean_deg: 1 // conifer spires stand near-plumb; kill the default lean/sweep
|
|
5026
|
+
trunk_sweep_pct: 3
|
|
5027
|
+
curve_jitter_pct: 5
|
|
5028
|
+
angle_deg: 106
|
|
5029
|
+
up_bias_pct: 8
|
|
5030
|
+
length_pct: 18
|
|
5031
|
+
length_taper_pct: 70
|
|
5032
|
+
droop_pct: 34
|
|
5033
|
+
leaf_size: 200
|
|
5034
|
+
root_flare_pct: 25
|
|
5035
|
+
crown_base: 300
|
|
5036
|
+
collider_levels: 1
|
|
5037
|
+
#end
|
|
5038
|
+
|
|
5039
|
+
// Weeping willow: spiral limbs arch up (up_bias) then cascade (droop) carrying
|
|
5040
|
+
// gravity-hung strand curtains (leaf_mode weeping). Long falls come from
|
|
5041
|
+
// leaf_size (the curtain card side, cm) - ~300 reaches near the ground from a
|
|
5042
|
+
// stout mid-height fork.
|
|
5043
|
+
#tree Willow
|
|
5044
|
+
seed: 9
|
|
5045
|
+
mode: spiral
|
|
5046
|
+
leaf_mode: weeping
|
|
5047
|
+
levels: 3
|
|
5048
|
+
children: 10
|
|
5049
|
+
segments: 8
|
|
5050
|
+
trunk_height: 750
|
|
5051
|
+
trunk_radius: 46
|
|
5052
|
+
length_pct: 82
|
|
5053
|
+
radius_pct: 50
|
|
5054
|
+
angle_deg: 40
|
|
5055
|
+
angle_jitter_deg: 18
|
|
5056
|
+
up_bias_pct: 34
|
|
5057
|
+
curve_jitter_pct: 18
|
|
5058
|
+
trunk_noise_pct: 5
|
|
5059
|
+
trunk_lean_deg: 4
|
|
5060
|
+
trunk_sweep_pct: 25 // waterside willows arc; pairs with the cascading crown
|
|
5061
|
+
droop_pct: 85
|
|
5062
|
+
leaves: 20
|
|
5063
|
+
leaf_size: 300
|
|
5064
|
+
root_flare_pct: 48
|
|
5065
|
+
#end
|
|
5066
|
+
|
|
5067
|
+
// Umbrella-thorn acacia: crown_dome mushroom cap on a bare fanning scaffold. The
|
|
5068
|
+
// short trunk + high cap forces colonize to bridge with long limbs; the TWO bare
|
|
5069
|
+
// guide ellipsoids make them diverge early and fork again mid-way (a lone
|
|
5070
|
+
// overhead cap pulls one straight vertical reach instead - attraction averages
|
|
5071
|
+
// out). children raises the forks per node. leaf_base at the dome cut with a
|
|
5072
|
+
// short fade keeps every guide bare and the cap underside crisp and flat.
|
|
5073
|
+
#tree Acacia
|
|
5074
|
+
seed: 4
|
|
5075
|
+
mode: colonize
|
|
5076
|
+
children: 7
|
|
5077
|
+
trunk_height: 260
|
|
5078
|
+
trunk_radius: 36
|
|
5079
|
+
points: 1024
|
|
5080
|
+
length_pct: 80
|
|
5081
|
+
radius_pct: 60
|
|
5082
|
+
curve_jitter_pct: 18
|
|
5083
|
+
trunk_noise_pct: 6
|
|
5084
|
+
trunk_lean_deg: 8 // savanna wind-shaped bole; crown_follow keeps the cap on it
|
|
5085
|
+
leaves: 13
|
|
5086
|
+
leaf_size: 185
|
|
5087
|
+
leaf_base: 740
|
|
5088
|
+
leaf_base_fade: 60
|
|
5089
|
+
root_flare_pct: 35
|
|
5090
|
+
crown_ellipsoid: 0, 0, 520, 300, 300, 160
|
|
5091
|
+
crown_ellipsoid: 0, 0, 690, 460, 460, 90
|
|
5092
|
+
crown_dome: 0, 0, 750, 800, 800, 360
|
|
5093
|
+
#end
|
|
5094
|
+
|
|
5095
|
+
object Beech1 { model = "tree.Beech" position = (0, 0, 0) }
|
|
5096
|
+
object Oak1 { model = "tree.Oak" position = (2200, 0, 0) }
|
|
5097
|
+
object Fir1 { model = "tree.Fir" position = (4000, 0, 0) }
|
|
5098
|
+
object Willow1 { model = "tree.Willow" position = (5800, 0, 0) }
|
|
5099
|
+
object Acacia1 { model = "tree.Acacia" position = (8000, 0, 0) }
|
|
4802
5100
|
|
|
4803
5101
|
</example_tree_species>
|
|
4804
5102
|
|
|
@@ -5272,19 +5570,23 @@ screenCanvas TutorialUI {
|
|
|
5272
5570
|
|
|
5273
5571
|
|
|
5274
5572
|
<example_vehicle_driving>
|
|
5275
|
-
// Drivable car with an NPC driver you can carjack - the seat primitive end-to-end
|
|
5276
|
-
//
|
|
5277
|
-
//
|
|
5573
|
+
// Drivable car with an NPC driver you can carjack - the seat primitive end-to-end on a MODEL
|
|
5574
|
+
// car. SetModelAnchor mints the "driver" seat once per model (model-root local cm, Z-up,
|
|
5575
|
+
// +X = nose; hips land there, rider faces +X); SeatPlayer parks riders on it: the engine
|
|
5576
|
+
// suspends the capsule + native controls, the avatar rides the seat, the default chase
|
|
5278
5577
|
// camera follows - no per-frame camera or position writes. Car feel (accel/drag/turn)
|
|
5279
5578
|
// stays script-owned kinematic velocity integration; seat roles and jack rules are
|
|
5280
|
-
// script vars.
|
|
5579
|
+
// script vars. Primitive-built seats (a cushion block, no model): SeatPlayerAt(P, "driver", offset).
|
|
5281
5580
|
|
|
5282
5581
|
#class CarController
|
|
5283
5582
|
var Vel = Vector(0, 0, 0)
|
|
5284
5583
|
var TopSpeed = 900
|
|
5285
|
-
|
|
5584
|
+
event OnSpawned {
|
|
5585
|
+
// The sedan model is center-origin and 140 tall: hips ~50cm above the underbody -> z -20; driver side +Y.
|
|
5586
|
+
SetModelAnchor(GetModel(), "driver", Position(-5, 40, -20), Vector(0, 0, 0))
|
|
5587
|
+
}
|
|
5286
5588
|
func Board(P: Object) {
|
|
5287
|
-
|
|
5589
|
+
SeatPlayer(P, "driver")
|
|
5288
5590
|
}
|
|
5289
5591
|
event Update {
|
|
5290
5592
|
var driver = SeatOccupant("driver")
|
|
@@ -5331,7 +5633,7 @@ event ActionDownByThisPlayer[Interact] {
|
|
|
5331
5633
|
|
|
5332
5634
|
material Asphalt { base = "PolishedConcrete" }
|
|
5333
5635
|
object ground { model = "cube" material = "Asphalt" position = (0, 0, -100) size = (12000, 12000, 100) }
|
|
5334
|
-
object Taxi : CarController { model = "
|
|
5636
|
+
object Taxi : CarController { model = "alias.model.sedan" height = 140 position = (300, 0, 5) color = (0.95, 0.75, 0.1) }
|
|
5335
5637
|
display manager : CityManager { visible = false }
|
|
5336
5638
|
screenCanvas HUD { textLabel T { offset = (20, 20) size = (620, 28) align = (left, center) text = "E near the taxi: carjack the cabbie. Drive with WASD; E again to step out." color = (1, 1, 1) } }
|
|
5337
5639
|
|
|
@@ -5359,15 +5661,18 @@ Worlds may carry `#doc_version N` = the doc version they were last authored/upgr
|
|
|
5359
5661
|
- only use '//' for comments
|
|
5360
5662
|
- Destroy() also ends the current function body (a value-returning func returns its type default); the caller keeps running this frame.
|
|
5361
5663
|
- Object member calls (including Destroy()) on a None or already-despawned Object are runtime errors (a second Destroy() before the queued despawn runs is fine). Avoid spamming Exists(); prefer fail-fast. Use Exists() only when absence is expected (mouse/crosshair miss, destroyed mid-loop). Note: Object.Exists() is safe on None (returns false), so `o == None or not o.Exists()` is redundant; write `not o.Exists()`.
|
|
5664
|
+
- `and`/`or` evaluate left to right and short-circuit: `o.Exists() and o.Hp > 0` is a safe guard. IsConnected() is a member call, not a presence check - it throws on a stale handle, guard it with Exists(). An Object local can despawn during Wait(): re-test Exists() after every Wait().
|
|
5362
5665
|
- Reference a named scene object with Scene.X (e.g. Scene.Hotbar, Scene.EnemyBase.SetVisible(true)). It resolves once at world load; Exists() is false if no such object. Runtime-spawned objects are not reachable this way - keep the SpawnObject result in a var.
|
|
5363
5666
|
- Never write saved_origin inside a saved clause (wrong: saved BrickBlock { object BrickBlock { saved_origin = "BrickBlock" } })
|
|
5364
5667
|
- when asked to make a game similar to original, stay as close to the original as possible in terms of game mechanics
|
|
5365
5668
|
- Split subsystem logic (production, AI opponent, camera, selection UI) into small manager classes early; don't let one class accumulate everything.
|
|
5366
5669
|
- Use one List<T> instead of numbered var runs (Slot0, Slot1, Slot2, ...).
|
|
5367
5670
|
- Objects are engine-pooled: SpawnObject/Destroy reuses object slots and is cheap. Spawn from `saved` templates; never build manual pools of pre-placed hidden objects.
|
|
5368
|
-
- SetAssetSubmesh* calls are global per-asset: call each once per scene (e.g.
|
|
5671
|
+
- SetAssetSubmesh* calls are global per-asset: call each once per scene (e.g. OnPreSpawn of a single setup object), not per spawned object.
|
|
5369
5672
|
- If scene init manipulates many static objects (OnSpawned chains, setup before the main loop), call RefreshStaticBaseline() once at the end of init.
|
|
5370
5673
|
- Delete debug scaffolding (test cursors, debug spawn panels, temp markers) once the feature works.
|
|
5674
|
+
- Class funcs cannot take an engine simcall name (Die, Attack, Jump, ...): compile error W2C0623 - rename (e.g. PlayerDeath).
|
|
5675
|
+
- A triple-quoted `text = """..."""` value must be the last token on its line; put other properties on their own lines.
|
|
5371
5676
|
</additional_notes>
|
|
5372
5677
|
|
|
5373
5678
|
<weave2_migration>
|