Skip to content

Instantly share code, notes, and snippets.

@karminski
Created September 18, 2025 19:40
Show Gist options
  • Select an option

  • Save karminski/0a9a231275cbf14808ff168266cc9553 to your computer and use it in GitHub Desktop.

Select an option

Save karminski/0a9a231275cbf14808ff168266cc9553 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name iPhone 17 Pro Custom Color Palette
// @namespace http://tampermonkey.net/
// @version 0.3
// @description iPhone 3D model with full color palette
// @author karminski-牙医
// @match https://www.apple.com.cn/iphone-17-pro/
// @grant none
// ==/UserScript==
(function () {
'use strict';
console.log('🎯 iPhone Color Palette Script Loaded');
// 调试工具
const debug = {
log: (type, ...args) => {
console.log(`🔍 [${type}]`, ...args);
}
};
// 当前选中的颜色
let currentCustomColor = null;
// 1. 网络请求拦截(保持原有功能)
function interceptAllRequests() {
const originalFetch = window.fetch;
window.fetch = function (...args) {
const url = typeof args[0] === 'string' ? args[0] : args[0].url;
if (url && (url.includes('.avif') || url.includes('.jpg') || url.includes('.png'))) {
debug.log('Texture', '🎨 Found asset:', url);
}
return originalFetch.apply(this, args);
};
}
// 2. 监听颜色选择变化(保持原有功能)
function monitorColorChanges() {
document.addEventListener('change', function (e) {
if (e.target && e.target.name === 'colornav-variant-default') {
const selectedColor = e.target.value;
debug.log('Color', '🎨 Color changed to:', selectedColor);
setTimeout(() => applyCustomColorLogic(selectedColor), 100);
}
});
}
// 3. 颜色转换工具
const ColorUtils = {
// HEX转HSL
hexToHsl(hex) {
const r = parseInt(hex.slice(1, 3), 16) / 255;
const g = parseInt(hex.slice(3, 5), 16) / 255;
const b = parseInt(hex.slice(5, 7), 16) / 255;
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
let h, s, l = (max + min) / 2;
if (max === min) {
h = s = 0;
} else {
const d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return [h * 360, s * 100, l * 100];
},
// 根据颜色生成CSS滤镜
colorToFilter(hex) {
const [h, s, l] = this.hexToHsl(hex);
// 基于HSL值计算滤镜参数
const hueRotate = Math.round(h);
const saturate = Math.round((s / 50) * 100) / 100;
const brightness = Math.round((l / 50) * 100) / 100;
const contrast = saturate > 1 ? saturate * 0.8 : 1;
return `hue-rotate(${hueRotate}deg) saturate(${saturate}) brightness(${brightness}) contrast(${contrast})`;
},
// 预设颜色配置
presets: {
'曼巴': '#2a4ba7',
'桃花运': '#c1a9b7',
'死亡芭比': '#c1498f',
'SU7': '#5cc7a3',
'辐射': '#a4ce64',
'老冰种': '#9fb3bc',
'月壤': '#6b6b6b',
'黄金精神': '#fdbb49',
'茄子': '#865997',
}
};
// 4. 应用自定义颜色
function applyCustomColorLogic(color, isHex = false) {
debug.log('Custom', '🎯 Applying color:', color);
const viewer = document.querySelector('.product-viewer-enhanced');
const canvas = document.querySelector('.product-viewer-enhanced-container');
if (viewer || canvas) {
let filterValue;
if (isHex) {
// 自定义十六进制颜色
filterValue = ColorUtils.colorToFilter(color);
currentCustomColor = color;
} else {
// 预设颜色或原始颜色
if (ColorUtils.presets[color]) {
filterValue = ColorUtils.colorToFilter(ColorUtils.presets[color]);
currentCustomColor = ColorUtils.presets[color];
} else {
// 原始苹果颜色的滤镜
const originalFilters = {
'Orange': 'none',
'Blue': 'hue-rotate(200deg) saturate(1.2)',
'Silver': 'saturate(0.2) brightness(1.2)',
};
filterValue = originalFilters[color] || 'none';
currentCustomColor = null;
}
}
// 应用滤镜到3D模型容器
if (canvas) {
canvas.style.filter = filterValue;
debug.log('Filter', '🎨 Applied filter:', filterValue);
}
// 更新调色盘的当前颜色显示
updateColorDisplay(currentCustomColor || (ColorUtils.presets[color] || '#ff8c00'));
}
}
// 5. 更新颜色显示
function updateColorDisplay(color) {
const currentColorDiv = document.getElementById('current-color');
const colorInput = document.getElementById('color-picker');
if (currentColorDiv) {
currentColorDiv.style.backgroundColor = color;
}
if (colorInput) {
colorInput.value = color;
}
}
// 6. 创建完整的调色盘界面
function createColorPalette() {
const paletteHTML = `
<div id="color-palette-panel" style="
position: fixed;
top: 20px;
right: 20px;
z-index: 99999;
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 50%, #dee2e6 100%);
color: #343a40;
padding: 24px;
border-radius: 16px;
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', sans-serif;
box-shadow: 0 20px 40px rgba(0,0,0,0.15), 0 0 0 1px rgba(255,255,255,0.8);
backdrop-filter: blur(20px);
border: 1px solid rgba(255,255,255,0.3);
min-width: 300px;
max-height: 85vh;
overflow-y: auto;
">
<!-- 标题栏 -->
<div style="
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 16px;
border-bottom: 1px solid rgba(52, 58, 64, 0.1);
">
<h3 style="
margin: 0;
color: #495057;
font-size: 18px;
font-weight: 600;
letter-spacing: -0.02em;
">🎨 库克, 我们需要这个</h3>
<button onclick="togglePalette()" style="
background: rgba(108, 117, 125, 0.1);
border: 1px solid rgba(108, 117, 125, 0.2);
color: #6c757d;
width: 28px;
height: 28px;
border-radius: 8px;
cursor: pointer;
font-size: 14px;
font-weight: bold;
transition: all 0.2s ease;
"
onmouseover="this.style.background='rgba(108, 117, 125, 0.15)'; this.style.transform='scale(1.05)'"
onmouseout="this.style.background='rgba(108, 117, 125, 0.1)'; this.style.transform='scale(1)'">×</button>
</div>
<!-- 当前颜色显示 -->
<div style="margin-bottom: 20px;">
<div style="
font-size: 14px;
font-weight: 500;
margin-bottom: 12px;
color: #495057;
">当前颜色</div>
<div style="
display: flex;
align-items: center;
justify-content: center;
gap: 16px;
padding: 16px;
background: rgba(248, 249, 250, 0.6);
border-radius: 12px;
border: 1px solid rgba(108, 117, 125, 0.1);
">
<div id="current-color" style="
width: 48px;
height: 48px;
border-radius: 12px;
border: 3px solid rgba(108, 117, 125, 0.2);
background: #ff8c00;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
"></div>
<input type="color" id="color-picker" value="#ff8c00" style="
width: 48px;
height: 48px;
border: 3px solid rgba(108, 117, 125, 0.2);
border-radius: 12px;
cursor: pointer;
background: none;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
">
</div>
</div>
<!-- 预设颜色 -->
<div style="margin-bottom: 20px;">
<div style="
font-size: 14px;
font-weight: 500;
margin-bottom: 12px;
color: #495057;
">预设颜色</div>
<div id="preset-colors" style="
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
padding: 16px;
background: rgba(248, 249, 250, 0.6);
border-radius: 12px;
border: 1px solid rgba(108, 117, 125, 0.1);
max-height: 300px;
overflow-y: auto;
scrollbar-width: none;
-ms-overflow-style: none;
">
${Object.entries(ColorUtils.presets).map(([name, color]) => `
<div style="
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
">
<button onclick="applyPresetColor('${name}')" style="
background: ${color};
border: 3px solid rgba(108, 117, 125, 0.2);
width: 56px;
height: 56px;
border-radius: 12px;
cursor: pointer;
transition: all 0.3s ease;
display: block;
margin-bottom: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
"
onmouseover="this.style.transform='scale(1.1)'; this.style.boxShadow='0 6px 20px rgba(0,0,0,0.2)'"
onmouseout="this.style.transform='scale(1)'; this.style.boxShadow='0 4px 12px rgba(0,0,0,0.1)'">
</button>
<div style="
font-size: 11px;
color: #6c757d;
font-weight: 500;
text-align: center;
line-height: 1.3;
max-width: 60px;
word-wrap: break-word;
">${name}</div>
</div>
`).join('')}
</div>
</div>
<!-- 控制按钮 -->
<div style="
display: flex;
gap: 12px;
margin-bottom: 20px;
">
<button onclick="resetToOriginal()" style="
flex: 1;
padding: 12px 16px;
background: linear-gradient(135deg, #f8f9fa, #e9ecef);
border: 1px solid rgba(108, 117, 125, 0.2);
color: #495057;
border-radius: 8px;
cursor: pointer;
font-size: 13px;
font-weight: 500;
transition: all 0.2s ease;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
"
onmouseover="this.style.background='linear-gradient(135deg, #e9ecef, #dee2e6)'; this.style.transform='translateY(-1px)'; this.style.boxShadow='0 4px 8px rgba(0,0,0,0.1)'"
onmouseout="this.style.background='linear-gradient(135deg, #f8f9fa, #e9ecef)'; this.style.transform='translateY(0)'; this.style.boxShadow='0 2px 4px rgba(0,0,0,0.05)'">重置</button>
<button onclick="randomColor()" style="
flex: 1;
padding: 12px 16px;
background: linear-gradient(135deg, #f8f9fa, #e9ecef);
border: 1px solid rgba(108, 117, 125, 0.2);
color: #495057;
border-radius: 8px;
cursor: pointer;
font-size: 13px;
font-weight: 500;
transition: all 0.2s ease;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
"
onmouseover="this.style.background='linear-gradient(135deg, #e9ecef, #dee2e6)'; this.style.transform='translateY(-1px)'; this.style.boxShadow='0 4px 8px rgba(0,0,0,0.1)'"
onmouseout="this.style.background='linear-gradient(135deg, #f8f9fa, #e9ecef)'; this.style.transform='translateY(0)'; this.style.boxShadow='0 2px 4px rgba(0,0,0,0.05)'">随机</button>
</div>
<!-- 调试信息 -->
<div style="
background: rgba(248, 249, 250, 0.8);
border: 1px solid rgba(108, 117, 125, 0.1);
padding: 12px;
border-radius: 8px;
font-size: 11px;
max-height: 80px;
overflow-y: auto;
" id="debug-mini">
<div style="color: #28a745; font-weight: 500;">✅ 调色盘已激活</div>
</div>
</div>
`;
document.body.insertAdjacentHTML('beforeend', paletteHTML);
// 添加样式增强
const style = document.createElement('style');
style.textContent = `
#preset-colors button:hover .color-tooltip {
opacity: 1 !important;
}
#preset-colors::-webkit-scrollbar {
width: 4px;
}
#preset-colors::-webkit-scrollbar-track {
background: rgba(248, 249, 250, 0.5);
border-radius: 2px;
}
#preset-colors::-webkit-scrollbar-thumb {
background: rgba(108, 117, 125, 0.3);
border-radius: 2px;
}
#color-palette-panel::-webkit-scrollbar {
width: 6px;
}
#color-palette-panel::-webkit-scrollbar-track {
background: rgba(248, 249, 250, 0.5);
border-radius: 3px;
}
#color-palette-panel::-webkit-scrollbar-thumb {
background: rgba(108, 117, 125, 0.3);
border-radius: 3px;
}
#color-palette-panel::-webkit-scrollbar-thumb:hover {
background: rgba(108, 117, 125, 0.5);
}
`;
document.head.appendChild(style);
}
// 7. 全局函数
window.applyPresetColor = function (colorName) {
debug.log('Preset', '🎨 Applying preset:', colorName);
applyCustomColorLogic(colorName);
updateDebugMini(`应用预设颜色: ${colorName}`);
};
window.togglePalette = function () {
const panel = document.getElementById('color-palette-panel');
if (panel) {
panel.style.display = panel.style.display === 'none' ? 'block' : 'none';
}
};
window.resetToOriginal = function () {
debug.log('Reset', '🔄 Resetting to original');
const canvas = document.querySelector('.product-viewer-enhanced-container');
if (canvas) {
canvas.style.filter = 'none';
}
updateColorDisplay('#ff8c00');
updateDebugMini('已重置为原始颜色');
};
window.randomColor = function () {
const randomHex = '#' + Math.floor(Math.random() * 16777215).toString(16);
debug.log('Random', '🎲 Random color:', randomHex);
applyCustomColorLogic(randomHex, true);
updateDebugMini(`随机颜色: ${randomHex}`);
};
function updateDebugMini(message) {
const debugDiv = document.getElementById('debug-mini');
if (debugDiv) {
const time = new Date().toLocaleTimeString();
debugDiv.innerHTML += `<div style="color: #60a5fa;">[${time}] ${message}</div>`;
debugDiv.scrollTop = debugDiv.scrollHeight;
}
}
// 8. 设置颜色选择器事件
function setupColorPicker() {
setTimeout(() => {
const colorInput = document.getElementById('color-picker');
if (colorInput) {
colorInput.addEventListener('input', function (e) {
const color = e.target.value;
debug.log('ColorPicker', '🎨 Custom color selected:', color);
applyCustomColorLogic(color, true);
updateDebugMini(`自定义颜色: ${color}`);
});
}
}, 1000);
}
// 9. 启动函数
function init() {
debug.log('Init', '🚀 Starting iPhone Color Palette');
interceptAllRequests();
monitorColorChanges();
// 创建调色盘界面
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
createColorPalette();
setupColorPicker();
});
} else {
createColorPalette();
setupColorPicker();
}
debug.log('Init', '✅ Color palette ready');
}
// 启动
init();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment