diff --git a/doc/en/0.Home.md b/doc/en/0.Home.md
new file mode 100644
index 00000000..70302da8
--- /dev/null
+++ b/doc/en/0.Home.md
@@ -0,0 +1,11 @@
+# Sections
+
+- [Engine usage recommendations](1.Engine-usage-recommendations.md)
+- [Content-packs](2.Content-packs.md)
+- [Block properties](3.Block-properties.md)
+- [Item properties](4.Item-properties.md)
+- [XML UI building](5.XML-UI-building.md)
+- [Assets preloading](6.Assets-preloading.md)
+- [Audio](7.Audio.md)
+- [Scripting](8.Scripting.md)
+- [Block modoels](9.Block-models.md)
diff --git a/doc/en/1.Engine-usage-recommendations.md b/doc/en/1.Engine-usage-recommendations.md
new file mode 100644
index 00000000..f5b13478
--- /dev/null
+++ b/doc/en/1.Engine-usage-recommendations.md
@@ -0,0 +1,31 @@
+# Engine usage recommendations
+
+## Content naming
+
+### Content packs ID
+
+Content pack identifier requirements:
+- name can consist of Capital letters A-Z, lowercase letters a-z digits 0-9, and underscore '\_' signs.
+- the first character must not be a digit.
+- name length must be in range \[2, 24\]
+
+### Blocks and items
+
+- blocks and items identifiers follow the same requirements as content-pack ID.
+- `.item` suffix added only to replace auto-generated block item. Example: `base:stone.item` - an item generated for stone block.
+- **caption** field specifying name displayed in inventory UI should not be Capitalized. The engine does it automatically depending on display context.
+
+## Storage
+
+### Content packs data
+
+Settings and other state that supposed to be saved with a world, must be stored in `world:data/pack_id/`. The path should be retrieved by calling a function:
+```lua
+local path = pack.data_file(PACK_ID, "file_name")
+file.write(path, some_data)
+-- writes data to file world:data/PACK_ID/file_name
+```
+PACK_ID is an existing variable containing current content-pack name.
+
+Directory `world:data/PACK_ID` will be created on call `pack.data_file(...)`.
+
diff --git a/doc/en/2.Content-packs.md b/doc/en/2.Content-packs.md
new file mode 100644
index 00000000..eb5b26c3
--- /dev/null
+++ b/doc/en/2.Content-packs.md
@@ -0,0 +1,40 @@
+# Content-packs
+
+Every content pack must have an ID following requirements:
+- name can consist of Capital letters A-Z, lowercase letters a-z digits 0-9, and underscore '\_' signs.
+- the first character must not be a digit.
+- name length must be in range \[2, 24\]
+
+Content-pack folder having name same as ID may be created in *res/content*.
+Content-pack folder must contain file **package.json** with following contents:
+
+```json
+{
+ "id": "pack_id",
+ "title": "pack name will be displayed in the content menu",
+ "version": "content-pack version - major.minor",
+ "creator": "content-pack creator",
+ "description": "short description",
+ "dependencies": [
+ "pack",
+ "dependencies"
+ ]
+}
+```
+
+Example:
+```json
+{
+ "id": "doors",
+ "title": "DOORS",
+ "creator": "MihailRis",
+ "version": "1.0",
+ "description": "doors test"
+}
+```
+
+Content pack picture should be added as *icon.png* file. Recommended size: 128x128
+
+See *res/content/base* as an example of content pack structure.
+
+
diff --git a/doc/en/3.Block-properties.md b/doc/en/3.Block-properties.md
new file mode 100644
index 00000000..6f3cee7e
--- /dev/null
+++ b/doc/en/3.Block-properties.md
@@ -0,0 +1,130 @@
+# Block properties
+## Visual
+
+### *texture*
+
+Block texture name (name of the file in `textures/blocks/` with no path and extension included, just name)
+
+Texture file must be a **png** image
+
+### *texture-faces*
+
+> [!IMPORTANT]
+> Can't be used if `texture` already specified
+
+An array of 6 texture names for block sides.
+
+Example:
+```json
+"texture-faces": [
+ "grass_side",
+ "grass_side",
+ "dirt",
+ "grass_top",
+ "grass_side",
+ "grass_side"
+]
+```
+
+### *model*
+
+Block model type from list:
+- "block" - default block model
+- "none" - invisible block (air)
+- "X" - grass model (two crossed sprites)
+- "aabb" - model based of block hitbox (complex hitbox will be combined into one). Examples: pipes, bulbs, panels.
+
+### *draw-group*
+
+Integer specifying number of block draw group (render order). Used for semi-transparent blocks.
+
+### *rotation*
+
+Rotation profile (set of available block rotations and behaviour of placing block rotation) from list:
+
+- "none" - no rotation available (default profile)
+- "pipe" - wood logs, pipes, pillars
+- "pane" - panels, doors, signs
+
+## Lighting
+
+### *emission*
+
+An array of 3 integers - R, G, B of light in range \[0, 15\]
+
+Examples:
+
+- *\[15, 15, 15\]* - white with maximal intensity
+- *\[7, 0, 0\]* - dim red light
+- *\[0, 0, 0\]* - no emission (default value)
+
+### *light-passing*
+
+Light ignores block if **true**
+
+### *sky-light-passing*
+
+Vertical sky light ray ignores block if **true**. (used for water)
+
+## Physics
+
+### *obstacle*
+
+Block is not a physical obstacle if **false**
+
+### *hitbox*
+
+An array of 6 numbers describing an offset an size of a block hitbox.
+
+Array *\[0.25, 0.0, 0.5, 0.75, 0.4, 0.3\]* describes hitbox width:
+- 0.75m width (from east to west)
+- 0.4m height
+- 0.3m length (from south to north)
+- offset 0.25m east
+- offset 0.0m up
+- offset 0.5m north
+
+### *grounded*
+
+Is block may only be set on a solid block and destructs on below block destruction.
+
+### *selectable*
+
+Cursor ray will ignore block if **false**.
+
+### *replaceable*
+
+Is block replaceable. Examples: air, water, grass, flower.
+
+### *breakable*
+
+Is block breakable by mouse click.
+
+## Inventory
+
+### *hidden*
+
+If **true** an item will not be generated for block. **picking-item** must be specified
+
+### *picking-item*
+
+Item will be chosen on MMB click on the block.
+
+Example: block `door:door_open` is hidden, so you need to specify `picking-item: "door:door.item"` to bind it to not hidden `door:door` block item.
+
+### *script-name*
+
+Used to specify block script name (to reuse one script to multiple blocks). Name must not contain `packid:scripts/` and extension. Just name.
+
+### *ui-layout*
+
+Block UI XML layout name. Default: string block id.
+
+Examples for block `containermod:container`:
+- default: `containermod:container` (*containermod/layouts/container.xml*)
+- if `containermod:randombox` specified: (*containermod/layouts/randombox.xml*)
+
+### *inventory-size*
+
+Number of block inventory slots. Default - 0 (no inventory).
+
diff --git a/doc/en/4.Item-properties.md b/doc/en/4.Item-properties.md
new file mode 100644
index 00000000..bab9769c
--- /dev/null
+++ b/doc/en/4.Item-properties.md
@@ -0,0 +1,39 @@
+# Visual
+
+## *icon-type* and *icon* itself
+
+Icon type defines a source of an item image displayed in inventory.
+- **none** - invisible type, used for *core:empty* only (empty item, like the air block). May be removed in future updates.
+- **sprite** - default type. 2D image. Requires *icon* set to *atlas_name:texture_name*. Example: *blocks:notfound*.
+ There's two atlases available:
+ - **blocks** (generated from *png* files in *res/textures/blocks/*)
+ - **items** (generated from *png* files in *res/textures/items/*)
+- **block** - block preview. Block ID must be specified in **icon** property. Example: *base:wood*.
+
+# Behaviour
+
+## *placing-block*
+
+Specifies what block will be placed on RMB click. Automatically specified in generated items.
+
+Example: an items that places bazalt blocks:
+
+```json
+"placing-block": "base:bazalt"
+```
+
+## *emission*
+
+Light emitted when player holds the item in hand.
+
+An array of 3 integers - R, G, B of light in range \[0, 15\]
+
+Examples:
+
+- *\[15, 15, 15\]* - white with maximal intensity
+- *\[7, 0, 0\]* - dim red light
+- *\[0, 0, 0\]* - no emission (default value)
+
+## *stack-size*
+
+Maximal number of an item units in one slot. Default - 64.
diff --git a/doc/en/5.XML-UI-building.md b/doc/en/5.XML-UI-building.md
new file mode 100644
index 00000000..5fe0efdb
--- /dev/null
+++ b/doc/en/5.XML-UI-building.md
@@ -0,0 +1,102 @@
+# XML UI Building
+
+# Specific types
+
+**2D vector** - pair of numbers separated with comma.
+Examples:
+- "500,200"
+- "0.4,53.01"
+- "0,0"
+
+**3D vector** - three numbers separated with comma.
+Examples:
+- "60,30,53"
+- "0.4,0.1,0.753"
+
+**4D vector** - four numbers separated with comma.
+- "10,5,10,3"
+- "0.1,0.5,0.0,0.0"
+
+**RGBA color** - only HEX notation available
+Examples:
+- "#FF8000" - opaque orange
+- "#FFFFFF80" - semi-transparent white
+- "#000000FF" - opaque black
+
+# Common element attributes
+
+- **id** - element identifier. Type: string.
+- **pos** - element position. Type: 2D vector.
+- **size** - element size. Type: 2D vector.
+- **color** - element color. Type: RGBA color.
+- **margin** - element margin. Type: 4D vector
+ *left, top, right, bottom*
+- **visible** - element visibility. Type: boolean (true/false)
+- **position-func** - position supplier for an element (two numbers), called on every parent container size update or on element adding on a container. May be called before *on_hud_open*
+# Common *container* attributes
+
+Buttons and panels are also containers.
+
+- **padding** - element padding. Type: 4D vector.
+ *left, top, right, bottom*
+ **scrollable** - element scrollability. Works on panels only. Type: boolean
+
+# Common *panel* attributes
+
+Buttons are also panels.
+
+- **max-length** - maximal length of panel stretching before scrolling (if scrollable = true). Type: number
+# Common elements
+
+## *button*
+
+Inner text is a button text.
+
+- **text-align** - inner text alignment (*left/center/right*). Type: string.
+- **onclick** - Lua function called on button press.
+
+## *image*
+
+- **src** - name of an image stored in textures folder. Extension is not specified. Type: string.
+ Example: *gui/error*
+
+## *trackbar*
+
+- **min** - minimal value. Type: number. Default: 0
+- **max** - maximal value. Type: number. Default: 1
+- **value** - initial value. Type: number. Default: 0
+- **step** - track step size. Type: number: Default: 1
+- **track-width** track pointer width (in steps). Type: number. Default: 1
+- **consumer** - Lua function - new value consumer
+- **supplier** - Lua function - value supplier
+
+# Inventory elements
+
+## *inventory*
+
+Element is a container. Does not have specific attributes.
+
+> [!WARNING]
+> Inventories position is controlled by the engine and can not be changed by attributes *pos* and *margin*
+
+## *slot*
+
+Element must be in direct sub-element of *inventory*.
+- **index** - inventory slot index (starting from 0). Type: integer
+- **item-source** - content access panel behaviour (infinite source of an item). Type: boolean
+- **sharefunc** - Lua event called on LMB + Shift. Inventory id and slot index passed as arguments.
+- **updatefunc** - Lua event called on slot content update.Inventory id and slot index passed as arguments.
+- **onrightclick** - Lua event called on RMB click. Inventory id and slot index passed as arguments.
+
+## *slots-grid*
+
+- **start-index** - inventory slot index of the first slot. Type: integer
+- **rows** - number of grid rows (unnecessary if *cols* and *count* specified). Type: integer
+- **cols** - number of grid columns (unnecessary if *rows* and *count* specified). Type: integer
+- **count** - total number of slots in grid (unnecessary if *rows* and *cols* specified). Type: integer
+- **interval** - visual slots interval. Type: number
+- **padding** - grid padding (not slots interval). Type: number. (*deprecated*)
+- **sharefunc** - Lua event called on LMB + Shift. Inventory id and slot index passed as arguments.
+- **updatefunc** - Lua event called on slot content update.Inventory id and slot index passed as arguments.
+- **onrightclick** - Lua event called on RMB click. Inventory id and slot index passed as arguments.
+
diff --git a/doc/en/6.Assets-preloading.md b/doc/en/6.Assets-preloading.md
new file mode 100644
index 00000000..0d3fed0b
--- /dev/null
+++ b/doc/en/6.Assets-preloading.md
@@ -0,0 +1,55 @@
+# Assets preloading (*preload.json* file)
+
+`preload.json` in content-pack folder is used for specifying additional assets should be loaded, like sounds.
+
+The file contains following categories available:
+- fonts
+- shaders
+- textures
+- sounds
+
+> [!NOTE]
+> Sound loading with all variations following template:
+> (sound: *sound_name*) -> *sound_name.ogg, sound_name_1.ogg, sound_name_2.ogg, ...*
+> or *sound_name_0.ogg, sound_name_1.ogg, sound_name_2.ogg, ...*
+
+Adding sound `packid:sounds/events/explosion.ogg` with all variants example:
+```json
+{
+ "sounds": [
+ "events/explosion"
+ ]
+}
+```
+
+Sound will be available as "events/explosion"
+
+Additional load settings example:
+```json
+{
+ "sounds": [
+ {
+ "name": "events/explosion",
+ "keep-pcm": true
+ }
+ ]
+}
+```
+
+*preload.json* example from `core:` package (`res/preload.json`):
+```json
+{
+ "shaders": [
+ "ui3d",
+ "screen",
+ "background",
+ "skybox_gen"
+ ],
+ "textures": [
+ "misc/moon",
+ "misc/sun",
+ "gui/crosshair"
+ ]
+}
+```
+
diff --git a/doc/en/7.Audio.md b/doc/en/7.Audio.md
new file mode 100644
index 00000000..5b810a34
--- /dev/null
+++ b/doc/en/7.Audio.md
@@ -0,0 +1,195 @@
+# Audio
+
+## Definitions
+
+### Backend
+
+Internal audio system implementation controlling audio output.
+- NoAudio - dummy audio used on OpenAL initialize fail or if audio is disabled by the *settings.toml*: *\[audio\] enabled=false*
+- ALAudio - OpenAL audio used
+
+### Channel
+
+Defines a sound sources category for group volume control, effects and pause.
+
+Now the engine has following channels:
+- *master* - controls other channels volume. Should not be used as a target channel when playing an audio.
+- *ui* - ui elements sounds (button clicks and other)
+- *regular* - world sounds, that will be paused with the game.
+- *ambient* - same as *regular* but added for background and ambient sounds/streams like weather.
+- *music* - music channel.
+
+Channels are controlled by the engine and currently are not available in scripts.
+
+### Speaker
+
+One-time use playing audio controller for sound or stream. Speaker is destroying after stop (**stop** method call or audio track end if not looped)
+
+> [!NOTE]
+> Speaker access is performed using 64 bit integer identifiers that **will not be reused** after speaker destruction. You should avoid storing direct references and pointers instead of ID.
+
+Speaker ID starts with 1, so 0 means audio play failure.
+
+### Sound
+
+Audio data loaded in memory to play multiple simultaneous instances from multiple sources. Can give access to loaded PCM data.
+
+### PCMStream (PCM data source)
+
+Stream used by an audio stream as an audio data source. Implementation depends on audio file format, not a backend. This interface may be used to implement network audio stream.
+
+### Stream
+
+Streaming audio. Not fully loading to the memory. Cannot be played via multiple speakers simultaneously.
+
+## Formats support
+
+- WAV: 8 and 16 bit supported (24 bit is not supported by OpenAL)
+- OGG: implemented with libvorbis
+
+## Additional information
+
+> [!WARNING]
+> **Stereo** audio played with OpenAL will ignore 3D position relative to the listener. Sounds that supposed to be played at specific world position must be **mono**
+
+## Scripting Audio API
+
+### Playing audio
+
+Library **audio** contains available Audio API in Lua scripts.
+
+```lua
+audio.play_stream(
+ -- audio file location
+ name: string,
+ -- audio source world position
+ x: number, y: number, z: number,
+ -- audio gain (0.0 - 1.0)
+ volume: number
+ -- audio playback speed (positive number)
+ pitch: number,
+ -- [optional] channel name: regular/ambient/music/ui (default - regular)
+ channel: string,
+ -- [optional] loop stream (default - false)
+ loop: bool
+) -> int
+```
+
+Plays streaming audio from the specified file at the specified world position. Returns speaker ID.
+
+```lua
+audio.play_stream_2d(
+ -- audio file location
+ name: string,
+ -- audio gain (0.0 - 1.0)
+ volume: number
+ -- audio playback speed (positive number)
+ pitch: number,
+ -- [optional] channel name: regular/ambient/music/ui (default - regular)
+ channel: string,
+ -- [optional] loop stream (default - false)
+ loop: bool
+) -> int
+
+```
+
+Plays streaming audio from the specified file. Returns speaker ID.
+
+```lua
+audio.play_sound(
+ -- name of a loaded sound without pack prefix, "sounds/", variant number and extension
+ -- example: "steps/stone" to play sound loaded from "sounds/steps/stone.ogg" or any of its variant
+ -- variant will be randomly chosen
+ name: string,
+ -- audio source world position
+ x: number, y: number, z: number,
+ -- audio gain (0.0 - 1.0)
+ volume: number
+ -- audio playback speed (positive number)
+ pitch: number,
+ -- [optional] channel name: regular/ambient/music/ui (default - regular)
+ channel: string,
+ -- [optional] loop sound (default - false)
+ loop: bool
+) -> int
+```
+
+Plays the specified sound on the specified position in world. Returns speaker ID.
+
+```lua
+audio.play_sound_2d(
+ -- name of a loaded sound without pack prefix, "sounds/", variant number and extension
+ -- example: "steps/stone" to play sound loaded from "sounds/steps/stone.ogg" or any of its variant
+ -- variant will be randomly chosen
+ name: string,
+ -- audio gain (0.0 - 1.0)
+ volume: number
+ -- audio playback speed (positive number)
+ pitch: number,
+ -- [optional] channel name: regular/ambient/music/ui (default - regular)
+ channel: string,
+ -- [optional] loop sound (default - false)
+ loop: bool
+) -> int
+```
+
+Plays the specified sound. Returns speaker ID.
+
+### Speaker interaction
+
+Interaction with a non-existing or destroyed speaker will be ignored.
+
+
+```lua
+-- stop audio playback and destroy the speaker
+audio.stop(speakerid: integer)
+
+-- pause speaker
+audio.pause(speakerid: integer)
+
+-- unpause speaker
+audio.resume(speakerid: integer)
+
+-- set audio loop
+audio.set_loop(speakerid: integer, state: bool)
+
+-- check if audio is in loop (false if does not exists)
+audio.is_loop(speakerid: integer) -> bool
+
+-- get audio gain value (0.0 if does not exists)
+audio.get_volume(speakerid: integer) -> number
+
+-- set audio gain value
+audio.set_volume(speakerid: integer, volume: number)
+
+-- get audio playback speed (1.0 if does not exists)
+audio.get_pitch(speakerid: integer) -> number
+
+-- set audio playback speed
+audio.set_pitch(speakerid: integer, pitch: number)
+
+-- get current audio playback time in seconds (0.0 if does not exists)
+audio.get_time(speakerid: integer) -> number
+
+-- set audio playback time position in seconds
+audio.set_time(speakerid: integer, time: number)
+
+-- get audio source world position (nil if does not exists)
+audio.get_position(speakerid: integer) -> number, number, number
+
+-- set audio source world position
+audio.set_position(speakerid: integer, x: number, y: number, z: number)
+
+-- get audio source movement speed in world (nil if does not exists)
+-- (OpenAL uses it for Doppler effect simulation)
+audio.get_velocity(speakerid: integer) -> number, number, number
+
+-- set audio source movement speed in world
+-- (OpenAL uses it for Doppler effect simulation)
+audio.set_velocity(speakerid: integer, x: number, y: number, z: number)
+
+-- get audio duration
+-- returns 0, if does not exists
+-- also returns 0, if duration is unknown (example: radio)
+audio.get_duration(speakerid: integer) -> number
+```
diff --git a/doc/en/8.Scripting.md b/doc/en/8.Scripting.md
new file mode 100644
index 00000000..80126126
--- /dev/null
+++ b/doc/en/8.Scripting.md
@@ -0,0 +1,523 @@
+# Scripting
+
+Project uses LuaJIT as a scripting language.
+
+## Core functions
+
+```lua
+require "packid:module_name" -- load Lua module from pack-folder/modules/
+-- no extension included, just name
+
+-- deprecated functions
+load_script("packid:scripts/script_name.lua") -- load Lua script if not loaded yet
+load_script("packid:scripts/script_name.lua", true) -- load Lua script anyway
+```
+
+## *player* library
+
+
+```python
+player.get_pos(playerid: int) -> number, number, number
+```
+Returns x, y, z coordinates of the player
+
+```python
+player.set_pos(playerid: int, x: number, y: number, z: number)
+```
+
+Set player position
+
+```python
+player.get_rot(playerid: int) -> number, number
+```
+
+Returns x, y of camera rotation (radians)
+
+```python
+player.set_rot(playerid: int, x: number, y: number, z: number)
+```
+
+Set camera rotation (radians)
+
+```python
+player.get_inventory(playerid: int) -> int, int
+```
+
+Returns player inventory ID and selected slot index (0-9)
+
+## *world* library
+
+```python
+world.get_day_time() -> number
+```
+
+Returns current day time in range \[0.0-1.0\] where 0.0 and 1.0 - midnight, 0.5 - noon.
+
+```python
+world.set_day_time(time: number)
+```
+
+Set day time value.
+
+```python
+world.get_total_time() -> number
+```
+
+Returns total time passed in the world
+
+```python
+world.get_seed() -> int
+```
+
+Returns world seed.
+
+## *gui* library
+
+Library contains ui elements access functions. Library should not be directly used, because script *layouts/layout_name.xml.lua* already has a generated variable **document** (instance of **Document**)
+
+Example:
+
+```lua
+print(document.some_button.text) -- where 'some_button' is an element id
+document.some_button.text = "new text"
+```
+
+## **inventory** library
+
+Library for inventories interaction.
+
+```python
+inventory.get(invid: int, slot: int) -> int, int
+```
+
+Requires an inventory ID and slot index. Returns item ID and count. ID = 0 (core:empty) means that slot is empty.
+
+```python
+inventory.set(invid: int, slot: int, itemid: int, count: int)
+```
+
+Set slot content.
+
+```python
+inventory.size(invid: int) -> int
+```
+
+Returns inventory size (slots number). Throws an exception if there's no inventory having specified ID.
+
+```python
+inventory.add(invid: int, itemid: int, count: int) -> int
+```
+
+Add an item to the specified inventory. Returns remaining count if could not to add fully.
+
+```python
+inventory.get_block(x: int, y: int, z: int) -> int
+```
+
+Returns block inventory ID or 0.
+
+```python
+inventory.bind_block(invid: int, x: int, y: int, z: int)
+```
+
+Bind inventory to the specified block.
+
+```python
+inventory.unbind_block(x: int, y: int, z: int)
+```
+
+Unbind inventory from the specified block.
+
+> [!WARNING]
+> Unbound inventories will be deleted on world close.
+
+```python
+inventory.clone(invid: int) -> int
+```
+
+Create inventory copy. Returns the created copy ID.
+
+## *block* library
+
+```python
+block.name(blockid: int) -> str
+```
+
+Returns block string ID (name) by index
+
+```python
+block.index(name: str) -> int
+```
+
+Returns block integer ID (index) by name
+
+```python
+block.get(x: int, y: int, z: int) -> int
+```
+
+Returns integer ID by block position
+
+```python
+block.get_states(x: int, y: int, z: int) -> int
+```
+
+Returns block state (rotation + additional information) as an integer.
+
+```python
+block.set(x: int, y: int, z: int, id: int, states: int)
+```
+
+Set block with specified integer ID and state (default - 0) at specified position.
+
+> [!WARNING]
+> `block.set` does not trigger on_placed.
+
+```python
+block.is_solid_at(x: int, y: int, z: int) -> bool
+```
+
+Check if block at the specified position is solid.
+
+```python
+block.is_replaceable_at(x: int, y: int, z: int) -> bool
+```
+Check if block may be placed at specified position. (Examples: air, water, grass, flower)
+
+```python
+block.defs_count() -> int
+```
+
+Returns count of available block IDs.
+
+Following three functions return direction vectors based on block rotation.
+
+
+```python
+block.get_X(x: int, y: int, z: int) -> int, int, int
+```
+
+Returns X: integer direction vector of the block at specified coordinates.
+Example: no rotation: 1, 0, 0
+
+```python
+block.get_Y(x: int, y: int, z: int) -> int, int, int
+```
+
+Returns Y: integer direction vector of the block at specified coordinates.
+Example: no rotation: 0, 1, 0
+
+```python
+block.get_Z(x: int, y: int, z: int) -> int, int, int
+```
+
+Returns Z: integer direction vector of the block at specified coordinates.
+Example: no rotation: 0, 0, 1
+
+### User bits
+
+Part of a voxel data used for scripting. Size: 8 bit.
+
+```python
+block.get_user_bits(x: int, y: int, z: int, offset: int, bits: int) -> int
+```
+
+Get specified bits as an unsigned integer.
+
+```python
+block.set_user_bits(x: int, y: int, z: int, offset: int, bits: int, value: int) -> int
+```
+Set specified bits.
+
+## *item* library
+
+
+```python
+item.name(itemid: int) -> str
+```
+
+Returns item string ID (name) by index
+
+```python
+item.index(name: str) -> int
+```
+
+Returns item integer ID (index) by name
+
+```python
+item.stack_size(itemid: int) -> int
+```
+
+Returns max stack size for the item
+
+```python
+item.defs_count() -> int
+```
+
+Returns count of available item IDs.
+
+## *hud* library
+
+
+```python
+hud.open_inventory()
+```
+
+Open player inventory
+
+```python
+hud.close_inventory()
+```
+
+Close inventory
+
+```python
+hud.open_block(x: int, y: int, z: int) -> int, str
+```
+
+Open block UI and inventory. Throws an exception if block has no UI layout.
+
+Returns block inventory ID (if *"inventory-size"=0* a virtual inventory will be created), and UI layout ID.
+
+> [!NOTE]
+> Only one block may be open at same time
+
+```python
+hud.open_permanent(layoutid: str)
+```
+
+Add element to the screen. The element will be removed on world close only.
+**inventory** element will be bound to the player inventory.
+
+```python
+hud.close(layoutid: str)
+```
+
+Remove an element from the screen
+
+## Block events
+
+```lua
+function on_placed(x, y, z, playerid)
+```
+
+Called on block placed by player
+
+```lua
+function on_broken(x, y, z, playerid)
+```
+
+Called on block broken by player
+
+```lua
+function on_interact(x, y, z, playerid) -> bool
+```
+
+Called on block RMB click interaction. Prevents block placing if **true** returned.
+
+```lua
+function on_update(x, y, z)
+```
+
+Called on block update (near block changed)
+
+```lua
+function on_random_update(x, y, z)
+```
+
+Called on random block update (grass growth)
+
+```lua
+function on_blocks_tick(tps: int)
+```
+
+Called tps (20) times per second.
+
+## Item events
+
+```lua
+function on_use(playerid: int)
+```
+
+Called on RMB click out of a block.
+
+```lua
+function on_use_on_block(x: int, y: int, z: int, playerid: int)
+```
+
+Called on block RMB click. Prevents block **placing-block** placing if returns **true**
+
+```lua
+function on_block_break_by(x: int, y: int, z: int, playerid: int)
+```
+
+Called on block LMB click (unbreakable blocks included). Prevents block destruction if returns **true**.
+
+## World events
+
+Script *scripts/world.lua* events.
+
+```lua
+function on_world_open()
+```
+
+Called on world open.
+
+```lua
+function on_world_save()
+```
+
+Called before world save.
+
+```lua
+function on_world_tick()
+```
+
+Called 20 times per second
+
+```lua
+function on_world_quit()
+```
+
+Called on world close (after saving)
+
+## Layout events
+
+Script *layouts/layout_name.xml.lua* events.
+
+```lua
+function on_open(invid: int, x: int, y: int, z: int)
+```
+
+Called on element added to the screen.
+invid=0 if no inventory bound
+x,y,z=0 if no block bound
+
+```lua
+function on_close(invid: int)
+```
+
+Called on element removed from the screen.
+
+## HUD events
+
+Script *scripts/hud.lua* events.
+
+
+```lua
+function on_hud_open(playerid: int)
+```
+
+Called after world open.
+
+```lua
+function on_hud_close(playerid: int)
+```
+
+Called on world close (before saving)
+
+## Engine libraries
+
+### file
+
+Filesystem interaction library.
+
+```python
+file.resolve(path: str) -> str
+```
+
+Function turns *entry_point:path* (example *user:worlds/house1*) to a regular path. (example *C://Users/user/.voxeng/worlds/house1*)
+
+> [!NOTE]
+> The function should be used for debug only. *entry_point:path* notation is required in all **file** functions.
+
+Resulting path is not canonical and may be relative.
+
+```python
+file.read(path: str) -> str
+```
+
+Read whole text file.
+
+```python
+file.read_bytes(path: str) -> array of integers
+```
+
+Read file into bytes array.
+
+```python
+file.write(path: str, text: str) -> nil
+```
+
+Overwrite text file.
+
+```python
+file.write_bytes(path: str, data: array of integers)
+```
+
+Overwrite binary file with bytes array.
+
+```python
+file.length(path: str) -> int
+```
+
+Get file length (bytes) or 0.
+
+```python
+file.exists(path: str) -> bool
+```
+
+Check if file or directory exist.
+
+```python
+file.isfile(path: str) -> bool
+```
+
+Check if the path points to a file.
+
+```python
+file.isdir(path: str) -> bool
+```
+
+Check if the path points to a directory.
+
+```python
+file.mkdir(path: str) -> bool
+```
+
+Create directory. Returns true if new directory created
+
+```python
+file.mkdirs(path: str) -> bool
+```
+
+Create directories chain. Returns true if new directory created
+
+### time
+
+```python
+time.uptime() -> float
+```
+
+Returns time elapsed since the engine started.
+
+## Available modules
+
+### TOML serialization/deserialization
+
+```lua
+local toml = require "core:toml"
+
+local t = {a=53, b=42, s="test", sub={x=1, y=6}}
+local s = toml.serialize(t)
+print(s)
+local t2 = toml.deserialize(s)
+```
+output:
+```toml
+b = 42
+s = "test"
+a = 53
+[sub]
+y = 6
+x = 1
+```
diff --git a/doc/en/9.Block-models.md b/doc/en/9.Block-models.md
new file mode 100644
index 00000000..c6fe7f19
--- /dev/null
+++ b/doc/en/9.Block-models.md
@@ -0,0 +1,20 @@
+# Block Models
+
+Block model may be created with following properties:
+
+```js
+"model": "custom",
+"model-primitives": {
+ "aabbs": [
+ // list of AABB primitives
+ ],
+ // ... other primitives
+}
+```
+
+**AABB** primitive is an array of values:
+```
+[x, y, z, width, height, depth, texture names for all 6 sides]
+```
+
+**tetragon** primitive (more like parallelogram) an array of three vectors, describing primitive position, X vector \* width, Y vector \* height.
diff --git a/doc/ru/0.Главная.md b/doc/ru/0.Главная.md
new file mode 100644
index 00000000..ae961c9e
--- /dev/null
+++ b/doc/ru/0.Главная.md
@@ -0,0 +1,13 @@
+# Разделы
+
+- [Рекомендации по использованию движка](1.Рекомендации-по-использованию-движка.md)
+- [Контент‐паки](2.Контент‐паки.md)
+- [Свойства блоков](3.Свойства-блоков.md)
+- [Свойства предметов](4.Свойства-предметов.md)
+- [XML разметка интерфейса](5.XML-разметка-интерфейса.md)
+- [Предзагрузка ассетов](6.Предзагрузка-ассетов.md)
+- [Аудио](7.Аудио.md)
+- [Скриптинг](8.Скриптинг.md)
+ - [Модуль core:bit_converter](8.1.Модуль-Lua-core_bit_converter.md)
+ - [Модуль core:data_buffer](8.2.Модуль-Lua-core_data_buffer.md)
+- [Модели блоков](9.Модели-блоков.md)
diff --git a/doc/ru/1.Рекомендации-по-использованию-движка.md b/doc/ru/1.Рекомендации-по-использованию-движка.md
new file mode 100644
index 00000000..92737140
--- /dev/null
+++ b/doc/ru/1.Рекомендации-по-использованию-движка.md
@@ -0,0 +1,30 @@
+# Рекомендации по использованию движка
+
+## Наименование контента
+
+### ID контент-паков
+
+Идентификатор контент-пака должен следовать следующим требованиям:
+- название может состоять только из букв латиницы, цифр и символа подчёркивания '\_'
+- название не может начинаться с цифры
+- длина названия должна находиться в пределах от 2 до 24 включительно
+
+### Блоки и предметы
+
+- id блоков и предметов следуют тем же требованиям, что и ID контент-пака.
+- окончание `.item` добавляется только для замены сгенерированного для блока предмета. Пример: `base:stone.item` - предмет сгенерированный для блока камня.
+- поле **caption**, предназначенное для отображения названия в инвентаре, не указывается с заглавной буквы, без необходимости. Движок автоматически повышает регистр при отображении в интерфейсе.
+
+## Хранение файлов
+
+### Данные контент-паков
+
+Настройки, состояние, которое нужно сохранять в мире, должны находиться в `world:data/id_пака/`. Путь следует получать через специальную функцию:
+```lua
+local path = pack.data_file(PACK_ID, "имя_файла")
+file.write(path, данные)
+-- запишет данные в файл world:data/PACK_ID/имя_файла
+```
+Здесь PACK_ID является доступной константой, т.е не нужно вписывать имя пака самостоятельно.
+
+Папка `world:data/PACK_ID` будет создана при вызове `pack.data_file`.
\ No newline at end of file
diff --git a/doc/ru/2.Контент‐паки.md b/doc/ru/2.Контент‐паки.md
new file mode 100644
index 00000000..f89c1f39
--- /dev/null
+++ b/doc/ru/2.Контент‐паки.md
@@ -0,0 +1,39 @@
+# Контент-паки
+
+Для создания контент-пака сначала нужно придумать ему название (id) соответствующее следующим требованиям:
+- название может состоять только из букв латиницы, цифр и символа подчёркивания '\_'
+- название не может начинаться с цифры
+- длина названия должна находиться в пределах от 2 до 24 включительно
+
+Далее в *res/content* создаётся папка с выбранным названием контент-пака.
+
+В созданной папке создаётся файл **package.json** с следующим содержимым:
+```json
+{
+ "id": "выбранное_имя_пака",
+ "title": "имя контент-пака для отображения в меню контента",
+ "version": "версия контент-пака в формате major.minor",
+ "creator": "создатель контент-пака",
+ "description": "краткое описание",
+ "dependencies": [
+ "зависимости",
+ "пакета"
+ ]
+}
+```
+
+Пример:
+```json
+{
+ "id": "doors",
+ "title": "DOORS",
+ "creator": "MihailRis",
+ "version": "1.0",
+ "description": "doors test"
+}
+```
+
+Изображение контент-пака добавляется в виде файла *icon.png* в папку пака (не в textures). Рекомендованный размер изображения: 128x128
+
+Новые блоки добавляются в под-папку **blocks**, предметы в **items**, текстуры в **textures**
+С примером файловой структуры лучше ознакомиться через базовый пакет (*res/content/base*)
diff --git a/doc/ru/3.Свойства-блоков.md b/doc/ru/3.Свойства-блоков.md
new file mode 100644
index 00000000..c1cc2bda
--- /dev/null
+++ b/doc/ru/3.Свойства-блоков.md
@@ -0,0 +1,131 @@
+# Вид
+
+## Текстура - `texture`
+
+Название текстуры блока (указывается только имя, без расширения или пути к файлу)
+
+Файл текстуры должен находиться в `res/textures/blocks/` и иметь формат **png**
+
+## Текстурирование сторон - `texture-faces`
+
+>[!IMPORTANT]
+> Не может использоваться одновременно с `texture`
+
+Массив из 6 названий текстур, позволяющих указать их для каждой из сторон отдельно.
+
+Пример:
+```json
+"texture-faces": [
+ "grass_side",
+ "grass_side",
+ "dirt",
+ "grass_top",
+ "grass_side",
+ "grass_side"
+]
+```
+
+## Модель - `model`
+
+Модель блока из списка:
+- "block" - используется по-умолчанию для всех обычных блоков
+- "none" - невидимый блок (пример: воздух)
+- "X" - модель травы (крест из двух спрайтов)
+- "aabb" - модель, соответствующая хитбоксу блока (составной хитбокс будет объединен в один). Примеры: трубы, лампочки, панели.
+
+## Группа отрисовки - `draw-group`
+
+Целое число определяющее номер группы отрисовки данного блока.
+Актуально для полупрозрачных блоков - решает проблемы невидимых сторон блоков за этим блоком.
+
+## Вращение - `rotation`
+
+Профиль вращения (набор положений, в которые можно установить блок) из списка:
+
+- "none" - вращение блока отключено (по-умолчанию)
+- "pipe" - профиль "труба". Примеры блоков: бревно, труба, лампочка
+- "pane" - профиль "панель". Примеры блоков: панель, дверь, табличка
+
+# Освещение
+
+## Излучение - `emission`
+
+Массив из трех целых чисел - R, G, B освещения от 0 до 15.
+
+Примеры:
+
+- `[15, 15, 15]` - самый яркий белый свет
+- `[7, 0, 0]` - слабый красный свет
+- `[0, 0, 0]` - блок не излучает свет (по-умолчанию)
+
+
+## Светопроводимость - `light-passing`
+
+При значении `true` блок проводит свет от излучающих блоков.
+
+## Солнечная светопроводимость - `sky-light-passing`
+
+При значении `true` блок не препятствует прохождению вертикального луча солнечного света.
+
+# Физика
+
+## Препятствие - `obstacle`:
+
+Значение false отключает хитбокс у блока (позволяет игроку проходить сквозь блок)
+
+## Хитбокс - `hitbox`:
+
+Массив из 6 чисел описывающих смещение и размер хитбокса блока.
+
+Числа указываются в диапазоне [0.0, 1.0] - т.е в пределах блока.
+
+Массив `[0.25, 0.0, 0.5, 0.75, 0.4, 0.3]` описывает хитбокс:
+- шириной (с востока на запад) 0.75 м
+- высотой 0.4 м
+- длиной (с юга на север) 0.3 м
+- смещен на 0.25 м на запад
+- смещен на 0.0 м вверх
+- смещен на 0.5 м на север
+
+## Приземленность - `grounded`
+
+Блок может быть установлен только на полный блок.
+Разрушается при разрушении блока под ним.
+
+## Выделяемость - `selectable`
+
+При значении в `false` курсор будет игнорировать блок, выделяя тот, что находится за ним.
+
+## Заменяемость - `replaceable`
+
+При значении в `true` на месте блока можно установить любой другой блок. Пример: вода, трава, цветок.
+
+## Разрушаемость - `breakable`
+
+При значении в `false` блок нельзя сломать.
+
+# Инвентарь
+
+## Скрытый блок - `hidden`
+
+При значении в `true` блок не появляется в инвентаре и для него не генерируется предмет, поэтому c 0.17 требуется указать свойство `picking-item`
+
+## Подбираемый предмет - `picking-item`
+
+Предмет, который будет выбран при при нажатии средней кнопкой мыши на блок.
+
+Пример: блок `door:door_open` скрыт (hidden) поэтому указывается `picking-item: "door:door.item"`
+
+## Имя скрипта - `script-name`
+
+Позволяет указать название скрипта блока. Свойство обеспечивает возможность использования одного скрипта для нескольких блоков.
+Название указывается без `пак:scripts/` и расширения.
+
+## Имя макета UI - `ui-layout`
+
+Позволяет указать id XML-макета интерфейса блока. По-умолчанию используется строковый id блока.
+
+## Размер инвентаря - `inventory-size`
+
+Число слотов инвентаря блока. По-умолчанию - 0 (инвентарь отсутствует)
+
diff --git a/doc/ru/4.Свойства-предметов.md b/doc/ru/4.Свойства-предметов.md
new file mode 100644
index 00000000..180aef4a
--- /dev/null
+++ b/doc/ru/4.Свойства-предметов.md
@@ -0,0 +1,38 @@
+# Вид
+
+## Тип иконки - `icon-type` и сама иконка - `icon`
+
+В последней версии движка существуют следующие типы иконок предметов, определяющих то, как предмет будет отображаться в инвентаре:
+- `none` - невидимый тип, используется только для `core:empty` (пустой предмет). Не влияет на появление предмета на панель доступа к контенту. Тип может быть удалён в будущем
+- `sprite` - 2D изображение. Требуется указание свойства icon, состоящее из имени атласа и имени текстуры в этом атласе, разделённые `:`. Пример: `blocks:notfound`. На данный момент в движке существует два текстурных атласа:
+ - blocks (генерируется из png файлов в `res/textures/blocks/`)
+ - items (генерируется из png файлов в `res/textures/items/`)
+- `block` - отображает предпросмотр блока. В icon указывается строковый id блока который нужно отображать. Пример `base:wood`
+
+# Поведение
+
+## Устанавливаемый блок - `placing-block`
+
+При указании строкового id блока предмет устанавливает его при нажатии ПКМ. Именно это свойство используется у всех сгенерированных для блоков предметов.
+
+Пример: предмет ставит блоки базальта:
+
+```json
+"placing-block": "base:bazalt"
+```
+
+## Излучение - `emission`
+
+Влияет на свет излучаемый предметом, когда он находится в руке игрока.
+
+Массив из трех целых чисел - R, G, B освещения от 0 до 15.
+
+Примеры:
+
+- `[15, 15, 15]` - самый яркий белый свет
+- `[7, 0, 0]` - слабый красный свет
+- `[0, 0, 0]` - предмет не излучает свет (по-умолчанию)
+
+## Размер стопки (стека) - `stack-size`
+
+Определяет максимальное количество предмета в одном слоте. Значение по-умолчанию - 64.
diff --git a/doc/ru/5.XML-разметка-интерфейса.md b/doc/ru/5.XML-разметка-интерфейса.md
new file mode 100644
index 00000000..27d07be1
--- /dev/null
+++ b/doc/ru/5.XML-разметка-интерфейса.md
@@ -0,0 +1,113 @@
+# XML разметка интерфейса
+
+# Специфические типы
+
+**2D вектор** - пара чисел, разделенная запятой.
+Примеры:
+- `"500,200"`
+- `"0.4,53.01"`
+- `"0,0"`
+
+**3D вектор** - три числа, разделенная запятой.
+Примеры:
+- `"60,30,53"`
+- `"0.4,0.1,0.753"`
+
+**4D вектор** - четыре числа, разделенная запятой.
+Примеры:
+- `"10,5,10,3"`
+- `"0.1,0.5,0.0,0.0"`
+
+**RGBA цвет** - на данный момент доступна только HEX запись.
+Примеры:
+- `"#FF8000"` - оранжевый непрозрачный
+- `"#FFFFFF80"` - белый полупрозрачный
+- `"#000000FF"` - черный непрозрачный
+
+# Общие атрибуты элементов
+
+- `id` - идентификатор элемента. Тип: строка.
+- `pos` - позиция элемента. Тип: 2D вектор.
+- `size` - размер элемента. Тип: 2D вектор.
+- `color` - цвет элемента. Тип: RGBA цвет.
+- `margin` - внешний отступ элемента. Тип: 4D вектор.
+ Порядок: `"left,top,right,bottom"`
+- `visible` - видимость элемента. Тип: логический ("true"/"false").
+- `position-func` - поставщик позиции элемента (два числа), вызываемый при изменении размера контейнера, в котором находится элемент, либо при добавлении элемента в контейнер. Может быть вызван до вызова on_hud_open.
+
+# Общие атрибуты контейнеров
+
+В число контейнеров также входят панели и кнопки.
+- `padding` - внутренний отступ элемента. Тип: 4D вектор.
+ Порядок: `"left,top,right,bottom"`
+- `scrollable` - возможность скроллинга. Работает только у Panel. Тип: логический.
+
+# Общие атрибуты панелей
+
+В число панелей также входят кнопки.
+- `max-length` - максимальная длина, на которую растягивается панель до начала скроллинга (если scrollable = true). Тип: число
+
+# Основные элементы
+
+## Кнопка `button`
+
+Внутренний текст - текст кнопки.
+
+- `text-align` - выравнивание текста ("left", "center" или "right"). Тип: строка.
+- `onclick` - lua функция вызываемая при нажатии на кнопку.
+
+## Изображение `image`
+
+- `src` - имя изображения в папке textures без указания расширения. Тип: строка. Например `gui/error`
+
+## Изображение `image`
+
+- `src` - имя изображения в папке textures без указания расширения. Тип: строка. Например `gui/error`
+
+# Текстовое поле `textbox`
+
+Внутренний текст - изначально введенный текст
+
+- `placeholder` - текст подстановки (используется текстовое поле пусто)
+- `consumer` - lua функция-приемник введенного текста. Вызывается только при завершении ввода
+
+## Ползунок `trackbar`
+
+- `min` - минимальное значение. Тип: число. По-умолчанию: 0
+- `max` - максимальное значение. Тип: число. По-умолчанию: 1
+- `value` - изначальное значение. Тип: число. По-умолчанию: 0
+- `step` - размер деления ползунка. Тип: число. По-умолчанию: 1
+- `track-width` - ширина указателя (в делениях). Тип: число. По-умолчанию: 1
+- `consumer` - lua функция-приемник установленного значения
+- `supplier` - lua функция-поставщик значения
+
+# Элементы инвентаря
+
+## Инвентарь `inventory`
+
+Элемент является контейнером. На данный момент не имеет специфических атрибутов.
+
+> [!WARNING]
+> Расположение инвентарей управляется движком и не может быть изменено свойствами pos, margin и т.д.
+
+## Одиночный слот `slot`
+
+Элемент должен находиться внутри `inventory` элемента, без посредников.
+- `index` - индекс слота инвентаря. (Нумерация с 0)
+- `item-source` - включает поведение подобное панели контента. Тип: логический
+- `sharefunc` - lua событие вызываемое при использовании ЛКМ + Shift. Передается id инвентаря и индекс слота
+- `updatefunc` - lua событие вызываемое при изменении содержимого слота
+- `onrightclick` - lua событие вызываемое при использовании ПКМ. Передается id инвентаря и индекс слота
+
+## Решетка слотов `slots-grid`
+
+Элемент должен находиться внутри `inventory` элемента, без посредников.
+- `start-index` - индекс первого слота
+- `rows` - число рядов (не указывается, если указано cols).
+- `cols` - число столбцов (не указывается, если указано rows).
+- `count` - общее число слотов (не указывается, если указаны rows и cols).
+- `interval` - интервал между слотами. Тип: число.
+- `padding` - отступ вокруг решетки слотов. Тип: число. (*атрибут будет удален*)
+- `sharefunc` - lua событие вызываемое при использовании ЛКМ + Shift. Передается id инвентаря и индекс слота
+- `updatefunc` - lua событие вызываемое при изменении содержимого слота
+- `onrightclick` - lua событие вызываемое при использовании ПКМ. Передается id инвентаря и индекс слота
\ No newline at end of file
diff --git a/doc/ru/6.Предзагрузка-ассетов.md b/doc/ru/6.Предзагрузка-ассетов.md
new file mode 100644
index 00000000..5b56757a
--- /dev/null
+++ b/doc/ru/6.Предзагрузка-ассетов.md
@@ -0,0 +1,54 @@
+# Предзагрузка ассетов (файл *preload.json*)
+
+Для загрузки ассетов, не загружаемых автоматически, такие как звуки, дополнительные текстуры, используется файл `preload.json`, создающийся в папке контент-пака.
+
+Ассеты в файле разделяются на категории:
+- fonts - шрифты
+- shaders - шейдеры
+- textures - текстуры
+- sounds - звуки
+
+> [!NOTE]
+> При загрузке звука подгружаются все его вариации, по шаблону:
+> (звук: sound_name) -> *sound_name.ogg, sound_name_1.ogg, sound_name_2.ogg, ...*
+> или *sound_name_0.ogg, sound_name_1.ogg, sound_name_2.ogg, ...*
+
+Добавление звука `пак:sounds/events/explosion.ogg` со всеми его вариантами:
+```json
+{
+ "sounds": [
+ "events/explosion"
+ ]
+}
+```
+Будет доступен под именем: "events/explosion"
+
+В случае, если нужно будет работать с PCM данными звука (сейчас не доступно из скриптинга), требуется указать параметр `keep-pcm`:
+```json
+{
+ "sounds": [
+ {
+ "name": "events/explosion",
+ "keep-pcm": true
+ }
+ ]
+}
+```
+
+
+Пример файла из пакета `core:` (`res/preload.json`):
+```json
+{
+ "shaders": [
+ "ui3d",
+ "screen",
+ "background",
+ "skybox_gen"
+ ],
+ "textures": [
+ "misc/moon",
+ "misc/sun",
+ "gui/crosshair"
+ ]
+}
+```
\ No newline at end of file
diff --git a/doc/ru/7.Аудио.md b/doc/ru/7.Аудио.md
new file mode 100644
index 00000000..66dfb311
--- /dev/null
+++ b/doc/ru/7.Аудио.md
@@ -0,0 +1,196 @@
+# Аудио
+
+## Основные понятия
+
+### Бекенд (Backend)
+
+Вариант внутренней реализации звуковой подсистемы, управляющий выводом звука.
+На данный момент в движке существует два:
+- NoAudio - заглушка, используемая при невозможности инициализации OpenAL, либо, при отключенной через файл настроек, аудиосистеме: `[audio] enabled=false`. Данный бекенд загружает PCM данные только по требованию, не создает спикеров при попытке воспроизведения аудио.
+- ALAudio - основной вариант. Вывод звука через OpenAL.
+
+### Канал (Channel)
+
+Определяет категорию источников аудио для регулирования громкости, наложения эффектов, паузы.
+На данный момент существует следующий набор каналов:
+- master - управляет громкостью остальных каналов. Не следует указывать как целевой канал при воспроизведении аудио.
+- ui - звуки интерфейса
+- regular - звуки игрового мира, ставятся на паузу вместе с игрой.
+- ambient - то же, что и regular, но предназначается для фоновых звуков: погода и иной эмбиент.
+- music - канал для воспроизведения музыки. Как правило, потокового аудио.
+
+Каналы управляются самим движком.
+### Спикер (Speaker)
+
+Одноразовый контроллер проигрываемого аудио: звука или потока. Спикер уничтожается после остановки через вызов метода **stop** или при окончании аудио (поток также не удерживает спикер от уничтожения).
+Контроллер продолжает жить при паузе.
+
+> [!NOTE]
+Доступ к спикерам производится по целочисленным id, которые не повторяются за время работы движка, следует избегать хранения прямых указателей на объекты класса.
+
+Нумерация ID спикеров начинается с 1. ID 0 означает невозможность воспроизведения, по какой-либо причине.
+### Звук (Sound)
+
+Звуковые данные загруженные в память для возможности одновременного воспроизведения из нескольких источников. Может предоставлять доступ к PCM данным.
+
+### Источник PCM (PCMStream)
+
+Поток, используемый потоком как источник PCM-данных. Реализация зависит не от бекенда звуковой системы, а от формата файла. Реализация потокового аудио из сетевого соединения делается через реализацию данного интерфейса.
+
+### Поток (Stream)
+
+Потоковое аудио. Не загружается полностью в память, поэтому не требует предзагрузки через `preload.json`. Не может воспроизводиться через несколько спикеров одновременно.
+
+## Поддержка форматов
+
+На данный момент реализована поддержка двух форматов.
+- WAV: поддерживаются 8 и 16 bit (24 bit не поддерживается OpenAL)
+- OGG: реализовано через библиотеку libvorbis
+
+
+## Дополнительно
+
+> [!WARNING]
+> При воспроизведении через OpenAL стерео звуки не будут учитывать расположение источников относительно игрока. Звуки, которые должны учитывать расположение, должны быть в моно.
+
+## API аудио в скриптинге
+
+### Воспроизведение аудио
+
+Работа с аудио производится с библиотекой `audio`.
+
+```lua
+audio.play_stream(
+ -- путь к аудио-файлу
+ name: string,
+ -- позиция источника аудио в мире
+ x: number, y: number, z: number,
+ -- громкость аудио (от 0.0 до 1.0)
+ volume: number
+ -- скорость воспроизведения (положительное число)
+ pitch: number,
+ -- [опционально] имя канала: regular/ambient/music/ui (по-умолчанию - regular)
+ channel: string,
+ -- [опционально] зацикливание потока (по-умолчанию - false)
+ loop: bool
+) -> int
+```
+
+Воспроизводит потоковое аудио из указанного файла, на указанной позиции в мире. Возвращает id спикера.
+
+```lua
+audio.play_stream_2d(
+ -- путь к аудио-файлу
+ name: string,
+ -- громкость аудио (от 0.0 до 1.0)
+ volume: number
+ -- скорость воспроизведения (положительное число)
+ pitch: number,
+ -- [опционально] имя канала: regular/ambient/music/ui (по-умолчанию - regular)
+ channel: string,
+ -- [опционально] зацикливание потока (по-умолчанию - false)
+ loop: bool
+) -> int
+```
+
+Воспроизводит потоковое аудио из указанного файла. Возвращает id спикера.
+
+
+```lua
+audio.play_sound(
+ -- название загруженного звука без префикса пака, "sounds/", номера варианта и расширения
+ -- пример "steps/stone" для проигрывания звука, загруженного из "sounds/steps/stone.ogg" или любого из его вариантов
+ -- вариант звука выбирается случайно
+ name: string,
+ -- позиция источника аудио в мире
+ x: number, y: number, z: number,
+ -- громкость аудио (от 0.0 до 1.0)
+ volume: number
+ -- скорость воспроизведения (положительное число)
+ pitch: number,
+ -- [опционально] имя канала: regular/ambient/music/ui (по-умолчанию - regular)
+ channel: string,
+ -- [опционально] зацикливание потока (по-умолчанию - false)
+ loop: bool
+) -> int
+```
+
+Воспроизводит звук на указанной позиции в мире. Возвращает id спикера.
+
+```lua
+audio.play_sound_2d(
+ -- название загруженного звука без префикса пака, "sounds/", номера варианта и расширения
+ -- пример "steps/stone" для проигрывания звука, загруженного из "sounds/steps/stone.ogg" или любого из его вариантов
+ -- вариант звука выбирается случайно
+ name: string,
+ -- громкость аудио (от 0.0 до 1.0)
+ volume: number
+ -- скорость воспроизведения (положительное число)
+ pitch: number,
+ -- [опционально] имя канала: regular/ambient/music/ui (по-умолчанию - regular)
+ channel: string,
+ -- [опционально] зацикливание потока (по-умолчанию - false)
+ loop: bool
+) -> int
+```
+
+Воспроизводит звук. Возвращает id спикера.
+
+### Взаимодействие со спикером.
+
+При обращении к несуществующим спикером ничего происходить не будет.
+
+```lua
+-- остановить воспроизведение спикера
+audio.stop(speakerid: integer)
+
+-- поставить спикер на паузу
+audio.pause(speakerid: integer)
+
+-- снять спикер с паузы
+audio.resume(speakerid: integer)
+
+-- установить зацикливание аудио
+audio.set_loop(speakerid: integer, state: bool)
+
+-- проверить, зациклено ли аудио (false если не существует)
+audio.is_loop(speakerid: integer) -> bool
+
+-- получить громкость спикера (0.0 если не существует)
+audio.get_volume(speakerid: integer) -> number
+
+-- установить громкость спикера
+audio.set_volume(speakerid: integer, volume: number)
+
+-- получить скорость воспроизведения (1.0 если не существует)
+audio.get_pitch(speakerid: integer) -> number
+
+-- установить скорость воспроизведения
+audio.set_pitch(speakerid: integer, pitch: number)
+
+-- получить временную позицию аудио в секундах (0.0 если не существует)
+audio.get_time(speakerid: integer) -> number
+
+-- установить временную позицию аудио в секундах
+audio.set_time(speakerid: integer, time: number)
+
+-- получить позицию источника звука в мире (nil если не существует)
+audio.get_position(speakerid: integer) -> number, number, number
+
+-- установить позицию источника звука в мире
+audio.set_position(speakerid: integer, x: number, y: number, z: number)
+
+-- получить скорость движения источника звука в мире (nil если не существует)
+-- (используется OpenAL для имитации эффекта Доплера)
+audio.get_velocity(speakerid: integer) -> number, number, number
+
+-- установить скорость движения источника звука в мире
+-- (используется OpenAL для имитации эффекта Доплера)
+audio.set_velocity(speakerid: integer, x: number, y: number, z: number)
+
+-- получить длительность аудио в секуднах, проигрываемого источником
+-- возвращает 0, если не спикер не существует
+-- так же возвращает 0, если длительность неизвестна (пример: радио)
+audio.get_duration(speakerid: integer) -> number
+```
+
diff --git a/doc/ru/8.1.Модуль-Lua-core_bit_converter.md b/doc/ru/8.1.Модуль-Lua-core_bit_converter.md
new file mode 100644
index 00000000..cf2126c6
--- /dev/null
+++ b/doc/ru/8.1.Модуль-Lua-core_bit_converter.md
@@ -0,0 +1,91 @@
+## Конвертация значений в байты и обратно
+
+```lua
+function bit_converter.string_to_bytes(string: str) -> table
+```
+Конвертирует строку в байты
+
+```lua
+function bit_converter.bool_to_byte(boolean: bool) -> integer
+```
+Конвертирует логический булев в байт
+
+```lua
+function bit_converter.single_to_bytes(number: single) -> table
+```
+Конвертирует плавающее значение одинарной точности в байты
+
+```lua
+function bit_converter.double_to_bytes(number: double) -> table
+```
+Конвертирует плавающее значение двойной точности в байты
+
+```lua
+function bit_converter.uint16_to_bytes(integer: int) -> table
+```
+Конвертирует беззнаковое 2-х битное целое число в байты
+
+```lua
+function bit_converter.uint32_to_bytes(integer: int) -> table
+```
+Конвертирует беззнаковое 4-х битное целое число в байты
+
+```lua
+function bit_converter.int16_to_bytes(integer: int) -> table
+```
+Конвертирует знаковое 2-х битное целое число в байты
+
+```lua
+function bit_converter.int32_to_bytes(integer: int) -> table
+```
+Конвертирует знаковое 4-х битное целое число в байты
+
+```lua
+function bit_converter.int64_to_bytes(integer: int) -> table
+```
+Конвертирует знаковое 8-и битное целое число в байты
+
+```lua
+function bit_converter.bytes_to_string(table: bytes) -> string
+```
+Конвертирует массив байтов в строку
+
+```lua
+function bit_converter.byte_to_bool(integer: byte) -> boolean
+```
+Конвертирует байт в логическое булевое значение
+
+```lua
+function bit_converter.bytes_to_single(table: bytes) -> number№
+```
+Конвертирует массив байтов в плавающее число одинарной точности
+
+```lua
+function bit_converter.bytes_to_double(table: bytes) -> number
+```
+Конвертирует массив байтов в плавающее число двойной точности
+
+```lua
+function bit_converter.bytes_to_uint16(table: bytes) -> integer
+```
+Конвертирует массив байтов в 2-х битное беззнаковое число
+
+```lua
+function bit_converter.bytes_to_uint32(table: bytes) -> integer
+```
+Конвертирует массив байтов в 4-х битное беззнаковое число
+
+```lua
+function bit_converter.bytes_to_int16(table: bytes) -> integer
+```
+Конвертирует массив байтов в 2-х битное знаковое число
+
+```lua
+function bit_converter.bytes_to_int32(table: bytes) -> integer
+```
+Конвертирует массив байтов в 4-х битное знаковое число
+
+```lua
+function bit_converter.bytes_to_int64(table: bytes) -> integer
+```
+Конвертирует массив байтов в 8-х битное знаковое число
\ No newline at end of file
diff --git a/doc/ru/8.2.Модуль-Lua-core_data_buffer.md b/doc/ru/8.2.Модуль-Lua-core_data_buffer.md
new file mode 100644
index 00000000..4bbbacf6
--- /dev/null
+++ b/doc/ru/8.2.Модуль-Lua-core_data_buffer.md
@@ -0,0 +1,153 @@
+## Буффер данных
+### Хранит в себе массив байтов и позволяет легко получать или добавлять разные значения
+
+```lua
+function data_buffer(bytes)
+```
+Создаёт новый экземпляр data_buffer (параметр bytes необязательный)
+
+```lua
+function data_buffer:put_byte(integer: byte)
+```
+Записывает байт в буффер
+
+```lua
+function data_buffer:put_bytes(table: bytes)
+```
+Записывает байты в буффер
+
+```lua
+function data_buffer:put_string(string: str)
+```
+Конвертирует строку в байты и записывает их в буффер
+
+```lua
+function data_buffer:put_bool(boolean: bool)
+```
+Конвертирует булевое значение в байт и записывает его в буффер
+
+```lua
+function data_buffer:put_single(number: single)
+```
+Конвертирует плавающее число одинарной точности в байты и записывает их в буффер
+
+```lua
+function data_buffer:put_double(number: double)
+```
+Конвертирует плавающее число двойной точности в байты и записывает их в буффер
+
+```lua
+function data_buffer:put_uint16(integer: int)
+```
+Конвертирует беззнаковое 2-х битное число в байты и записывает их в буффер
+
+```lua
+function data_buffer:put_uint32(integer: int)
+```
+Конвертирует беззнаковое 4-х битное число в байты и записывает их в буффер
+
+```lua
+function data_buffer:put_int16(integer: int)
+```
+Конвертирует знаковое 2-х битное число в байты и записывает их в буффер
+
+```lua
+function data_buffer:put_int32(integer: int)
+```
+Конвертирует знаковое 4-х битное число в байты и записывает их в буффер
+
+```lua
+function data_buffer:put_int64(integer: int)
+```
+Конвертирует знаковое 8-и битное число в байты и записывает их в буффер
+
+```lua
+function data_buffer:put_number(number: num)
+```
+Конвертирует любое число в байты и записывает их в буффер;
+
+Первый байт это тип значения:
+```lua
+zero = 0
+uint16 = 1
+uint32 = 2
+int16 = 3
+int32 = 4
+int64 = 5
+double = 6
+```
+
+```lua
+function data_buffer:get_byte() -> integer
+```
+Возвращает следующий байт из буффера
+
+```lua
+function data_buffer:get_bytes(n) -> table
+```
+Возвращает n следующих байтов, если n равен nil или не указан, то возвращается массив всех байтов
+
+```lua
+function data_buffer:get_string() -> string
+```
+Читает следующую строку из буффера
+
+```lua
+function data_buffer:get_bool() -> boolean
+```
+Читает следующий логический булев из буффера
+
+```lua
+function data_buffer:get_single() -> number
+```
+Читает следующее плавающее число одинарной точности из буффера
+
+```lua
+function data_buffer:get_double() -> number
+```
+Читает следующее плавающее число двойной точности из буффера
+
+```lua
+function data_buffer:get_uint16() -> integer
+```
+Читает следующее 2-х битное беззнаковое целое число из буффера
+
+```lua
+function data_buffer:get_uint32() -> integer
+```
+Читает следующее 4-х битное беззнаковое целое число из буффера
+
+```lua
+function data_buffer:get_int16() -> integer
+```
+Читает следующее 2-х битное знаковое целое число из буффера
+
+```lua
+function data_buffer:get_int32() -> integer
+```
+Читает следующее 4-х битное знаковое целое число из буффера
+
+```lua
+function data_buffer:get_int64() -> integer
+```
+Читает следующее 8-х битное знаковое целое число из буффера
+
+```lua
+function data_buffer:get_number() -> number
+```
+Читает следующее число (см. data_buffer:put_number)
+
+```lua
+function data_buffer:size() -> integer
+```
+Возвращает размер буффера
+
+```lua
+function data_buffer:set_position(integer: pos)
+```
+Устанавливает текущую позицию в буффере
+
+```lua
+function data_buffer:set_bytes(table: bytes)
+```
+Устанавливает байты в буффер
\ No newline at end of file
diff --git a/doc/ru/8.Скриптинг.md b/doc/ru/8.Скриптинг.md
new file mode 100644
index 00000000..9f88954f
--- /dev/null
+++ b/doc/ru/8.Скриптинг.md
@@ -0,0 +1,513 @@
+# Скриптинг
+
+В качестве языка сценариев используется LuaJIT
+
+## Функции, доступные в скриптах
+
+```lua
+load_script("контентпак:scripts/имя_скрипта.lua") -- загружает скрипт, если ещё не загружен
+load_script("контентпак:scripts/имя_скрипта.lua", true) -- перезагружает скрипт
+require "контентпак:имя_модуля" -- загружает lua модуль из папки modules (расширение не указывается)
+```
+
+## Библиотека player
+```python
+player.get_pos(playerid: int) -> number, number, number
+```
+Возвращает x, y, z координаты игрока
+
+```python
+player.set_pos(playerid: int, x: number, y: number, z: number)
+```
+
+Устанавливает x, y, z координаты игрока
+
+```python
+player.get_rot(playerid: int) -> number, number
+```
+
+Возвращает x, y вращения камеры (в радианах)
+
+```python
+player.set_rot(playerid: int, x: number, y: number, z: number)
+```
+
+Устанавливает x, y вращения камеры (в радианах)
+
+```python
+player.get_inventory(playerid: int) -> int, int
+```
+
+Возвращает id инвентаря игрока и индекс выбранного слота (от 0 до 9)
+
+## Библиотека world
+
+```python
+world.get_day_time() -> number
+```
+
+Возвращает текущее игровое время от 0.0 до 1.0, где 0.0 и 1.0 - полночь, 0.5 - полдень.
+
+```python
+world.set_day_time(time: number)
+```
+
+Устанавливает указанное игровое время.
+
+```python
+world.get_total_time() -> number
+```
+
+Возвращает общее суммарное время, прошедшее в мире
+
+```python
+world.get_seed() -> int
+```
+
+Возвращает зерно мира.
+
+## Библиотека gui
+
+Библиотека содержит функции для доступа к свойствам UI элементов. Вместо gui следует использовать объектную обертку, предоставляющую доступ к свойствам через мета-методы __index, __newindex:
+```lua
+local inventory_doc = Document.new("id-макета")
+print(inventory_doc.some_button.text)
+indentory_doc.some_button.text = "new text"
+```
+
+В скрипте макета `layouts/файл_макета.xml` - `layouts/файл_макета.xml.lua` уже доступна переменная **document** содержащая объект класса Document
+
+## Библиотека inventory
+
+Библиотека функций для работы с инвентарем.
+
+```python
+inventory.get(invid: int, slot: int) -> int, int
+```
+
+Принимает id инвентаря и индекс слота. Возвращает id предмета и его количество. id = 0 (core:empty) обозначает, что слот пуст.
+
+```python
+inventory.set(invid: int, slot: int, itemid: int, count: int)
+```
+
+Устанавливает содержимое слота.
+
+```python
+inventory.size(invid: int) -> int
+```
+
+Возращает размер инвентаря (число слотов). Если указанного инвентаря не существует, бросает исключение.
+
+```python
+inventory.add(invid: int, itemid: int, count: int) -> int
+```
+
+Добавляет предмет в инвентарь. Если не удалось вместить все количество, возвращает остаток.
+
+```python
+inventory.get_block(x: int, y: int, z: int) -> int
+```
+
+Функция возвращает id инвентаря указанного блока. Если блок не может иметь инвентарь - возвращает 0.
+
+```python
+inventory.bind_block(invid: int, x: int, y: int, z: int)
+```
+
+Привязывает указанный инвентарь к блоку.
+
+```python
+inventory.unbind_block(x: int, y: int, z: int)
+```
+
+Отвязывает инвентарь от блока.
+
+> [!WARNING]
+> Инвентари, не привязанные ни к одному из блоков, удаляются при выходе из мира.
+
+```python
+inventory.clone(invid: int) -> int
+```
+
+Создает копию инвентаря и возвращает id копии. Если копируемого инвентаря не существует, возвращает 0.
+
+## Библиотека block
+
+```python
+block.name(blockid: int) -> str
+```
+
+Возвращает строковый id блока по его числовому id
+
+```python
+block.index(name: str) -> int
+```
+
+Возвращает числовой id блока, принимая в качестве агрумента строковый
+
+```python
+block.get(x: int, y: int, z: int) -> int
+```
+
+Возвращает числовой id блока на указанных координатах. Если чанк на указанных координатах не загружен, возвращает -1.
+
+```python
+block.get_states(x: int, y: int, z: int) -> int
+```
+
+Возвращает состояние (поворот + доп. информация) в виде целого числа
+
+```python
+block.set(x: int, y: int, z: int, id: int, states: int)
+```
+
+Устанавливает блок с заданным числовым id и состоянием (0 - по-умолчанию) на заданных координатах.
+
+> [!WARNING]
+> `block.set` не вызывает событие on_placed.
+
+```python
+block.is_solid_at(x: int, y: int, z: int) -> bool
+```
+
+Проверяет, является ли блок на указанных координатах полным
+
+```python
+block.is_replaceable_at(x: int, y: int, z: int) -> bool
+```
+Проверяет, можно ли на заданных координатах поставить блок (примеры: воздух, трава, цветы, вода)
+
+```python
+block.defs_count() -> int
+```
+
+Возвращает количество id доступных в движке блоков
+
+Следующие три функции используется для учёта вращения блока при обращении к соседним блокам или других целей, где направление блока имеет решающее значение.
+
+
+```python
+block.get_X(x: int, y: int, z: int) -> int, int, int
+```
+
+Возвращает целочисленный единичный вектор X блока на указанных координатах с учётом его вращения (три целых числа).
+Если поворот отсутствует, возвращает 1, 0, 0
+
+```python
+block.get_Y(x: int, y: int, z: int) -> int, int, int
+```
+
+Возвращает целочисленный единичный вектор Y блока на указанных координатах с учётом его вращения (три целых числа).
+Если поворот отсутствует, возвращает 0, 1, 0
+
+```python
+block.get_Z(x: int, y: int, z: int) -> int, int, int
+```
+
+Возвращает целочисленный единичный вектор Z блока на указанных координатах с учётом его вращения (три целых числа).
+Если поворот отсутствует, возвращает 0, 0, 1
+
+### Пользовательские биты
+
+Выделенная под использования в скриптах часть поля `voxel.states` хранящего доп-информацию о вокселе, такую как вращение блока. На данный момент выделенная часть составляет 8 бит.
+
+```python
+block.get_user_bits(x: int, y: int, z: int, offset: int, bits: int) -> int
+```
+
+Возвращает выбранное число бит с указанного смещения в виде целого беззнакового числа
+
+```python
+block.set_user_bits(x: int, y: int, z: int, offset: int, bits: int, value: int) -> int
+```
+Записывает указанное число бит значения value в user bits по выбранному смещению
+
+## Библиотека item
+
+```python
+item.name(itemid: int) -> str
+```
+
+Возвращает строковый id предмета по его числовому id (как block.name)
+
+```python
+item.index(name: str) -> int
+```
+
+Возвращает числовой id предмета по строковому id (как block_index)
+
+```python
+item.stack_size(itemid: int) -> int
+```
+
+Возвращает максимальный размер стопки для предмета.
+
+```python
+item.defs_count() -> int
+```
+
+Возвращает общее число доступных предметов (включая сгенерированные)
+
+## Библиотека hud
+
+```python
+hud.open_inventory()
+```
+
+Открывает инвентарь
+
+```python
+hud.close_inventory()
+```
+
+Закрывает инвентарь
+
+```python
+hud.open_block(x: int, y: int, z: int) -> int, str
+```
+
+Открывает инвентарь и UI блока. Если блок не имеет макета UI - бросается исключение.
+
+Возвращает id инвентаря блока (при *"inventory-size"=0* создаётся виртуальный инвентарь, который удаляется после закрытия), и id макета UI.
+
+> [!NOTE]
+> Одновременно может быть открыт только один блок
+
+```python
+hud.open_permanent(layoutid: str)
+```
+
+Добавляет постоянный элемент на экран. Элемент не удаляется при закрытии инвентаря. Чтобы не перекрывать затенение в режиме инвентаря нужно установить z-index элемента меньшим чем -1. В случае тега inventory, произойдет привязка слотов к инвентарю игрока.
+
+```python
+hud.close(layoutid: str)
+```
+
+Удаляет элемент с экрана
+## События блоков
+
+```lua
+function on_placed(x, y, z, playerid)
+```
+
+Вызывается после установки блока игроком
+
+```lua
+function on_broken(x, y, z, playerid)
+```
+
+Вызывается после разрушения блока игроком
+
+```lua
+function on_interact(x, y, z, playerid) -> bool
+```
+
+Вызывается при нажатии на блок ПКМ. Предотвращает установку блоков, если возвращает `true`
+
+```lua
+function on_update(x, y, z)
+```
+
+Вызывается при обновлении блока (если изменился соседний блок)
+
+```lua
+function on_random_update(x, y, z)
+```
+
+Вызывается в случайные моменты времени (рост травы на блоках земли)
+
+```lua
+function on_blocks_tick(tps: int)
+```
+
+Вызывается tps (20) раз в секунду
+
+## События предметов
+
+```lua
+function on_use(playerid: int)
+```
+
+Вызывается при нажатии ПКМ не на блок.
+
+```lua
+function on_use_on_block(x: int, y: int, z: int, playerid: int)
+```
+
+Вызывается при нажатии ПКМ на блок. Предотвращает установку блока, прописанного в `placing-block` если возвращает `true`
+
+```lua
+function on_block_break_by(x: int, y: int, z: int, playerid: int)
+```
+
+Вызывается при нажатии ЛКМ на блок (в т.ч неразрушимый). Предотвращает разрушение блока, если возвращает `true`
+
+## События мира
+
+События мира для контент-пака прописываются в `scripts/world.lua`
+
+```lua
+function on_world_open()
+```
+
+Вызывается при загрузке мира
+
+```lua
+function on_world_save()
+```
+
+Вызывается перед сохранением мира
+
+```lua
+function on_world_tick()
+```
+
+Вызывается 20 раз в секунду
+
+```lua
+function on_world_quit()
+```
+
+Вызывается при выходе из мира (после сохранения)
+
+## События макета
+
+События прописываются в файле `layouts/имя_макета.xml.lua`.
+
+```lua
+function on_open(invid: int, x: int, y: int, z: int)
+```
+
+Вызывается при добавлении элемента на экран.
+При отсутствии привязки к инвентарю invid будет равен 0.
+При отсутствии привязки к блоку x, y, z так же будут равны 0.
+
+```lua
+function on_close(invid: int)
+```
+
+Вызывается при удалении элемента с экрана.
+
+## События HUD
+
+События связанные с игровым интерфейсом прописываются в файле `scripts/hud.lua`
+
+```lua
+function on_hud_open(playerid: int)
+```
+
+Вызывается после входа в мир, когда становится доступна библиотека hud. Здесь на экран добавляются постоянные элементы.
+
+```lua
+function on_hud_close(playerid: int)
+```
+
+Вызывается при выходе из мира, перед его сохранением.
+
+## Библиотеки движка
+
+### file
+
+Библиотека функций для работы с файлами
+
+```python
+file.resolve(путь: str) -> str
+```
+
+Функция приводит запись `точка_входа:путь` (например `user:worlds/house1`) к обычному пути. (например `C://Users/user/.voxeng/worlds/house1`)
+
+> [!NOTE]
+> Функцию не нужно использовать в сочетании с другими функциями из библиотеки, так как они делают это автоматически
+
+Возвращаемый путь не является каноническим и может быть как абсолютным, так и относительным.
+
+```python
+file.read(путь: str) -> str
+```
+
+Читает весь текстовый файл и возвращает в виде строки
+
+```python
+file.read_bytes(путь: str) -> array of integers
+```
+
+Читает файл в массив байт.
+
+```python
+file.write(путь: str, текст: str) -> nil
+```
+
+Записывает текст в файл (с перезаписью)
+
+```python
+file.write_bytes(путь: str, data: array of integers)
+```
+
+Записывает массив байт в файл (с перезаписью)
+
+```python
+file.length(путь: str) -> int
+```
+
+Возвращает размер файла в байтах, либо -1, если файл не найден
+
+```python
+file.exists(путь: str) -> bool
+```
+
+Проверяет, существует ли по данному пути файл или директория
+
+```python
+file.isfile(путь: str) -> bool
+```
+
+Проверяет, существует ли по данному пути файл
+
+```python
+file.isdir(путь: str) -> bool
+```
+
+Проверяет, существует ли по данному пути директория
+
+```python
+file.mkdir(путь: str) -> bool
+```
+
+Создает директорию. Возвращает true если была создана новая директория
+
+```python
+file.mkdirs(путь: str) -> bool
+```
+
+Создает всю цепочку директорий. Возвращает true если были созданы директории.
+
+### time
+
+```python
+time.uptime() -> float
+```
+
+Возвращает время с момента запуска движка в секундах
+
+## Доступные модули
+
+### TOML сериализация/десериализация
+
+```lua
+local toml = require "core:toml"
+
+local t = {a=53, b=42, s="test", sub={x=1, y=6}}
+local s = toml.serialize(t)
+print(s)
+local t2 = toml.deserialize(s)
+```
+вывод:
+```toml
+b = 42
+s = "test"
+a = 53
+[sub]
+y = 6
+x = 1
+```
diff --git a/doc/ru/9.Модели-блоков.md b/doc/ru/9.Модели-блоков.md
new file mode 100644
index 00000000..660f5d37
--- /dev/null
+++ b/doc/ru/9.Модели-блоков.md
@@ -0,0 +1,19 @@
+# Модели блоков
+
+Создание собственной модели блока может быть реализовано при указании у блока свойств:
+```js
+"model": "custom",
+"model-primitives": {
+ "aabbs": [
+ // список описаний AABB примитивов
+ ],
+ // ... другие примитивы
+}
+```
+
+**AABB** примитив - массив состоящий из значений:
+```
+[x, y, z, width, height, depth, имёна текстур для каждой стороны]
+```
+
+**tetragon** примитив (по смыслу скорее parallelogram) - массив из трёх векторов, описывающих позицию примитива, вектор X\*ширина, Y\*высота.