mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-24 19:26:39 +00:00
Add prototype UI clients
This commit is contained in:
30
client/ui-electron/scripts/check-frame0-colors.js
Normal file
30
client/ui-electron/scripts/check-frame0-colors.js
Normal file
@@ -0,0 +1,30 @@
|
||||
const fs = require('fs');
|
||||
const data = JSON.parse(fs.readFileSync('./src/assets/button-full.json', 'utf8'));
|
||||
|
||||
// Check frame 0 colors - this should be in the first asset
|
||||
const asset0 = data.assets[0]; // button start connecting (frames 0-78)
|
||||
console.log('Asset 0:', asset0.nm);
|
||||
|
||||
// Look at layer 0 which has the main shapes
|
||||
const layer0 = asset0.layers[0];
|
||||
console.log('\nLayer 0:', layer0.nm);
|
||||
|
||||
if (layer0.shapes) {
|
||||
layer0.shapes.forEach((shape, idx) => {
|
||||
console.log(`\nShape ${idx}:`, shape.nm || 'unnamed');
|
||||
if (shape.it) {
|
||||
shape.it.forEach((item, iIdx) => {
|
||||
if (item.ty === 'fl' && item.c) {
|
||||
console.log(` Item ${iIdx} (fill):`);
|
||||
console.log(` Color:`, item.c.k);
|
||||
if (item.c.k && Array.isArray(item.c.k) && item.c.k[0] && item.c.k[0].t !== undefined) {
|
||||
console.log(` Keyframes:`, item.c.k.length);
|
||||
item.c.k.slice(0, 3).forEach(kf => {
|
||||
console.log(` Frame ${kf.t}: start =`, kf.s);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
150
client/ui-electron/scripts/diagnose-frames.js
Normal file
150
client/ui-electron/scripts/diagnose-frames.js
Normal file
@@ -0,0 +1,150 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const animationPath = path.join(__dirname, '../src/assets/button-full.json');
|
||||
|
||||
console.log('Reading animation file...');
|
||||
const animationData = JSON.parse(fs.readFileSync(animationPath, 'utf8'));
|
||||
|
||||
console.log('\n🔍 Checking frames 259-339 (disconnecting fade-out)...\n');
|
||||
|
||||
// Function to check opacity at specific frames
|
||||
function checkOpacityAtFrames(obj, path = '', frameRange = { start: 259, end: 339 }) {
|
||||
const findings = [];
|
||||
|
||||
function traverse(obj, currentPath = '') {
|
||||
if (Array.isArray(obj)) {
|
||||
obj.forEach((item, index) => traverse(item, `${currentPath}[${index}]`));
|
||||
} else if (obj && typeof obj === 'object') {
|
||||
// Check for opacity keyframes
|
||||
if (obj.o && obj.o.k) {
|
||||
const opacity = obj.o.k;
|
||||
|
||||
// Animated opacity (keyframes)
|
||||
if (Array.isArray(opacity) && opacity[0] && typeof opacity[0] === 'object' && opacity[0].t !== undefined) {
|
||||
opacity.forEach((keyframe, idx) => {
|
||||
if (keyframe.t >= frameRange.start && keyframe.t <= frameRange.end) {
|
||||
const value = keyframe.s ? keyframe.s[0] : null;
|
||||
if (value !== null && value < 50) {
|
||||
findings.push({
|
||||
path: currentPath,
|
||||
frame: keyframe.t,
|
||||
opacity: value,
|
||||
type: 'keyframe'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// Static opacity
|
||||
else if (typeof opacity === 'number') {
|
||||
if (opacity < 50) {
|
||||
findings.push({
|
||||
path: currentPath,
|
||||
opacity: opacity,
|
||||
type: 'static'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Recursively process all properties
|
||||
for (const key in obj) {
|
||||
traverse(obj[key], `${currentPath}.${key}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
traverse(obj, path);
|
||||
return findings;
|
||||
}
|
||||
|
||||
// Check main layers
|
||||
console.log('📊 Checking main layers:');
|
||||
if (animationData.layers) {
|
||||
const findings = checkOpacityAtFrames(animationData.layers, 'layers');
|
||||
if (findings.length > 0) {
|
||||
console.log(` ⚠️ Found ${findings.length} opacity issues:`);
|
||||
findings.forEach(f => {
|
||||
console.log(` - ${f.path}`);
|
||||
console.log(` ${f.type === 'keyframe' ? `Frame ${f.frame}:` : 'Static:'} opacity = ${f.opacity}`);
|
||||
});
|
||||
} else {
|
||||
console.log(' ✅ No low opacity values found in main layers');
|
||||
}
|
||||
}
|
||||
|
||||
// Check assets (compositions)
|
||||
console.log('\n📊 Checking asset compositions:');
|
||||
if (animationData.assets) {
|
||||
animationData.assets.forEach((asset, idx) => {
|
||||
if (asset.layers) {
|
||||
const findings = checkOpacityAtFrames(asset.layers, `assets[${idx}].layers`);
|
||||
if (findings.length > 0) {
|
||||
console.log(` ⚠️ Asset "${asset.nm || asset.id}" has ${findings.length} opacity issues:`);
|
||||
findings.forEach(f => {
|
||||
console.log(` - ${f.path}`);
|
||||
console.log(` ${f.type === 'keyframe' ? `Frame ${f.frame}:` : 'Static:'} opacity = ${f.opacity}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Also check for in/out points that might hide layers during this range
|
||||
console.log('\n📊 Checking layer in/out points (frames 259-339):');
|
||||
|
||||
function checkLayerTiming(layers, prefix = '') {
|
||||
const issues = [];
|
||||
layers.forEach((layer, idx) => {
|
||||
const layerName = layer.nm || `Layer ${idx}`;
|
||||
const inPoint = layer.ip !== undefined ? layer.ip : 0;
|
||||
const outPoint = layer.op !== undefined ? layer.op : 999;
|
||||
|
||||
// Check if layer is hidden during our critical range (259-339)
|
||||
if (outPoint < 339 || inPoint > 259) {
|
||||
if (!(inPoint > 339 || outPoint < 259)) {
|
||||
// Layer is partially visible in our range
|
||||
issues.push({
|
||||
name: layerName,
|
||||
inPoint: inPoint,
|
||||
outPoint: outPoint,
|
||||
issue: outPoint < 339 ? `ends at frame ${outPoint} (before 339)` : `starts at frame ${inPoint} (after 259)`
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return issues;
|
||||
}
|
||||
|
||||
if (animationData.layers) {
|
||||
const timingIssues = checkLayerTiming(animationData.layers);
|
||||
if (timingIssues.length > 0) {
|
||||
console.log(' ⚠️ Found layers with timing issues:');
|
||||
timingIssues.forEach(issue => {
|
||||
console.log(` - "${issue.name}": in=${issue.inPoint}, out=${issue.outPoint}`);
|
||||
console.log(` Issue: ${issue.issue}`);
|
||||
});
|
||||
} else {
|
||||
console.log(' ✅ All main layers are visible throughout frames 259-339');
|
||||
}
|
||||
}
|
||||
|
||||
if (animationData.assets) {
|
||||
animationData.assets.forEach((asset, idx) => {
|
||||
if (asset.layers) {
|
||||
const timingIssues = checkLayerTiming(asset.layers);
|
||||
if (timingIssues.length > 0) {
|
||||
console.log(` ⚠️ Asset "${asset.nm || asset.id}" has timing issues:`);
|
||||
timingIssues.forEach(issue => {
|
||||
console.log(` - "${issue.name}": in=${issue.inPoint}, out=${issue.outPoint}`);
|
||||
console.log(` Issue: ${issue.issue}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
console.log('\n✅ Diagnosis complete!');
|
||||
72
client/ui-electron/scripts/fix-animation-bg.js
Normal file
72
client/ui-electron/scripts/fix-animation-bg.js
Normal file
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const animationPath = path.join(__dirname, '../src/assets/button-full.json');
|
||||
|
||||
console.log('Reading animation file...');
|
||||
const animationData = JSON.parse(fs.readFileSync(animationPath, 'utf8'));
|
||||
|
||||
// Function to recursively find and modify background layers
|
||||
function removeBackgrounds(obj) {
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map(item => removeBackgrounds(item));
|
||||
} else if (obj && typeof obj === 'object') {
|
||||
// Check if this is a layer with "Shape Layer" in the name
|
||||
if (obj.nm && (obj.nm.includes('Shape Layer') || obj.nm.includes('background'))) {
|
||||
console.log(`Found potential background layer: ${obj.nm}`);
|
||||
|
||||
// Look for fill color in shapes
|
||||
if (obj.shapes) {
|
||||
obj.shapes = obj.shapes.map(shape => {
|
||||
if (shape.it) {
|
||||
shape.it = shape.it.map(item => {
|
||||
// If it's a fill with white/light color, make it transparent
|
||||
if (item.ty === 'fl' && item.c && item.c.k) {
|
||||
const color = item.c.k;
|
||||
// Check if it's a white or very light gray (close to 1.0 in RGB)
|
||||
if (Array.isArray(color) && color.length >= 3) {
|
||||
const [r, g, b] = color;
|
||||
if (r > 0.8 && g > 0.8 && b > 0.8) {
|
||||
console.log(` Removing white fill from ${obj.nm}`);
|
||||
item.o = { a: 0, k: 0, ix: 5 }; // Set opacity to 0
|
||||
}
|
||||
}
|
||||
}
|
||||
return item;
|
||||
});
|
||||
}
|
||||
return shape;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Recursively process all properties
|
||||
const result = {};
|
||||
for (const key in obj) {
|
||||
result[key] = removeBackgrounds(obj[key]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
console.log('Processing animation layers...');
|
||||
animationData.layers = removeBackgrounds(animationData.layers);
|
||||
|
||||
// Also check for asset compositions
|
||||
if (animationData.assets) {
|
||||
console.log('Processing animation assets...');
|
||||
animationData.assets = animationData.assets.map(asset => {
|
||||
if (asset.layers) {
|
||||
asset.layers = removeBackgrounds(asset.layers);
|
||||
}
|
||||
return asset;
|
||||
});
|
||||
}
|
||||
|
||||
console.log('Writing modified animation...');
|
||||
fs.writeFileSync(animationPath, JSON.stringify(animationData, null, 2));
|
||||
|
||||
console.log('✓ Animation background modified successfully!');
|
||||
95
client/ui-electron/scripts/update-animation-colors-smart.js
Normal file
95
client/ui-electron/scripts/update-animation-colors-smart.js
Normal file
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const animationPath = path.join(__dirname, '../src/assets/button-full.json');
|
||||
|
||||
console.log('Reading animation file...');
|
||||
const animationData = JSON.parse(fs.readFileSync(animationPath, 'utf8'));
|
||||
|
||||
// Icy blue color: #a3d7e5 -> RGB normalized: [0.639, 0.843, 0.898]
|
||||
const ICY_BLUE = [0.639, 0.843, 0.898, 1];
|
||||
|
||||
function isOrangeColor(color) {
|
||||
if (!Array.isArray(color) || color.length < 3) return false;
|
||||
const [r, g, b] = color;
|
||||
// Check if it's orange-ish (high red, medium green, low blue)
|
||||
return r > 0.85 && g > 0.3 && g < 0.6 && b < 0.3;
|
||||
}
|
||||
|
||||
// Function to recursively find and modify orange colors
|
||||
function replaceOrangeWithIcyBlue(obj, path = '') {
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map((item, index) => replaceOrangeWithIcyBlue(item, `${path}[${index}]`));
|
||||
} else if (obj && typeof obj === 'object') {
|
||||
// Check if this object has a color property 'c' with keyframe data 'k'
|
||||
if (obj.c && obj.c.k) {
|
||||
const color = obj.c.k;
|
||||
|
||||
// Handle static color (array)
|
||||
if (Array.isArray(color) && isOrangeColor(color)) {
|
||||
console.log(` Replacing orange color at ${path} -> icy blue`);
|
||||
obj.c.k = [...ICY_BLUE];
|
||||
}
|
||||
|
||||
// Handle animated color (keyframes)
|
||||
if (Array.isArray(color) && color[0] && color[0].s) {
|
||||
color.forEach((keyframe, idx) => {
|
||||
if (keyframe.s && isOrangeColor(keyframe.s)) {
|
||||
console.log(` Replacing orange keyframe at ${path}.c.k[${idx}].s -> icy blue`);
|
||||
keyframe.s = [...ICY_BLUE];
|
||||
}
|
||||
if (keyframe.e && isOrangeColor(keyframe.e)) {
|
||||
console.log(` Replacing orange keyframe at ${path}.c.k[${idx}].e -> icy blue`);
|
||||
keyframe.e = [...ICY_BLUE];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Recursively process all properties
|
||||
const result = {};
|
||||
for (const key in obj) {
|
||||
result[key] = replaceOrangeWithIcyBlue(obj[key], `${path}.${key}`);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
console.log('\n🎨 Replacing orange colors with icy blue (#a3d7e5)...\n');
|
||||
console.log('Only processing connecting/active states (not disconnected state)\n');
|
||||
|
||||
// Process assets (compositions)
|
||||
if (animationData.assets) {
|
||||
animationData.assets.forEach((asset, idx) => {
|
||||
// Only replace colors in these precomps (NOT in "button off" which is the gray disconnected state)
|
||||
const shouldProcess = [
|
||||
'button start connecting', // comp_0: frames 0-78
|
||||
'connecting loop', // comp_1: frames 78-120
|
||||
'connecting to active', // comp_2: frames 120-150
|
||||
'button activate', // comp_3: frames 150-310 (connected state)
|
||||
].includes(asset.nm || asset.id);
|
||||
|
||||
if (shouldProcess && asset.layers) {
|
||||
console.log(`📦 Processing asset "${asset.nm || asset.id}"...`);
|
||||
asset.layers = replaceOrangeWithIcyBlue(asset.layers, `assets[${idx}].layers`);
|
||||
} else if (asset.nm === 'button off' || asset.id === 'comp_4') {
|
||||
console.log(`⏭️ Skipping asset "${asset.nm || asset.id}" (keeping gray disconnected state)`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Also process main layers (though they're just references to precomps)
|
||||
if (animationData.layers) {
|
||||
console.log('\n📦 Processing main timeline layers...');
|
||||
animationData.layers = replaceOrangeWithIcyBlue(animationData.layers, 'layers');
|
||||
}
|
||||
|
||||
console.log('\nWriting updated animation...');
|
||||
fs.writeFileSync(animationPath, JSON.stringify(animationData, null, 2));
|
||||
|
||||
console.log('✅ Animation colors updated!');
|
||||
console.log(' - Connecting/active states: icy blue (#a3d7e5)');
|
||||
console.log(' - Disconnected state: original gray');
|
||||
86
client/ui-electron/scripts/update-animation-colors.js
Normal file
86
client/ui-electron/scripts/update-animation-colors.js
Normal file
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const animationPath = path.join(__dirname, '../src/assets/button-full.json');
|
||||
|
||||
console.log('Reading animation file...');
|
||||
const animationData = JSON.parse(fs.readFileSync(animationPath, 'utf8'));
|
||||
|
||||
// Icy blue color: #a3d7e5 -> RGB normalized: [0.639, 0.843, 0.898]
|
||||
const ICY_BLUE = [0.639, 0.843, 0.898, 1];
|
||||
|
||||
// Orange colors to replace (normalized RGB):
|
||||
// - 0.964705944061, 0.51372551918, 0.1882353127 (primary orange)
|
||||
// - 0.952941236309, 0.36862745098, 0.196078446332 (secondary orange)
|
||||
// - 0.952941179276, 0.368627458811, 0.196078434587 (another variant)
|
||||
|
||||
function isOrangeColor(color) {
|
||||
if (!Array.isArray(color) || color.length < 3) return false;
|
||||
const [r, g, b] = color;
|
||||
// Check if it's orange-ish (high red, medium green, low blue)
|
||||
return r > 0.85 && g > 0.3 && g < 0.6 && b < 0.3;
|
||||
}
|
||||
|
||||
// Function to recursively find and modify orange colors
|
||||
function replaceOrangeWithIcyBlue(obj, path = '') {
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map((item, index) => replaceOrangeWithIcyBlue(item, `${path}[${index}]`));
|
||||
} else if (obj && typeof obj === 'object') {
|
||||
// Check if this object has a color property 'c' with keyframe data 'k'
|
||||
if (obj.c && obj.c.k) {
|
||||
const color = obj.c.k;
|
||||
|
||||
// Handle static color (array)
|
||||
if (Array.isArray(color) && isOrangeColor(color)) {
|
||||
console.log(` Replacing orange color at ${path} -> icy blue`);
|
||||
obj.c.k = [...ICY_BLUE];
|
||||
}
|
||||
|
||||
// Handle animated color (keyframes)
|
||||
if (Array.isArray(color) && color[0] && color[0].s) {
|
||||
color.forEach((keyframe, idx) => {
|
||||
if (keyframe.s && isOrangeColor(keyframe.s)) {
|
||||
console.log(` Replacing orange keyframe at ${path}.c.k[${idx}].s -> icy blue`);
|
||||
keyframe.s = [...ICY_BLUE];
|
||||
}
|
||||
if (keyframe.e && isOrangeColor(keyframe.e)) {
|
||||
console.log(` Replacing orange keyframe at ${path}.c.k[${idx}].e -> icy blue`);
|
||||
keyframe.e = [...ICY_BLUE];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Recursively process all properties
|
||||
const result = {};
|
||||
for (const key in obj) {
|
||||
result[key] = replaceOrangeWithIcyBlue(obj[key], `${path}.${key}`);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
console.log('Replacing orange colors with icy blue (#a3d7e5)...');
|
||||
|
||||
// Process layers
|
||||
if (animationData.layers) {
|
||||
animationData.layers = replaceOrangeWithIcyBlue(animationData.layers, 'layers');
|
||||
}
|
||||
|
||||
// Process assets (compositions)
|
||||
if (animationData.assets) {
|
||||
animationData.assets = animationData.assets.map((asset, idx) => {
|
||||
if (asset.layers) {
|
||||
asset.layers = replaceOrangeWithIcyBlue(asset.layers, `assets[${idx}].layers`);
|
||||
}
|
||||
return asset;
|
||||
});
|
||||
}
|
||||
|
||||
console.log('Writing updated animation...');
|
||||
fs.writeFileSync(animationPath, JSON.stringify(animationData, null, 2));
|
||||
|
||||
console.log('✓ Animation colors updated to icy blue theme!');
|
||||
Reference in New Issue
Block a user