Compare commits

...
Author SHA1 Message Date
github-actions[bot] 98396c6bcd chore(ai): sync LobeHub models at 6c7a6fb033e4
Sync source to CNB / Sync Git ref (push) Skipped
2026-10-10 09:55:54 +00:00
AxTps 403a883e0b fix: CI 钉住 cargo-shear 版本为 1.13.4
Sync source to CNB / Sync Git ref (push) Skipped
Axolotl desktop CI / guardrails (push) Canceled after 0s
Axolotl desktop CI / desktop (macos-latest) (push) Canceled after 0s
Axolotl desktop CI / desktop (ubuntu-latest) (push) Canceled after 0s
Axolotl desktop CI / desktop (windows-latest) (push) Canceled after 0s
Axolotl desktop CI / website (push) Canceled after 0s
Repository checks / typos (push) Canceled after 0s
Repository checks / tombi (push) Canceled after 0s
Rust checks / shear (push) Canceled after 0s
check-rust.yml 的 shear 任务在 Rust 1.95 工具链下装最新
cargo-shear(1.14.0) 失败:其依赖 ra_ap_syntax 0.0.352 要求
rustc >= 1.98。且 binstall 走 GitHub release 下载时遭遇
api.github.com 403,回退源码编译后同样因版本过高而失败。

钉到 cargo-shear@1.13.4(依赖 ra_ap_syntax 0.0.347,要求
rustc 1.95),与 CI 的 stable 工具链兼容。
2026-10-09 22:20:48 +08:00
AxTps 53c749aaea fix: 补齐 skin-rendering barrel 的盔甲导出
Sync source to CNB / Sync Git ref (push) Skipped
Axolotl desktop CI / guardrails (push) Canceled after 0s
Axolotl desktop CI / desktop (macos-latest) (push) Canceled after 0s
Axolotl desktop CI / desktop (ubuntu-latest) (push) Canceled after 0s
Axolotl desktop CI / desktop (windows-latest) (push) Canceled after 0s
Axolotl desktop CI / website (push) Canceled after 0s
Rust checks / shear (push) Canceled after 0s
Repository checks / typos (push) Canceled after 0s
Repository checks / tombi (push) Canceled after 0s
PR #8 合并后 CI 打包报 MISSING_EXPORT:ArmorTrimPanel.vue 与
SkinPreviewRenderer.vue 从 #ui/composables/skin-rendering 导入
ARMOR_SLOTS / ARMOR_TRIM_MATERIALS / ARMOR_TRIM_PATTERNS /
armorMaterialsForSlot / createDefaultArmorPreviewConfig /
useArmorPreview,但该 barrel 未导出这些符号。

补上 armor-preview-types 与 use-armor-preview 的导出。
本地 pnpm --filter @modrinth/app-frontend build 已通过。
2026-10-09 22:12:41 +08:00
Ap_Tx addc31c7c1 Merge pull request #8 from ApTx2012/feat/axolotl-port
feat: 移植 Axolotl 皮肤盔甲预览(Armor Preview)
2026-10-09 21:50:24 +08:00
AxTps 25978bcd8f Merge remote-tracking branch 'origin2/main'
Sync source to CNB / Sync Git ref (push) Skipped
Repository checks / typos (push) Canceled after 0s
Repository checks / tombi (push) Canceled after 0s
Axolotl desktop CI / guardrails (push) Canceled after 0s
Axolotl desktop CI / desktop (macos-latest) (push) Canceled after 0s
Axolotl desktop CI / desktop (ubuntu-latest) (push) Canceled after 0s
Axolotl desktop CI / desktop (windows-latest) (push) Canceled after 0s
Axolotl desktop CI / website (push) Canceled after 0s
Rust checks / shear (push) Canceled after 0s
2026-10-09 21:46:12 +08:00
AxTps 117eaad9ff style: 对分组修复涉及的 Rust 文件补 cargo fmt 2026-10-09 21:44:22 +08:00
AxTps ae2992d7f8 feat: 移植 Axolotl 皮肤盔甲预览(Armor Preview)
Sync source to CNB / Sync Git ref (push) Canceled after 0s
从 Axolotl 1.9.7 移植皮肤编辑器的盔甲/盔甲纹饰预览功能,
让玩家在皮肤选择页可试穿盔甲并调整纹饰。

新增:
- 前端组件 ArmorTrimTab / SkinListSkeleton 及 skin-armor-preview helper
- packages/ui 组件 ArmorPreviewControls / ArmorTrimPanel
- packages/ui armor 预览 composable(armor-preview-assets/types、use-armor-preview)
- packages/ui webgl 盔甲渲染(armor-geometry / armor-preview-object / armor-rendering)
- packages/ui/src/assets/minecraft-armor 盔甲素材

改动:
- SkinPreviewRenderer 增加 armorPreview/armorControls props、
  armorConfig model 与 useArmorPreview 集成
- Skins.vue 增加盔甲 tab、状态逻辑与模板接入
- 补齐 skin/composables/utils 的导出

适配说明:ArmorPreviewControls 原版依赖 reka-ui 的 popover,
Starlight 无该依赖且只用 external 模式,故改写为 external-only,
去除 reka-ui 与 overlays.css 依赖。
2026-10-07 20:01:19 +08:00
157 changed files with 2192 additions and 257 deletions

No files matched your search

