diff --git a/docs/RENPY_PLAYER.md b/docs/RENPY_PLAYER.md new file mode 100644 index 0000000..dc80bc7 --- /dev/null +++ b/docs/RENPY_PLAYER.md @@ -0,0 +1,79 @@ +# Плеер Ren'Py: что он делает так же, как Ren'Py + +Плеер (`frontend/src/player/`) исполняет сценарий Ren'Py из IR в браузере. Здесь — то, что +повторяет поведение Ren'Py, а не его упрощение. Принцип: если игра приносит свой код (библиотеку +текстовых эффектов, свои displayable, свои настройки), плеер запускает **её код**, а не заменяет +его собственной копией. + +## Геометрия трансформаций + +`rendertransform.ts` — порт `RenderTransform` из `renpy/display/accelerator.pyx`: обрезка (`crop`), +`size`/`fit`, `zoom` и отражения, `rotate` с `rotate_pad`, 3D-повороты (`xrotate`, `yrotate`, +`zrotate`) вокруг `matrixanchor`, `zpos`, `zzoom`, `matrixtransform`, якорь по `transform_anchor`. +Матрицы — Ren'Py (`Matrix4`: векторы-столбцы, ось z от зрителя); в CSS уходит `matrix3d` с +отражённым z. `xpan`/`ypan`/`xtile`/`ytile` — отдельный элемент с повторяющимся фоном. +`blend` и `additive` переводятся в `mix-blend-mode`. Тесты — `frontend/tests/rendertransform.test.mjs`. + +## Слои и камера + +`config.layers` задаёт порядок слоёв снизу вверх; слой `screens` — собственный интерфейс плеера +(текстбокс, меню, экраны), слои до него лежат под интерфейсом, после — над ним. Игра управляет +слоями так же, как в Ren'Py: + +* `show`/`hide`/`scene ... onlayer имя`, `renpy.show/hide/scene(layer=...)`, `renpy.showing`, + `renpy.get_showing_tags`, `renpy.get_attributes` с `layer`; +* `show screen`/`hide screen`/`call screen ... onlayer имя`, свойство `layer` экрана, + `renpy.show_screen(_layer=...)`, `renpy.get_screen(layer=...)`; +* `renpy.add_layer(имя, above=, below=)` — порядок сохраняется в сохранении; +* `camera имя at ...` и `renpy.show_layer_at(список, layer=)` — трансформация всего слоя + (анимируемая, с теми же свойствами, что у картинки); +* `perspective True|число|(near, p, far)` на слое: картинки со `zpos` уходят в глубину с + перспективой (CSS `perspective` на слое). + +Смена сцены (`with`) снимает копию всех слоёв под интерфейсом. `preferences.transitions = 0` +отключает переходы. + +## Откат + +Плеер хранит снимок состояния на каждом взаимодействии (до 50) и возвращается к предыдущему по +колесу вверх, `PageUp` и действию `Rollback`. Журнал очищается при новой игре и загрузке. + +## Текст + +* `{font}`, `{alpha}`, `{k}`, `{plain}`, `{outlinecolor}`, `{cps}` (в том числе `{cps=*2}` и + `{/cps}`), `{a=...}` (адреса, `show:`, `hide:`, `jump:`, `call_in_new_context:` или + `config.hyperlink_handler`), `{rb}`/`{rt}` (ruby), `{space=N}`, `{vspace=N}`, `{alt}`, `{image=...}`. +* **Свои теги игры** (`config.custom_text_tags[...]`, `config.self_closing_custom_text_tags[...]`): + плеер вызывает функцию игры с `(tag, argument, contents)`, где `contents` — пары + `(renpy.TEXT_TEXT | TEXT_TAG, текст)`; ответ — тот же список, а `renpy.TEXT_DISPLAYABLE` + вставляет displayable в строку как один символ. Так работают Kinetic Text Tags (`{bt}`, `{fi}`, + `{sc}`, `{rotat}`, `{chaos}`, `{swap}`, `{move}`, `{omega}`), `{glitch}`, `{gradient}`, + `{explode}` и `{ruby}` в *That New Teacher*: их библиотеки — обычные скрипты игры. +* История, сохранения и перевод видят текст без вызова функций тегов (`parseText(text, false)`). + +## API отрисовки для своих displayable + +`render.ts`: `renpy.Displayable`, `renpy.Render` (`blit`, `subpixel_blit`, `fill`, `canvas`, +`subsurface`, `zoom`), `renpy.render`, `renpy.redraw`, `Text.set_text`. Дерево рендера +превращается в DOM и перерисовывается, пока элемент на странице. + +## Настройки игры + +`preferences` — объект настроек плеера: `text_cps`, `afm_time`, `afm_enable`, `fullscreen`, +`transitions`, `language`, `volumes[...]`, `get_volume`/`set_volume`, `get_mute`/`set_mute`, +`get_all_mixers`; `default preferences.x = ...` добавляет поле. `Color(...)` — настоящий `Color` +Ren'Py (`interpolate`, `tint`, `shade`, `hexcode`, `replace_*`, `rgb`/`hls`/`hsv`). +`renpy.fetch` отправляет запрос из браузера (нужен CORS на сервере); без сети игра получает +`FetchError`, как в Ren'Py. + +Шрифты: `FontGroup().add(файл, от, до)` собирается в одно CSS-семейство с `unicode-range`. +`config.mouse_displayable = MouseDisplayable(...)` и `config.mouse` меняют курсор. + +## Чего пока нет + +* Шейдеры и сетки (`renpy.register_shader`, ATL `shader`/`mesh`, `u_*`, `gl_*`), поэтому + шейдерные эффекты текста (`{wave}`) и размытие через `blur.rpy` в профилях пропускаются; + частичное `additive` (0 < x < 1). +* Live2D. +* Снимки экрана в слотах сохранения и импорт `.save` Ren'Py. +* Пропуск только прочитанного текста (`preferences.skip_unseen` сохраняется, но не действует). diff --git a/docs/SCREENS.md b/docs/SCREENS.md index c2cedd0..58d6e15 100644 --- a/docs/SCREENS.md +++ b/docs/SCREENS.md @@ -43,8 +43,8 @@ ## Ограничения -* Не поддерживаются `input`, `imagemap`/`hotspot`, `mousearea`, `drag`/`draggroup`, `side`, - `matrixcolor`, шейдеры и `im.*`; такие экраны блокируют импорт. +* Шейдеры (`shader`, `mesh`, `u_*`) не исполняются; про слои экранов (`onlayer`), камеру, + текстовые теги и остальное, что плеер делает как Ren'Py, — `docs/RENPY_PLAYER.md`. * Экран перестраивается целиком; положение прокрутки сохраняется, фокус и ввод — нет. * Позиции без точки (`xpos 1`) читаются как доля, а целые больше 1 — как пиксели. * Фокус с клавиатуры — только Tab и Enter/Space на кнопках.