Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
4c0f278
ci: fix release build and nexus upload pipeline after 1.6 (#2444)
SkrubbySkrubInAShrub May 31, 2026
660fc51
feat(screenshots): HDR & SDR .png, clipboard support (#2434)
davo0411 May 31, 2026
f62f4b1
refactor(weather-editor): migrate isl light editor (#2414)
SkrubbySkrubInAShrub May 31, 2026
aa0e1a6
feat: add GPU/CPU profiling system with per-feature timing (#2389)
doodlum May 31, 2026
e259a92
chore(sky-sync): move to core (#2418)
SkrubbySkrubInAShrub May 31, 2026
ca1c494
fix(hooks): promote snow render targets to fp16 for banding (#2410)
doodlum May 31, 2026
6d4d8ad
feat: advanced skin (#2428)
jiayev Jun 1, 2026
2e57080
chore: rename weather editor to CS editor (#2449)
Dlizzio Jun 1, 2026
055d508
fix(emat): allow solid-black height-only masks (#2441)
FIocker Jun 1, 2026
22ea056
fix(water): fix water blending (ghosting) and LOD gaps (#2440)
FIocker Jun 1, 2026
26c10c4
ci: fix perm for hotfix workflow (#2451)
SkrubbySkrubInAShrub Jun 1, 2026
d49f150
perf: remove per-update heap allocation from feature cbuffer path (#2…
davo0411 Jun 2, 2026
a9681df
feat: localization (#2416)
jiayev Jun 2, 2026
03096be
chore(UI): centeralize rounded button highlight (#2454)
Dlizzio Jun 2, 2026
15e4575
chore(UI): weather picker refinement (#2456)
Dlizzio Jun 2, 2026
1882718
feat(water-effects): water caustic with chromatic abberation (#2433)
jiayev Jun 2, 2026
6e82454
ci: reconcile dev by merge instead of rebase (#2453)
SkrubbySkrubInAShrub Jun 2, 2026
be22b78
feat(fog): volumetric fog (#2361)
jiayev Jun 3, 2026
c185b5c
fix(UI): DPI scale new UI additions (#2457)
Dlizzio Jun 3, 2026
8465329
feat(i18n): sort translation files (#2461)
jiayev Jun 3, 2026
8fa4e90
chore(tools): add shader-refactor bytecode verifier (#2464)
SkrubbySkrubInAShrub Jun 3, 2026
9ff72fa
fix(truepbr): honor DisableTerrainVertexColors on PBR landscape (#2463)
SkrubbySkrubInAShrub Jun 3, 2026
4d66c32
fix(lighting): guard EMAT parallax shadow against undefined TBN (#2462)
SkrubbySkrubInAShrub Jun 3, 2026
1561e4c
fix(vol-fog): add missing include (#2466)
jiayev Jun 3, 2026
7cbe43f
fix(i18n): add 'ready_for_review' type to pull request triggers (#2467)
jiayev Jun 3, 2026
c412e20
fix(vol-fog): missing define (#2468)
SkrubbySkrubInAShrub Jun 4, 2026
38d3ce8
fix(sss): clamp skin albedo to prevent explosion (#2469)
jiayev Jun 4, 2026
e7194b8
chore(cs-editor): reduce logging (#2471)
SkrubbySkrubInAShrub Jun 4, 2026
d1f4060
fix(UI): hide profiling when data not available (#2473)
Dlizzio Jun 5, 2026
eda4e97
fix(unified water): add IsDisabledByDefault (#2474)
doodlum Jun 6, 2026
e368f30
ci: use prebuilt CommonLib (#2476)
SkrubbySkrubInAShrub Jun 6, 2026
4d42fbe
fix: dynamic cubemaps X4000 warning (#2478)
davo0411 Jun 6, 2026
16f6ede
fix: triplanar.hlsli x4000 warning (#2479)
davo0411 Jun 6, 2026
4dff23f
feat(UI): custom cursor support (#2480)
davo0411 Jun 6, 2026
e0c890c
feat(skysync): rework shadow fader, expose sun/moon to shared data (#…
doodlum Jun 6, 2026
e9ecea3
fix(lighting): create Masks2 RT and divide SSGI AO by vertexAO (#2411)
doodlum Jun 7, 2026
d0550a5
feat(sss): add diffuse extraction pre-pass and scatter modes (#2407)
doodlum Jun 7, 2026
bcea965
fix: unified water bad cell guards (#2482)
davo0411 Jun 7, 2026
29cb5e6
chore(tools): add RenderDoc verification harness (#2470)
SkrubbySkrubInAShrub Jun 7, 2026
b48bf24
chore: remove all VR support (#2475)
doodlum Jun 7, 2026
a3e13d1
fix(ci): resolve broken job name in shader validation workflow (#2485)
doodlum Jun 7, 2026
dc7e251
fix: fix render target properties (#2484)
doodlum Jun 7, 2026
b74dedf
chore(release): 1.7.0-rc.1 [skip ci]
semantic-release-bot Jun 7, 2026
f8cbed0
Merge upstream Community Shaders v1.7.0-rc.1 (keep VR)
alandtse Jun 7, 2026
47821fa
Revert "chore: remove all VR support (#2475)" (restore VR)
alandtse Jun 7, 2026
b6e1065
fix: resolve v1.7.0 sync compile cascades
alandtse Jun 7, 2026
7430048
fix: VR regressions found by sync audit + bigobj
alandtse Jun 7, 2026
aae3980
fix(vr): RE Water RT VR offsets + dedup depth propagate
alandtse Jun 8, 2026
d7e70c5
feat(skysync): restore altitude correction over upstream #2408
alandtse Jun 8, 2026
36376be
feat(screenshot): adopt upstream HDR-PNG export onto VR Subrect path
alandtse Jun 8, 2026
d36d5ab
style: 🎨 apply pre-commit.ci formatting
pre-commit-ci[bot] Jun 8, 2026
a58e2df
chore(i18n): regen en.json; dedup snow RT comment
alandtse Jun 8, 2026
0abdfd8
fix(fog): init out-params to clear fxc X4000 (max-warnings 0)
alandtse Jun 8, 2026
eb5bb80
fix(shaders): clear remaining fxc X4000/X3206 under max-warnings 0
alandtse Jun 8, 2026
4698d0f
chore(i18n): re-sort zh_CN.json to match en.json key order
alandtse Jun 8, 2026
1318a62
chore(i18n): prune zh_CN orphaned keys not in en.json
alandtse Jun 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions .github/workflows/pr-i18n.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
name: "PR: i18n Check"

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
paths:
- "src/**"
- "package/SKSE/Plugins/CommunityShaders/Translations/**"
- "tools/extract-i18n.py"
- "tools/sort-i18n.py"

permissions:
contents: read

jobs:
i18n-check:
name: Verify en.json is in sync with source
if: ${{ !github.event.pull_request.draft }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}

- uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Check en.json is up to date
run: python tools/extract-i18n.py --check

- name: Check for orphaned keys
run: python tools/extract-i18n.py --orphans

- name: Check translation file key order matches en.json
run: python tools/sort-i18n.py --check

- name: Validate translation file formats
run: |
python -c "
import json, sys, pathlib

translations_dir = pathlib.Path('package/SKSE/Plugins/CommunityShaders/Translations')
if not translations_dir.exists():
print('No Translations directory found')
sys.exit(0)

# Load en.json keys as reference
en_path = translations_dir / 'en.json'
if not en_path.exists():
print('ERROR: en.json not found')
sys.exit(1)

with open(en_path, encoding='utf-8') as f:
en_data = json.load(f)
en_keys = {k for k in en_data if k != '_meta'}

errors = []
for path in sorted(translations_dir.glob('*.json')):
if path.name == 'en.json':
continue
try:
with open(path, encoding='utf-8') as f:
data = json.load(f)
except json.JSONDecodeError as e:
errors.append(f'{path.name}: Invalid JSON - {e}')
continue

if not isinstance(data, dict):
errors.append(f'{path.name}: Root must be a JSON object')
continue

# Check for keys not in en.json (stale/typo keys)
locale_keys = {k for k in data if k != '_meta'}
extra_keys = locale_keys - en_keys
if extra_keys:
errors.append(f'{path.name}: {len(extra_keys)} key(s) not in en.json: {sorted(extra_keys)[:5]}')

# Check placeholder consistency
import re
placeholder_re = re.compile(r'\{(\w+)\}')
for key in locale_keys & en_keys:
en_placeholders = set(placeholder_re.findall(en_data[key]))
locale_placeholders = set(placeholder_re.findall(data[key]))
if en_placeholders != locale_placeholders:
errors.append(f'{path.name}: Key \"{key}\" has mismatched placeholders: expected {en_placeholders}, got {locale_placeholders}')

if errors:
print(f'Found {len(errors)} error(s):')
for e in errors:
print(f' - {e}')
sys.exit(1)
else:
print(f'All translation files valid. Checked {len(list(translations_dir.glob(\"*.json\"))) - 1} locale(s).')
"
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,13 @@ target_include_directories(
${BSHOSHANY_THREAD_POOL_INCLUDE_DIRS}
${CLIB_UTIL_INCLUDE_DIRS}
"${CMAKE_SOURCE_DIR}/package/Shaders"
"${CMAKE_SOURCE_DIR}/extern/sk_hdr_png/include"
${DETOURS_INCLUDE_DIRS}
${EXPRTK_INCLUDE_DIRS}
)

target_compile_definitions(${PROJECT_NAME} PRIVATE SK_HDR_PNG_COMMUNITY_SHADERS)

target_link_libraries(
${PROJECT_NAME}
PRIVATE
Expand All @@ -166,6 +169,7 @@ target_link_libraries(
d3d12.lib
Microsoft::DirectX-Headers
${DETOURS_LIBRARY}
windowscodecs
)

# devbench bridge: opt-out via -DDEVBENCH_BRIDGE=OFF. When off, the port isn't required
Expand All @@ -184,6 +188,9 @@ if(MSVC)
"$<$<CONFIG:RelWithDebInfo>:/LTCG>"
"$<$<CONFIG:RelWithDebInfo>:/INCREMENTAL:NO>"
)
# Large translation units (e.g. LightLimitFix/ShadowCasterManager.cpp pulling the
# full feature + editor headers) exceed the default COFF section limit; /bigobj.
target_compile_options(${PROJECT_NAME} PRIVATE "/bigobj")
endif()

# https://gitlab.kitware.com/cmake/cmake/-/issues/24922#note_1371990
Expand Down
138 changes: 138 additions & 0 deletions TRANSLATING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# Translating Community Shaders

Community Shaders supports multiple languages through a JSON-based translation system.
This document explains how to contribute translations.

## For Translators (No Coding Required)

### Option A: Via Weblate (Recommended)

The easiest way to contribute translations is through our hosted Weblate instance:

1. Visit: **[hosted.weblate.org/projects/community-shaders](https://hosted.weblate.org/projects/community-shaders/)** _(link will be active once configured)_
2. Create an account or log in with GitHub
3. Select your language
4. Translate strings in the web interface
5. Your translations are automatically submitted as PRs

Weblate provides:

- Translation memory and suggestions
- Consistency checks
- Placeholder validation (`{name}` must be preserved)
- Progress tracking per language

### Option B: Direct PR on GitHub

1. Fork the repository
2. Copy `package/SKSE/Plugins/CommunityShaders/Translations/en.json` to a new file named with your locale code (e.g., `zh_CN.json`, `ja.json`, `de.json`)
3. Translate the string values (NOT the keys)
4. Submit a Pull Request

## Translation File Format

```json
{
"_meta": {
"language": "简体中文",
"locale": "zh_CN",
"version": "1.0.0",
"authors": ["Your Name"]
},
"menu.home.welcome": "欢迎使用 Community Shaders {version}",
"menu.faq.q1": "什么是 Community Shaders?",
...
}
```

### Rules

| Rule | Example |
| --------------------------------- | ---------------------------------------------------- |
| **Translate values, not keys** | `"menu.faq.q1": "翻译这里"` — key 左边不改 |
| **Preserve placeholders** | `{version}`, `{count}`, `{key}` 必须保留,位置可调整 |
| **Preserve format specifiers** | `%s`, `%d`, `%.1f` 必须保留 |
| **`\n` = line break** | 可以调整分行位置 |
| **`_meta.language`** | 用该语言自身书写(如 "日本語" 而非 "Japanese") |
| **Don't translate `##` suffixes** | 如果值中包含 `##xxx`,不翻译 `##` 后面的部分 |
| **Partial translations OK** | 缺失的 key 会自动 fallback 到英文 |

### Locale Codes

Use standard BCP 47-style codes:

| Code | Language |
| ------- | ------------------ |
| `zh_CN` | 简体中文 |
| `zh_TW` | 繁體中文 |
| `ja` | 日本語 |
| `ko` | 한국어 |
| `de` | Deutsch |
| `fr` | Français |
| `es` | Español |
| `pt_BR` | Português (Brasil) |
| `ru` | Русский |
| `it` | Italiano |
| `pl` | Polski |

## For Developers

### Adding New Translatable Strings

```cpp
// 1. Use T() with inline default in source code
ImGui::Text("%s", T("menu.faq.q10", "My new FAQ question?"));

// 2. For Feature files, use TKEY macro for shorter keys
#define I18N_KEY_PREFIX "feature.my_feature."
ImGui::Checkbox(T(TKEY("enabled"), "Enabled"), &settings.enabled);
#undef I18N_KEY_PREFIX

// 3. Regenerate en.json
// Run: python tools/extract-i18n.py --write
```

### CI Validation

The `pr-i18n.yaml` workflow checks:

- `en.json` is in sync with source code (`--check`)
- No orphaned keys exist (`--orphans`)
- Translation file key order matches `en.json` (`sort-i18n.py --check`)
- Translation files have valid JSON format
- Placeholders `{name}` are consistent across languages

### Translation Key Ordering

All non-English translation files must have their keys ordered to match `en.json`. This ensures consistency and makes diffs easier to review.

```bash
# Check if translation files are correctly ordered
python tools/sort-i18n.py --check

# Automatically reorder translation files to match en.json
python tools/sort-i18n.py --write
```

Ordering rules:

1. `_meta` always comes first
2. Keys present in `en.json` follow `en.json`'s order
3. Any extra keys not in `en.json` are appended alphabetically at the end

### Key Naming Convention

```
menu.<page>.<item> — Menu UI labels
menu.<page>.<item>_tooltip — Tooltip text
feature.<short_name>.<setting> — Feature settings
overlay.<type> — Overlay messages
common.<term> — Shared/reused text
ui.<component> — Utility UI
weather_editor.<item> — Weather editor
```

## CJK Font Support

CJK languages (Chinese, Japanese, Korean) require fonts with appropriate glyph coverage.
Community Shaders uses system CJK fonts by default.
4 changes: 2 additions & 2 deletions docs/weather-system-docs/WeatherVariableRegistration.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ The system now automatically:

- Saves/loads weather-specific settings to JSON
- Interpolates variables during weather transitions
- Appears in the weather editor UI with per-weather toggle buttons
- Appears in the CS Editor UI with per-weather toggle buttons
- Handles default values and missing data
- Shows weather-controlled status in feature settings UI

Expand Down Expand Up @@ -278,7 +278,7 @@ Weather-specific settings are stored in:

```
Data/SKSE/Plugins/CommunityShaders/Weathers/
WeatherEditorID_FormID.json
WeatherFormEditorID_FormID.json
```

Each file contains settings for all features:
Expand Down
28 changes: 28 additions & 0 deletions extern/sk_hdr_png/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
This is free and unencumbered software released into the public domain.

Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.

In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

For more information, please refer to <https://unlicense.org/>

Source: sk_hdr_png.hpp from ReShade (commit e7cce821877b8a195fcc842febbcc7e0d8edd86b)
https://github.com/crosire/reshade/commit/e7cce821877b8a195fcc842febbcc7e0d8edd86b
Author: Kaldaien (Special K)
8 changes: 8 additions & 0 deletions extern/sk_hdr_png/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# sk_hdr_png

HDR10/scRGB screenshot encoding as PNG with HDR metadata chunks (cHRM, mDCv, cLLi, iCCP).

Vendored from [ReShade](https://github.com/crosire/reshade) commit
[e7cce82](https://github.com/crosire/reshade/commit/e7cce821877b8a195fcc842febbcc7e0d8edd86b).

Licensed under the [Unlicense](LICENSE) (public domain).
Loading
Loading