+1 -1
View File
@@ -22,5 +22,5 @@ jobs:
node-version-file: .nvmrc
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
- uses: cargo-bins/cargo-binstall@dc19f1e48450eefe5a29b8da6c6b00a87d730b37 # v1.18.1
- run: cargo binstall --no-confirm cargo-shear
- run: cargo binstall --no-confirm cargo-shear@1.13.4
- run: cargo shear
@@ -0,0 +1,123 @@
<script setup lang="ts">
import { CheckIcon, RotateCounterClockwiseIcon, XIcon } from '@modrinth/assets'
import {
type ArmorPreviewConfig,
ArmorTrimPanel,
Button,
defineMessages,
useVIntl,
} from '@modrinth/ui'
import { computed, onMounted, onUnmounted } from 'vue'
const messages = defineMessages({
title: { id: 'app.skins.armor.title', defaultMessage: 'Armour and trims' },
description: {
id: 'app.skins.armor.description',
defaultMessage: 'Try armour and trims on your skin. Nothing is stored until you save it.',
},
unsaved: { id: 'app.skins.armor.unsaved', defaultMessage: 'Unsaved changes' },
resetToSaved: { id: 'app.skins.armor.reset-to-saved', defaultMessage: 'Reset to saved' },
restoreDefaults: {
id: 'app.skins.armor.restore-defaults',
defaultMessage: 'Restore defaults',
},
save: { id: 'app.skins.armor.save', defaultMessage: 'Save' },
close: { id: 'app.skins.armor.close', defaultMessage: 'Close' },
})
const draft = defineModel<ArmorPreviewConfig>({ required: true })
const props = defineProps<{
saved: ArmorPreviewConfig
/** Stable id shared with the toggle so it can point `aria-controls` here. */
panelId: string
}>()
const emit = defineEmits<{
save: []
reset: []
defaults: []
close: []
}>()
const { formatMessage } = useVIntl()
/**
* The tab is mounted only while it is showing, so this listens exactly for that
* window. It listens in the capture phase because the app's own global
* shortcuts listen on `window` the same way, and a bubble-phase listener here
* would be skipped as soon as anything closer stopped the event. A modal on top
* of the page owns Escape while it is up, and focus sits inside it, so the key
* is left to it.
*/
function handleKeydown(event: KeyboardEvent) {
if (event.key !== 'Escape') return
if (
event.target instanceof Element &&
event.target.closest('[role="dialog"], [role="alertdialog"], [aria-modal="true"]')
) {
return
}
emit('close')
}
onMounted(() => window.addEventListener('keydown', handleKeydown, true))
onUnmounted(() => window.removeEventListener('keydown', handleKeydown, true))
const isDirty = computed(() =>
Object.entries(draft.value).some(([slot, piece]) => {
const applied = props.saved[slot as keyof ArmorPreviewConfig]
return (
!applied ||
applied.material !== piece.material ||
applied.trimPattern !== piece.trimPattern ||
applied.trimMaterial !== piece.trimMaterial
)
}),
)
</script>
<template>
<div
:id="panelId"
role="region"
:aria-label="formatMessage(messages.title)"
class="flex min-h-[24rem] flex-col gap-4 rounded-2xl border border-solid border-surface-5 bg-surface-2 p-4"
>
<header class="flex flex-wrap items-start justify-between gap-3">
<div class="min-w-0">
<h2 class="m-0 text-lg font-bold text-[var(--color-text-primary)]">
{{ formatMessage(messages.title) }}
</h2>
<p class="m-0 mt-1 text-sm leading-6 text-[var(--color-text-tertiary)]">
{{ formatMessage(messages.description) }}
</p>
</div>
<div class="flex shrink-0 flex-wrap items-center gap-2">
<span v-if="isDirty" class="text-sm font-semibold text-[var(--color-text-tertiary)]">
{{ formatMessage(messages.unsaved) }}
</span>
<Button type="outlined" @click="emit('close')"
><XIcon />{{ formatMessage(messages.close) }}</Button
>
</div>
</header>
<ArmorTrimPanel v-model="draft" />
<footer
class="mt-auto flex flex-wrap items-center justify-between gap-2 border-0 border-t border-solid border-surface-5 pt-3"
>
<div class="flex flex-wrap items-center gap-2">
<Button type="outlined" :disabled="!isDirty" @click="emit('reset')"
><RotateCounterClockwiseIcon />{{ formatMessage(messages.resetToSaved) }}</Button
>
<Button type="outlined" @click="emit('defaults')">{{
formatMessage(messages.restoreDefaults)
}}</Button>
</div>
<Button type="colored" color="brand" :disabled="!isDirty" @click="emit('save')"
><CheckIcon />{{ formatMessage(messages.save) }}</Button
>
</footer>
</div>
</template>
@@ -0,0 +1,28 @@
<script setup lang="ts">
const { sections = 2, cards = 12 } = defineProps<{
sections?: number
cards?: number
}>()
</script>
<template>
<!--
Shaped after VirtualSkinSectionList: the same grid breakpoints and card
ratio, so the swap to real content does not move anything. Decorative, so
it stays out of the accessibility tree.
-->
<div class="flex flex-col gap-8" aria-hidden="true">
<div v-for="section in sections" :key="section" class="flex flex-col gap-4">
<div class="h-7 w-44 animate-pulse rounded-lg bg-surface-4" />
<div
class="grid w-full grid-cols-3 gap-3 min-[1300px]:grid-cols-4 min-[1750px]:grid-cols-5 min-[2050px]:grid-cols-6"
>
<div
v-for="card in cards"
:key="card"
class="aspect-[31/40] w-full animate-pulse rounded-[20px] bg-surface-4"
/>
</div>
</div>
</div>
</template>
@@ -0,0 +1,60 @@
import assert from 'node:assert/strict'
import test from 'node:test'
import { loadSkinArmorPreview, saveSkinArmorPreview } from './skin-armor-preview.ts'
const originalStorage = Object.getOwnPropertyDescriptor(globalThis, 'localStorage')
function withStorage(run: (values: Map<string, string>) => void): void {
const values = new Map<string, string>()
Object.defineProperty(globalThis, 'localStorage', {
configurable: true,
value: {
getItem: (key: string) => values.get(key) ?? null,
setItem: (key: string, value: string) => values.set(key, value),
},
})
try {
run(values)
} finally {
if (originalStorage) Object.defineProperty(globalThis, 'localStorage', originalStorage)
else delete (globalThis as { localStorage?: Storage }).localStorage
}
}
test('armor preview selections survive storage round trips', () => {
withStorage(() => {
const config = loadSkinArmorPreview()
config.helmet.material = 'diamond'
config.helmet.trimPattern = 'sentry'
config.helmet.trimMaterial = 'gold'
saveSkinArmorPreview(config)
assert.deepEqual(loadSkinArmorPreview(), config)
})
})
test('invalid stored armor values fall back per slot and field', () => {
withStorage((values) => {
values.set(
'axolotl:skin-armor-preview',
JSON.stringify({
helmet: { material: 'diamond', trimPattern: 'invalid', trimMaterial: 'gold' },
boots: { material: 'turtle', trimPattern: 'sentry', trimMaterial: 'invalid' },
}),
)
const config = loadSkinArmorPreview()
assert.deepEqual(config.helmet, {
material: 'diamond',
trimPattern: null,
trimMaterial: 'gold',
})
assert.deepEqual(config.boots, {
material: null,
trimPattern: 'sentry',
trimMaterial: 'iron',
})
assert.equal(config.chestplate.material, null)
})
})
@@ -0,0 +1,47 @@
import {
ARMOR_SLOTS,
ARMOR_TRIM_MATERIALS,
ARMOR_TRIM_PATTERNS,
armorMaterialsForSlot,
type ArmorPreviewConfig,
createDefaultArmorPreviewConfig,
} from '@modrinth/ui'
const STORAGE_KEY = 'axolotl:skin-armor-preview'
function includes<T extends string>(values: readonly T[], value: unknown): value is T {
return typeof value === 'string' && values.some((item) => item === value)
}
export function loadSkinArmorPreview(): ArmorPreviewConfig {
const config = createDefaultArmorPreviewConfig()
try {
const saved = JSON.parse(globalThis.localStorage?.getItem(STORAGE_KEY) ?? 'null')
if (!saved || typeof saved !== 'object' || Array.isArray(saved)) return config
for (const slot of ARMOR_SLOTS) {
const piece = saved[slot]
if (!piece || typeof piece !== 'object' || Array.isArray(piece)) continue
if (piece.material === null || includes(armorMaterialsForSlot(slot), piece.material)) {
config[slot].material = piece.material
}
if (piece.trimPattern === null || includes(ARMOR_TRIM_PATTERNS, piece.trimPattern)) {
config[slot].trimPattern = piece.trimPattern
}
if (includes(ARMOR_TRIM_MATERIALS, piece.trimMaterial)) {
config[slot].trimMaterial = piece.trimMaterial
}
}
} catch {
// Invalid or unavailable local storage falls back to a fresh preview.
}
return config
}
export function saveSkinArmorPreview(config: ArmorPreviewConfig): void {
try {
globalThis.localStorage?.setItem(STORAGE_KEY, JSON.stringify(config))
} catch {
// The preview remains usable when local storage is unavailable.
}
}
+122 -8
View File
@@ -9,9 +9,13 @@ import {
SpinnerIcon,
} from '@modrinth/assets'
import {
type ArmorPreviewConfig,
ArmorPreviewControls,
ButtonStyled,
cloneArmorPreviewConfig,
commonMessages,
ConfirmModal,
createDefaultArmorPreviewConfig,
defineMessages,
injectNotificationManager,
NavTabs,
@@ -24,12 +28,14 @@ import { invoke } from '@tauri-apps/api/core'
import type { DragDropEvent } from '@tauri-apps/api/webview'
import { getCurrentWebview } from '@tauri-apps/api/webview'
import { computedAsync } from '@vueuse/core'
import type { Ref } from 'vue'
import type { ComponentPublicInstance, Ref } from 'vue'
import { computed, inject, onMounted, onUnmounted, ref, useTemplateRef, watch } from 'vue'
import { onBeforeRouteLeave, useRouter } from 'vue-router'
import type AccountsCard from '@/components/ui/AccountsCard.vue'
import ArmorTrimTab from '@/components/ui/skin/ArmorTrimTab.vue'
import EditSkinModal from '@/components/ui/skin/EditSkinModal.vue'
import SkinListSkeleton from '@/components/ui/skin/SkinListSkeleton.vue'
import VirtualSkinSectionList from '@/components/ui/skin/VirtualSkinSectionList.vue'
import {
openSkinSiteLogin,
@@ -45,6 +51,7 @@ import { useNetworkStatus } from '@/composables/useNetworkStatus'
import { check_reachable, get_default_user, users } from '@/helpers/auth'
import type { RenderResult } from '@/helpers/rendering/batch-skin-renderer.ts'
import { skinBlobUrlMap } from '@/helpers/rendering/batch-skin-renderer.ts'
import { loadSkinArmorPreview, saveSkinArmorPreview } from '@/helpers/skin-armor-preview'
import type { Cape, Skin, SkinTextureUrl } from '@/helpers/skins.ts'
import {
determineModelType,
@@ -252,6 +259,8 @@ const editSkinModal = useTemplateRef('editSkinModal')
const addSkinFileInput = useTemplateRef<HTMLInputElement>('addSkinFileInput')
const skinSectionList = useTemplateRef<VirtualSkinSectionListExpose>('skinSectionList')
const skinPreviewArea = useTemplateRef<HTMLElement>('skinPreviewArea')
const armorTrimTab = useTemplateRef<ComponentPublicInstance>('armorTrimTab')
const armorPreviewControls = useTemplateRef<ComponentPublicInstance>('armorPreviewControls')
const { formatMessage } = useVIntl()
const router = useRouter()
@@ -391,7 +400,8 @@ const isAddSkinButtonDragActive = ref(false)
const deleteSkinModal = ref()
const skinToDelete = ref<Skin | null>(null)
const skinListTab = ref<'saved' | 'default'>('saved')
const lastSkinListTab = ref<'saved' | 'default'>('saved')
const skinListTab = ref<'saved' | 'default' | 'armor'>('saved')
const skinListTabLinks = computed(() => [
{
@@ -403,6 +413,70 @@ const skinListTabLinks = computed(() => [
label: formatMessage(messages.defaultTab),
},
])
const ARMOR_TRIM_PANEL_ID = 'skins-armor-trim-panel'
const savedArmorPreview = ref<ArmorPreviewConfig>(loadSkinArmorPreview())
const armorPreviewConfig = ref<ArmorPreviewConfig>(cloneArmorPreviewConfig(savedArmorPreview.value))
function saveArmorPreview() {
savedArmorPreview.value = cloneArmorPreviewConfig(armorPreviewConfig.value)
saveSkinArmorPreview(savedArmorPreview.value)
}
function resetArmorPreviewToSaved() {
armorPreviewConfig.value = cloneArmorPreviewConfig(savedArmorPreview.value)
}
function restoreDefaultArmorPreview() {
armorPreviewConfig.value = createDefaultArmorPreviewConfig()
}
/** A third tab behind the two list tabs, opened from the preview's action row. */
function openArmorTab() {
if (skinListTab.value !== 'armor') lastSkinListTab.value = skinListTab.value
skinListTab.value = 'armor'
}
/**
* Whether an element belongs to the armour surface: somewhere inside the open
* armour tab or the button that toggles it. Only those hold a focus ring that
* would be left behind when the tab closes.
*/
function isArmorPreviewElement(element: Element) {
const tabElement: unknown = armorTrimTab.value?.$el
const toggleElement: unknown = armorPreviewControls.value?.$el
return (
(tabElement instanceof Element && tabElement.contains(element)) ||
(toggleElement instanceof Element && toggleElement.contains(element))
)
}
function closeArmorTab() {
// Leaving the tab drops whatever was not saved on purpose.
resetArmorPreviewToSaved()
skinListTab.value = lastSkinListTab.value
// Escape and the toggle both leave the armour button holding focus, which
// keeps its focus ring drawn until something else is clicked. Only drop that
// ring when the focus sits on the armour surface, never on an unrelated
// control that happened to hold it when Escape was pressed.
const focused = document.activeElement
if (focused instanceof HTMLElement && isArmorPreviewElement(focused)) focused.blur()
}
/**
* The tab bar keeps the last list tab highlighted while the armour tab shows, so
* picking one of them leaves the armour tab. That transition has to drop the
* draft exactly like the toggle and Escape paths do, or it lingers on the model
* while the panel is gone.
*/
function selectSkinListTab(index: number) {
if (skinListTab.value === 'armor') resetArmorPreviewToSaved()
lastSkinListTab.value = index === 0 ? 'saved' : 'default'
skinListTab.value = lastSkinListTab.value
}
function confirmDeleteSkin(skin: Skin) {
if (isSkinManagementReadOnly.value) return
@@ -1211,6 +1285,9 @@ await loadSkins()
class="ml-5 mt-4 flex h-[calc(80vh-1rem)] items-center justify-center max-[700px]:h-[calc(50vh-1rem)]"
>
<SkinPreviewRenderer
v-model:armor-config="armorPreviewConfig"
armor-preview
:armor-controls="false"
:cape-src="capeTexture"
:texture-src="skinTexture || ''"
:variant="skinVariant"
@@ -1257,6 +1334,16 @@ await loadSkins()
<EditIcon />
{{ formatMessage(messages.editSkinButton) }}
</button>
<ArmorPreviewControls
v-if="!isSkinSiteProfile"
ref="armorPreviewControls"
v-model="armorPreviewConfig"
panel="external"
:panel-id="ARMOR_TRIM_PANEL_ID"
:open="skinListTab === 'armor'"
@open="openArmorTab"
@close="closeArmorTab"
/>
</template>
</SkinPreviewRenderer>
</div>
@@ -1265,14 +1352,10 @@ await loadSkins()
<div class="pt-2">
<div class="mb-4 flex flex-wrap items-center justify-between gap-3">
<NavTabs
:active-index="skinListTab === 'saved' ? 0 : 1"
:active-index="lastSkinListTab === 'saved' ? 0 : 1"
:links="skinListTabLinks"
mode="local"
@tab-click="
(index: number) => {
skinListTab = index === 0 ? 'saved' : 'default'
}
"
@tab-click="selectSkinListTab"
/>
<ButtonStyled v-if="!isSkinSiteProfile" color="brand">
<button @click="router.push('/lab/skin-editor')">
@@ -1281,7 +1364,11 @@ await loadSkins()
</button>
</ButtonStyled>
</div>
<Transition name="armor-tab" mode="out-in">
<div v-if="skinListTab !== 'armor'" key="list">
<SkinListSkeleton v-if="isSkinListBuffering" />
<VirtualSkinSectionList
v-show="!isSkinListBuffering"
ref="skinSectionList"
:active-tab="skinListTab"
:saved-skins="savedSkins"
@@ -1303,6 +1390,20 @@ await loadSkins()
@add-skin-drop="onAddSkinDrop"
/>
</div>
<ArmorTrimTab
v-else
ref="armorTrimTab"
key="armor"
v-model="armorPreviewConfig"
:panel-id="ARMOR_TRIM_PANEL_ID"
:saved="savedArmorPreview"
@save="saveArmorPreview"
@reset="resetArmorPreviewToSaved"
@defaults="restoreDefaultArmorPreview"
@close="closeArmorTab"
/>
</Transition>
</div>
</div>
<div
@@ -1382,4 +1483,17 @@ await loadSkins()
grid-template-columns: 1fr;
}
}
// The armour tab crossfades with the skin list it replaces.
.armor-tab-enter-active,
.armor-tab-leave-active {
transition:
opacity 180ms ease,
transform 180ms ease;
}
.armor-tab-enter-from,
.armor-tab-leave-to {
opacity: 0;
transform: translateY(0.5rem);
}
</style>
+1 -1
View File
@@ -19,7 +19,7 @@ use uuid::Uuid;
use crate::{ErrorKind, State};
const CATALOG_SOURCE: &str = "LobeHub 906b10e03029648655e0257bda4f785a9e0973f0";
const CATALOG_SOURCE: &str = "LobeHub 6c7a6fb033e443bc27bf34cbd5509ab3db7f22f3";
const KEYRING_PREFIX: &str = "ai-provider";
const OAUTH_CREDENTIAL: &str = "oauth";
const API_KEY_CREDENTIAL: &str = "api-key";
+270 -240
View File
@@ -1,5 +1,5 @@
{
"source": "LobeHub 906b10e03029648655e0257bda4f785a9e0973f0 model-bank chat models",
"source": "LobeHub 6c7a6fb033e443bc27bf34cbd5509ab3db7f22f3 model-bank chat models",
"providers": {
"ai21": [
{
@@ -203,6 +203,16 @@
}
],
"aihubmix": [
{
"id": "gpt-6-sol",
"name": "GPT-6 Sol",
"enabled": true
},
{
"id": "gpt-6-luna",
"name": "GPT-6 Luna",
"enabled": true
},
{
"id": "gpt-5.5",
"name": "GPT-5.5",
@@ -343,6 +353,11 @@
"name": "ChatGPT-4o",
"enabled": false
},
{
"id": "grok-4.7",
"name": "Grok 4.7",
"enabled": true
},
{
"id": "grok-4-20-non-reasoning",
"name": "Grok 4.20 (Non-Reasoning)",
@@ -368,6 +383,11 @@
"name": "Grok 3 Mini",
"enabled": false
},
{
"id": "claude-opus-5-5",
"name": "Claude Opus 5.5",
"enabled": true
},
{
"id": "claude-opus-4-7",
"name": "Claude Opus 4.7",
@@ -383,11 +403,6 @@
"name": "Claude Opus 4.5",
"enabled": false
},
{
"id": "claude-opus-4-1-20250805",
"name": "Claude Opus 4.1",
"enabled": false
},
{
"id": "claude-sonnet-4-6",
"name": "Claude Sonnet 4.6",
@@ -403,6 +418,21 @@
"name": "Claude Haiku 4.5",
"enabled": true
},
{
"id": "mimo-v2.6-pro",
"name": "MiMo-V2.6 Pro",
"enabled": true
},
{
"id": "mimo-v2.6-pro-ultraspeed",
"name": "MiMo-V2.6 Pro UltraSpeed",
"enabled": true
},
{
"id": "mimo-v2.6-flash",
"name": "MiMo-V2.6 Flash",
"enabled": true
},
{
"id": "DeepSeek-V3.1-Think",
"name": "DeepSeek V3.1 (Think)",
@@ -542,11 +572,6 @@
"name": "Ring-2.6-1T",
"enabled": true
},
{
"id": "Ring-2.5-1T",
"name": "Ring-2.5-1T",
"enabled": false
},
{
"id": "Ling-3.0-flash",
"name": "Ling-3.0-flash",
@@ -561,14 +586,14 @@
"id": "Ling-2.6-flash",
"name": "Ling-2.6-flash",
"enabled": false
},
{
"id": "Ling-2.5-1T",
"name": "Ling-2.5-1T",
"enabled": false
}
],
"anthropic": [
{
"id": "claude-opus-5-5",
"name": "Claude Opus 5.5",
"enabled": true
},
{
"id": "claude-fable-5-1",
"name": "Claude Fable 5.1",
@@ -623,14 +648,24 @@
"id": "claude-haiku-4-5-20251001",
"name": "Claude Haiku 4.5",
"enabled": true
},
{
"id": "claude-opus-4-1-20250805",
"name": "Claude Opus 4.1",
"enabled": false
}
],
"azure": [
{
"id": "gpt-6-astra",
"name": "GPT-6 Astra",
"enabled": true
},
{
"id": "gpt-6-sol",
"name": "GPT-6 Sol",
"enabled": true
},
{
"id": "gpt-6-luna",
"name": "GPT-6 Luna",
"enabled": true
},
{
"id": "gpt-5.4",
"name": "GPT-5.4",
@@ -914,6 +949,11 @@
}
],
"bedrock": [
{
"id": "global.anthropic.claude-opus-5-5",
"name": "Claude Opus 5.5",
"enabled": true
},
{
"id": "global.anthropic.claude-opus-4-7",
"name": "Claude Opus 4.7",
@@ -1030,14 +1070,29 @@
"id": "gpt-oss-120b",
"name": "GPT OSS 120B",
"enabled": false
},
{
"id": "zai-glm-4.7",
"name": "GLM-4.7",
"enabled": false
}
],
"chatgpt": [
{
"id": "gpt-6.1-sol",
"name": "GPT-6.1 Sol",
"enabled": true
},
{
"id": "gpt-6-astra",
"name": "GPT-6 Astra",
"enabled": true
},
{
"id": "gpt-6-sol",
"name": "GPT-6 Sol",
"enabled": true
},
{
"id": "gpt-6-luna",
"name": "GPT-6 Luna",
"enabled": true
},
{
"id": "gpt-5.6-sol",
"name": "GPT-5.6 Sol",
@@ -1056,7 +1111,7 @@
{
"id": "gpt-5.5",
"name": "GPT-5.5",
"enabled": true
"enabled": false
}
],
"cloudflare": [
@@ -1883,10 +1938,15 @@
"name": "Gemini Flash-Lite Latest",
"enabled": false
},
{
"id": "gemini-3.8-flash",
"name": "Gemini 3.8 Flash",
"enabled": true
},
{
"id": "gemini-3.7-flash",
"name": "Gemini 3.7 Flash",
"enabled": true
"enabled": false
},
{
"id": "gemini-3.6-flash",
@@ -1972,26 +2032,6 @@
"id": "gemini-2.5-flash-lite",
"name": "Gemini 2.5 Flash-Lite",
"enabled": false
},
{
"id": "gemini-2.0-flash",
"name": "Gemini 2.0 Flash",
"enabled": false
},
{
"id": "gemini-2.0-flash-001",
"name": "Gemini 2.0 Flash 001",
"enabled": false
},
{
"id": "gemini-2.0-flash-lite",
"name": "Gemini 2.0 Flash-Lite",
"enabled": false
},
{
"id": "gemini-2.0-flash-lite-001",
"name": "Gemini 2.0 Flash-Lite 001",
"enabled": false
}
],
"groq": [
@@ -2005,10 +2045,15 @@
"name": "Compound Mini",
"enabled": false
},
{
"id": "qwen/qwen3.8-27b",
"name": "Qwen3.8 27B",
"enabled": true
},
{
"id": "qwen/qwen3.6-27b",
"name": "Qwen3.6 27B",
"enabled": true
"enabled": false
},
{
"id": "minimaxai/minimax-m2.7",
@@ -2025,16 +2070,6 @@
"name": "GPT OSS 20B",
"enabled": false
},
{
"id": "llama-3.1-8b-instant",
"name": "Llama 3.1 8B Instant",
"enabled": false
},
{
"id": "llama-3.3-70b-versatile",
"name": "Llama 3.3 70B Versatile",
"enabled": false
},
{
"id": "meta-llama/llama-prompt-guard-2-22m",
"name": "Llama Prompt Guard 2 22M",
@@ -3575,13 +3610,13 @@
],
"mistral": [
{
"id": "mistral-medium-3.5",
"name": "Mistral Medium 3.5",
"enabled": true
"id": "zai-glm-5-2",
"name": "Z.ai GLM 5.2",
"enabled": false
},
{
"id": "devstral-2512",
"name": "Devstral 2",
"id": "mistral-medium-3.5",
"name": "Mistral Medium 3.5",
"enabled": true
},
{
@@ -3589,61 +3624,21 @@
"name": "Devstral Small 2",
"enabled": false
},
{
"id": "mistral-medium-2508",
"name": "Mistral Medium 3.1",
"enabled": false
},
{
"id": "magistral-medium-2509",
"name": "Magistral Medium 1.2",
"enabled": false
},
{
"id": "magistral-small-2509",
"name": "Magistral Small 1.2",
"enabled": false
},
{
"id": "open-mistral-nemo",
"name": "Mistral Nemo",
"enabled": false
},
{
"id": "mistral-small-2603",
"name": "Mistral Small 4",
"enabled": false
},
{
"id": "mistral-small-2506",
"name": "Mistral Small 3.2",
"enabled": false
},
{
"id": "mistral-large-2512",
"name": "Mistral Large 3",
"enabled": true
},
{
"id": "mistral-large-2411",
"name": "Mistral Large 2.1",
"enabled": false
},
{
"id": "codestral-latest",
"name": "Codestral 2508",
"enabled": false
},
{
"id": "pixtral-large-latest",
"name": "Pixtral Large",
"enabled": false
},
{
"id": "pixtral-12b-2409",
"name": "Pixtral 12B",
"enabled": false
},
{
"id": "ministral-3b-latest",
"name": "Ministral 3B",
@@ -3653,16 +3648,6 @@
"id": "ministral-8b-latest",
"name": "Ministral 8B",
"enabled": false
},
{
"id": "open-codestral-mamba",
"name": "Codestral Mamba",
"enabled": false
},
{
"id": "labs-leanstral-2603",
"name": "Leanstral",
"enabled": false
}
],
"modelscope": [
@@ -3676,30 +3661,10 @@
"name": "Qwen3 Next 80B A3B Instruct",
"enabled": false
},
{
"id": "deepseek-ai/DeepSeek-V3.2",
"name": "DeepSeek V3.2",
"enabled": true
},
{
"id": "deepseek-ai/DeepSeek-V3.2-Exp",
"name": "DeepSeek V3.2 Exp",
"enabled": false
},
{
"id": "deepseek-ai/DeepSeek-V3.1",
"name": "DeepSeek V3.1",
"enabled": false
},
{
"id": "Qwen/Qwen3-235B-A22B",
"name": "Qwen3 235B A22B",
"enabled": false
},
{
"id": "Qwen/Qwen3-32B",
"name": "Qwen3 32B",
"enabled": false
}
],
"moonshot": [
@@ -3722,41 +3687,6 @@
"id": "kimi-k2.6",
"name": "Kimi K2.6",
"enabled": false
},
{
"id": "kimi-k2.5",
"name": "Kimi K2.5",
"enabled": false
},
{
"id": "moonshot-v1-8k",
"name": "Moonshot V1 8K",
"enabled": false
},
{
"id": "moonshot-v1-32k",
"name": "Moonshot V1 32K",
"enabled": false
},
{
"id": "moonshot-v1-128k",
"name": "Moonshot V1 128K",
"enabled": false
},
{
"id": "moonshot-v1-8k-vision-preview",
"name": "Moonshot V1 8K Vision Preview",
"enabled": false
},
{
"id": "moonshot-v1-32k-vision-preview",
"name": "Moonshot V1 32K Vision Preview",
"enabled": false
},
{
"id": "moonshot-v1-128k-vision-preview",
"name": "Moonshot V1 128K Vision Preview",
"enabled": false
}
],
"nebius": [
@@ -4424,16 +4354,6 @@
"name": "Qwen3.5 397B A17B",
"enabled": false
},
{
"id": "minimax-m2.5",
"name": "MiniMax M2.5",
"enabled": false
},
{
"id": "kimi-k2.5",
"name": "Kimi K2.5",
"enabled": false
},
{
"id": "gpt-oss:20b",
"name": "GPT-OSS 20B",
@@ -4451,6 +4371,26 @@
}
],
"openai": [
{
"id": "gpt-6.1-sol",
"name": "GPT-6.1 Sol",
"enabled": true
},
{
"id": "gpt-6-astra",
"name": "GPT-6 Astra",
"enabled": true
},
{
"id": "gpt-6-sol",
"name": "GPT-6 Sol",
"enabled": true
},
{
"id": "gpt-6-luna",
"name": "GPT-6 Luna",
"enabled": true
},
{
"id": "chat-latest",
"name": "Chat Latest",
@@ -4474,7 +4414,7 @@
{
"id": "gpt-5.5",
"name": "GPT-5.5",
"enabled": true
"enabled": false
},
{
"id": "gpt-5.5-pro",
@@ -4484,7 +4424,7 @@
{
"id": "gpt-5.4",
"name": "GPT-5.4",
"enabled": true
"enabled": false
},
{
"id": "gpt-5.4-pro",
@@ -4494,7 +4434,7 @@
{
"id": "gpt-5.4-mini",
"name": "GPT-5.4 mini",
"enabled": true
"enabled": false
},
{
"id": "gpt-5.4-nano",
@@ -4708,6 +4648,16 @@
"name": "MiniMax M3",
"enabled": false
},
{
"id": "muse-spark-1.2-contributor",
"name": "Muse Spark 1.2 Contributor",
"enabled": false
},
{
"id": "muse-spark-1.3-contributor",
"name": "Muse Spark 1.3 Contributor",
"enabled": true
},
{
"id": "qwen3.6-plus",
"name": "Qwen3.6 Plus",
@@ -4912,6 +4862,41 @@
"name": "Auto (best for prompt)",
"enabled": true
},
{
"id": "anthropic/claude-opus-5.5",
"name": "Claude Opus 5.5",
"enabled": true
},
{
"id": "openai/gpt-6-sol",
"name": "GPT-6 Sol",
"enabled": true
},
{
"id": "openai/gpt-6-luna",
"name": "GPT-6 Luna",
"enabled": true
},
{
"id": "x-ai/grok-4.7",
"name": "Grok 4.7",
"enabled": true
},
{
"id": "xiaomi/mimo-v2.6-pro",
"name": "MiMo-V2.6 Pro",
"enabled": true
},
{
"id": "xiaomi/mimo-v2.6-pro-ultraspeed",
"name": "MiMo-V2.6 Pro UltraSpeed",
"enabled": true
},
{
"id": "xiaomi/mimo-v2.6-flash",
"name": "MiMo-V2.6 Flash",
"enabled": true
},
{
"id": "deepseek/deepseek-chat-v3.1",
"name": "DeepSeek V3.1",
@@ -5260,6 +5245,26 @@
}
],
"qwen": [
{
"id": "deepseek-v4-pro-0813",
"name": "DeepSeek V4 Pro 0813",
"enabled": false
},
{
"id": "deepseek-v4-flash-0731",
"name": "DeepSeek V4 Flash 0731",
"enabled": false
},
{
"id": "qwen3.8-max-0902",
"name": "Qwen3.8 Max 0902",
"enabled": true
},
{
"id": "qwen3.8-max",
"name": "Qwen3.8 Max",
"enabled": true
},
{
"id": "kimi-k2.6",
"name": "Kimi K2.6",
@@ -5490,10 +5495,15 @@
"name": "QwQ Plus",
"enabled": false
},
{
"id": "qwen3.8-flash",
"name": "Qwen3.8 Flash",
"enabled": true
},
{
"id": "qwen3.7-flash",
"name": "Qwen3.7 Flash",
"enabled": true
"enabled": false
},
{
"id": "qwen3.6-flash",
@@ -5802,75 +5812,40 @@
}
],
"sambanova": [
{
"id": "MiniMax-M2.7",
"name": "MiniMax M2.7",
"enabled": false
},
{
"id": "DeepSeek-V3.1",
"name": "DeepSeek V3.1",
"enabled": false
},
{
"id": "Meta-Llama-3.3-70B-Instruct",
"name": "Meta Llama 3.3 70B Instruct",
"enabled": true
},
{
"id": "Meta-Llama-3.2-1B-Instruct",
"name": "Meta Llama 3.2 1B Instruct",
"enabled": false
},
{
"id": "Meta-Llama-3.2-3B-Instruct",
"name": "Meta Llama 3.2 3B Instruct",
"enabled": false
},
{
"id": "Llama-3.2-11B-Vision-Instruct",
"name": "Meta Llama 3.2 11B Vision Instruct",
"id": "gpt-oss-120b",
"name": "GPT OSS 120B",
"enabled": true
},
{
"id": "Llama-3.2-90B-Vision-Instruct",
"name": "Meta Llama 3.2 90B Vision Instruct",
"id": "MiniMax-M3",
"name": "MiniMax M3",
"enabled": true
},
{
"id": "Meta-Llama-3.1-8B-Instruct",
"name": "Meta Llama 3.1 8B Instruct",
"id": "DeepSeek-V3.2",
"name": "DeepSeek V3.2",
"enabled": false
},
{
"id": "Meta-Llama-3.1-70B-Instruct",
"name": "Meta Llama 3.1 70B Instruct",
"id": "gemma-4-31B-it",
"name": "Gemma 4 31B IT",
"enabled": false
},
{
"id": "Meta-Llama-3.1-405B-Instruct",
"name": "Meta Llama 3.1 405B Instruct",
"enabled": false
},
{
"id": "Llama-3.1-Tulu-3-405B",
"name": "Llama 3.1 Tulu 3 405B",
"enabled": false
},
{
"id": "DeepSeek-R1",
"name": "DeepSeek R1",
"enabled": false
},
{
"id": "DeepSeek-R1-Distill-Llama-70B",
"name": "DeepSeek R1 Distill Llama 70B",
"enabled": true
},
{
"id": "QwQ-32B-Preview",
"name": "QwQ 32B Preview",
"enabled": true
},
{
"id": "Qwen2.5-72B-Instruct",
"name": "Qwen2.5 72B Instruct",
"enabled": true
},
{
"id": "Qwen2.5-Coder-32B-Instruct",
"name": "Qwen2.5 Coder 32B Instruct",
"enabled": true
}
],
"search1api": [
@@ -6262,6 +6237,11 @@
}
],
"stepfun": [
{
"id": "step-5-preview",
"name": "Step 5 Preview",
"enabled": true
},
{
"id": "step-3.7-flash",
"name": "Step 3.7 Flash",
@@ -6407,6 +6387,16 @@
}
],
"supergrok": [
{
"id": "grok-4.7",
"name": "Grok 4.7",
"enabled": true
},
{
"id": "grok-4.6",
"name": "Grok 4.6",
"enabled": true
},
{
"id": "grok-4.5",
"name": "Grok 4.5",
@@ -7166,10 +7156,15 @@
}
],
"vertexai": [
{
"id": "gemini-3.8-flash",
"name": "Gemini 3.8 Flash",
"enabled": true
},
{
"id": "gemini-3.7-flash",
"name": "Gemini 3.7 Flash",
"enabled": true
"enabled": false
},
{
"id": "gemini-3.6-flash",
@@ -7345,20 +7340,30 @@
"name": "Doubao Seed 2.1 Turbo",
"enabled": true
},
{
"id": "deepseek-v4-pro-ga",
"name": "DeepSeek V4 Pro 0813",
"enabled": false
},
{
"id": "deepseek-v4-flash-ga",
"name": "DeepSeek V4 Flash 0731",
"enabled": false
},
{
"id": "glm-5-2",
"name": "GLM-5.2",
"enabled": true
"enabled": false
},
{
"id": "deepseek-v4-pro",
"name": "DeepSeek V4 Pro",
"enabled": true
"enabled": false
},
{
"id": "deepseek-v4-flash",
"name": "DeepSeek V4 Flash",
"enabled": true
"enabled": false
},
{
"id": "doubao-seed-2.0-pro",
@@ -7701,6 +7706,16 @@
}
],
"xai": [
{
"id": "grok-4.7",
"name": "Grok 4.7",
"enabled": true
},
{
"id": "grok-4.6",
"name": "Grok 4.6",
"enabled": true
},
{
"id": "grok-4.5",
"name": "Grok 4.5",
@@ -7728,6 +7743,21 @@
}
],
"xiaomimimo": [
{
"id": "mimo-v2.6-pro",
"name": "MiMo-V2.6 Pro",
"enabled": true
},
{
"id": "mimo-v2.6-pro-ultraspeed",
"name": "MiMo-V2.6 Pro UltraSpeed",
"enabled": true
},
{
"id": "mimo-v2.6-flash",
"name": "MiMo-V2.6 Flash",
"enabled": true
},
{
"id": "mimo-v2.5-pro",
"name": "MiMo-V2.5 Pro",
@@ -1,6 +1,5 @@
use crate::api::pack::import::{
ImportLauncherType,
direct_link::resolve_direct_link,
ImportLauncherType, direct_link::resolve_direct_link,
};
use crate::launcher::ExternalGameDirMode;
use crate::state::instances::{
@@ -1,7 +1,7 @@
use super::create_direct_link_instance::create_direct_link_instance;
use crate::api::pack::import::direct_link::{
detect_direct_link_source,
has_minecraft_version_manifest, resolve_direct_link,
detect_direct_link_source, has_minecraft_version_manifest,
resolve_direct_link,
};
use crate::event::{InstancePayloadType, emit::emit_instance};
use crate::launcher::ExternalGameDirMode;
Binary file not shown.

After

Width:  |  Height:  |  Size: 251 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 438 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 434 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 424 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 467 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 B

Loaded 100 of 157 files, more files were not shown because too many files have changed in this diff. Show more