exploded-classic #1
51
index.html
51
index.html
@ -41,11 +41,6 @@
|
||||
<button type="button" class="tab-btn tab-idle" data-target="#tab-wall" aria-pressed="false">Wall</button>
|
||||
</nav>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="flex items-center gap-1 px-2 py-1 rounded-xl bg-white/70 border border-gray-200 shadow-sm" title="Active Color">
|
||||
<div id="current-color-chip-global" class="current-color-chip">
|
||||
<span id="current-color-label-global" class="text-[10px] font-semibold text-slate-700"></span>
|
||||
</div>
|
||||
</div>
|
||||
<button id="app-fullscreen-toggle" class="btn-dark text-xs px-3 py-2" aria-label="Toggle fullscreen">Fullscreen</button>
|
||||
<button id="clear-canvas-btn-top" class="btn-danger text-xs px-3 py-2">Start Fresh</button>
|
||||
</div>
|
||||
@ -79,11 +74,11 @@
|
||||
</button>
|
||||
</div>
|
||||
<div class="grid grid-cols-3 gap-2 mb-3">
|
||||
<button id="tool-undo" class="tool-btn" title="Ctrl+Z" aria-label="Undo">
|
||||
<button id="tool-undo" class="tool-btn" aria-label="Undo">
|
||||
<svg viewBox="0 0 24 24"><path d="M12.5 8c-2.65 0-5.05.99-6.9 2.6L2 7v9h9l-3.62-3.62c1.39-1.16 3.16-1.88 5.12-1.88 3.54 0 6.55 2.31 7.6 5.5l2.37-.78C21.08 11.03 17.15 8 12.5 8z"/></svg>
|
||||
<span class="hidden sm:inline">Undo</span>
|
||||
</button>
|
||||
<button id="tool-redo" class="tool-btn" title="Ctrl+Y" aria-label="Redo">
|
||||
<button id="tool-redo" class="tool-btn" aria-label="Redo">
|
||||
<svg viewBox="0 0 24 24"><path d="M18.4 10.6C16.55 9 14.15 8 11.5 8c-4.65 0-8.58 3.03-9.96 7.22L3.9 16c1.05-3.19 4.05-5.5 7.6-5.5 1.95 0 3.73.72 5.12 1.88L13 16h9V7l-3.6 3.6z"/></svg>
|
||||
<span class="hidden sm:inline">Redo</span>
|
||||
</button>
|
||||
@ -99,31 +94,17 @@
|
||||
<input id="garland-density" type="range" min="0.6" max="1.6" step="0.1" value="1" class="flex-1 h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer">
|
||||
<span id="garland-density-label" class="w-10 text-right text-xs text-gray-500">1.0</span>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 gap-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<label for="garland-color-main1" class="font-medium w-24">Main A</label>
|
||||
<select id="garland-color-main1" class="select text-sm flex-1"></select>
|
||||
<span id="garland-swatch-main1" class="swatch tiny"></span>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="font-medium text-sm text-gray-700">Main Colors</span>
|
||||
<button type="button" id="garland-add-color" class="btn-blue text-xs px-3 py-1">+ Add</button>
|
||||
</div>
|
||||
<div id="garland-main-chips" class="flex flex-wrap gap-2"></div>
|
||||
<p class="hint text-xs">Tap a chip to change it. You can add up to 10 main colors.</p>
|
||||
<div class="flex items-center gap-2">
|
||||
<label for="garland-color-main2" class="font-medium w-24">Main B</label>
|
||||
<select id="garland-color-main2" class="select text-sm flex-1"></select>
|
||||
<span id="garland-swatch-main2" class="swatch tiny"></span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<label for="garland-color-main3" class="font-medium w-24">Main C</label>
|
||||
<select id="garland-color-main3" class="select text-sm flex-1"></select>
|
||||
<span id="garland-swatch-main3" class="swatch tiny"></span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<label for="garland-color-main4" class="font-medium w-24">Main D</label>
|
||||
<select id="garland-color-main4" class="select text-sm flex-1"></select>
|
||||
<span id="garland-swatch-main4" class="swatch tiny"></span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<label for="garland-color-accent" class="font-medium w-24">5" Accent</label>
|
||||
<select id="garland-color-accent" class="select text-sm flex-1"></select>
|
||||
<span id="garland-swatch-accent" class="swatch tiny"></span>
|
||||
<span class="font-medium text-sm text-gray-700">Accent</span>
|
||||
<button type="button" id="garland-accent-chip" class="replace-chip" aria-label="Pick accent color"></button>
|
||||
<button type="button" id="garland-accent-clear" class="btn-yellow text-xs px-3 py-1">Clear</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -138,7 +119,7 @@
|
||||
<button id="duplicate-selected" class="btn-dark" disabled>Duplicate</button>
|
||||
</div>
|
||||
<div class="mt-2">
|
||||
<p class="hint">Drag balloons to reposition. Use keyboard arrows for fine nudges.</p>
|
||||
<p class="hint">Drag balloons to reposition. Use arrows/touches for fine nudges.</p>
|
||||
</div>
|
||||
<div class="mt-2 flex items-center gap-2 text-xs text-gray-600">
|
||||
<span class="font-semibold">Resize</span>
|
||||
@ -185,7 +166,7 @@
|
||||
|
||||
<div class="panel-heading mt-4">Color Library</div>
|
||||
<div class="panel-card">
|
||||
<p class="hint mb-2">Alt+click on canvas to sample a balloon’s color.</p>
|
||||
<p class="hint mb-2">Tap or click on canvas to sample a balloon’s color (use the eyedropper).</p>
|
||||
<div class="flex items-center gap-3 mb-2">
|
||||
<span class="text-sm font-medium text-gray-700">Active Color</span>
|
||||
<div id="current-color-chip" class="current-color-chip">
|
||||
@ -447,7 +428,7 @@
|
||||
Show wireframe for empty spots
|
||||
</label>
|
||||
<label class="text-sm font-medium inline-flex items-center gap-2 col-span-2">
|
||||
<input id="wall-outline" type="checkbox" class="align-middle">
|
||||
<input id="wall-outline" type="checkbox" class="align-middle" checked>
|
||||
Outline balloons
|
||||
</label>
|
||||
</div>
|
||||
@ -464,7 +445,7 @@
|
||||
<span>Erase</span>
|
||||
</button>
|
||||
</div>
|
||||
<p class="hint mt-2 text-xs">Paint applies the active color; Erase clears. Hold Shift/Ctrl for temporary erase.</p>
|
||||
<p class="hint mt-2 text-xs">Paint applies the active color; Erase clears. Hold modifier on desktop to erase temporarily.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -477,7 +458,7 @@
|
||||
<span id="wall-active-color-label" class="text-[10px] font-semibold text-slate-700"></span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="hint mt-2">Tap a swatch to set. Tap a balloon to paint; tap again (same color) to clear. Alt+click (desktop) to pick.</p>
|
||||
<p class="hint mt-2">Tap a swatch to set. Tap a balloon to paint; tap again (same color) to clear. Use the eyedropper to pick from the canvas.</p>
|
||||
</div>
|
||||
<div class="panel-heading mt-4">Used Colors</div>
|
||||
<div class="panel-card">
|
||||
|
||||
177
organic.js
177
organic.js
@ -138,16 +138,10 @@
|
||||
const fitViewBtn = document.getElementById('fit-view-btn');
|
||||
const garlandDensityInput = document.getElementById('garland-density');
|
||||
const garlandDensityLabel = document.getElementById('garland-density-label');
|
||||
const garlandColorMain1Sel = document.getElementById('garland-color-main1');
|
||||
const garlandColorMain2Sel = document.getElementById('garland-color-main2');
|
||||
const garlandColorMain3Sel = document.getElementById('garland-color-main3');
|
||||
const garlandColorMain4Sel = document.getElementById('garland-color-main4');
|
||||
const garlandColorAccentSel = document.getElementById('garland-color-accent');
|
||||
const garlandSwatchMain1 = document.getElementById('garland-swatch-main1');
|
||||
const garlandSwatchMain2 = document.getElementById('garland-swatch-main2');
|
||||
const garlandSwatchMain3 = document.getElementById('garland-swatch-main3');
|
||||
const garlandSwatchMain4 = document.getElementById('garland-swatch-main4');
|
||||
const garlandSwatchAccent = document.getElementById('garland-swatch-accent');
|
||||
const garlandMainChips = document.getElementById('garland-main-chips');
|
||||
const garlandAddColorBtn = document.getElementById('garland-add-color');
|
||||
const garlandAccentChip = document.getElementById('garland-accent-chip');
|
||||
const garlandAccentClearBtn = document.getElementById('garland-accent-clear');
|
||||
const garlandControls = document.getElementById('garland-controls');
|
||||
|
||||
const sizePresetGroup = document.getElementById('size-preset-group');
|
||||
@ -214,8 +208,8 @@
|
||||
let usedSortDesc = true;
|
||||
let garlandPath = [];
|
||||
let garlandDensity = parseFloat(garlandDensityInput?.value || '1') || 1;
|
||||
let garlandMainIdx = [0, 0, 0, 0];
|
||||
let garlandAccentIdx = 0;
|
||||
let garlandMainIdx = [0];
|
||||
let garlandAccentIdx = -1;
|
||||
let lastCommitMode = '';
|
||||
let lastAddStatus = '';
|
||||
let evtStats = { down: 0, up: 0, cancel: 0, touchEnd: 0, addBalloon: 0, addGarland: 0, lastType: '' };
|
||||
@ -234,11 +228,11 @@
|
||||
const canRedo = historyPointer < historyStack.length - 1;
|
||||
if (toolUndoBtn) {
|
||||
toolUndoBtn.disabled = !canUndo;
|
||||
toolUndoBtn.title = canUndo ? 'Undo (Ctrl+Z)' : 'Nothing to undo';
|
||||
toolUndoBtn.title = canUndo ? 'Undo' : 'Nothing to undo';
|
||||
}
|
||||
if (toolRedoBtn) {
|
||||
toolRedoBtn.disabled = !canRedo;
|
||||
toolRedoBtn.title = canRedo ? 'Redo (Ctrl+Y)' : 'Nothing to redo';
|
||||
toolRedoBtn.title = canRedo ? 'Redo' : 'Nothing to redo';
|
||||
}
|
||||
}
|
||||
|
||||
@ -997,8 +991,8 @@
|
||||
if (garlandDensityLabel) garlandDensityLabel.textContent = garlandDensity.toFixed(1);
|
||||
}
|
||||
if (Array.isArray(s.garlandMainIdx)) {
|
||||
garlandMainIdx = s.garlandMainIdx.slice(0, 4).map(v => Number(v) || -1);
|
||||
while (garlandMainIdx.length < 4) garlandMainIdx.push(-1);
|
||||
garlandMainIdx = s.garlandMainIdx.slice(0, 10).map(v => Number.isInteger(v) ? v : -1).filter((v, i) => i < 10);
|
||||
if (!garlandMainIdx.length) garlandMainIdx = [selectedColorIdx];
|
||||
}
|
||||
if (typeof s.garlandAccentIdx === 'number') garlandAccentIdx = s.garlandAccentIdx;
|
||||
if (typeof s.isBorderEnabled === 'boolean') isBorderEnabled = s.isBorderEnabled;
|
||||
@ -1010,6 +1004,109 @@
|
||||
loadAppState();
|
||||
resetHistory(); // establish initial history state for undo/redo controls
|
||||
|
||||
// ====== Garland color UI (dynamic chips) ======
|
||||
const styleChip = (el, meta) => {
|
||||
if (!el || !meta) return;
|
||||
if (meta.image) {
|
||||
el.style.backgroundImage = `url("${meta.image}")`;
|
||||
el.style.backgroundColor = meta.hex || '#fff';
|
||||
el.style.backgroundSize = `${100 * SWATCH_TEXTURE_ZOOM}%`;
|
||||
el.style.backgroundPosition = `${(meta.imageFocus?.x ?? 0.5) * 100}% ${(meta.imageFocus?.y ?? 0.5) * 100}%`;
|
||||
} else {
|
||||
el.style.backgroundImage = 'none';
|
||||
el.style.backgroundColor = meta.hex || '#f1f5f9';
|
||||
}
|
||||
};
|
||||
|
||||
const garlandMaxColors = 10;
|
||||
function renderGarlandMainChips() {
|
||||
if (!garlandMainChips) return;
|
||||
garlandMainChips.innerHTML = '';
|
||||
const items = garlandMainIdx.length ? garlandMainIdx : [selectedColorIdx];
|
||||
items.forEach((idx, i) => {
|
||||
const wrap = document.createElement('div');
|
||||
wrap.className = 'flex items-center gap-1';
|
||||
const chip = document.createElement('button');
|
||||
chip.type = 'button';
|
||||
chip.className = 'replace-chip garland-chip';
|
||||
const meta = FLAT_COLORS[idx] || FLAT_COLORS[selectedColorIdx] || FLAT_COLORS[0];
|
||||
styleChip(chip, meta);
|
||||
chip.title = meta?.name || meta?.hex || 'Color';
|
||||
chip.addEventListener('click', () => {
|
||||
if (!window.openColorPicker) return;
|
||||
window.openColorPicker({
|
||||
title: 'Path color',
|
||||
subtitle: 'Pick a main color',
|
||||
items: (FLAT_COLORS || []).map((c, ci) => ({ label: c.name || c.hex, metaText: c.family || '', idx: ci })),
|
||||
onSelect: (item) => {
|
||||
garlandMainIdx[i] = item.idx;
|
||||
renderGarlandMainChips();
|
||||
if (mode === 'garland') requestDraw();
|
||||
persist();
|
||||
}
|
||||
});
|
||||
});
|
||||
const removeBtn = document.createElement('button');
|
||||
removeBtn.type = 'button';
|
||||
removeBtn.className = 'btn-yellow text-xs px-2 py-1';
|
||||
removeBtn.textContent = '×';
|
||||
removeBtn.title = 'Remove color';
|
||||
removeBtn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
garlandMainIdx.splice(i, 1);
|
||||
if (!garlandMainIdx.length) garlandMainIdx.push(selectedColorIdx);
|
||||
renderGarlandMainChips();
|
||||
if (mode === 'garland') requestDraw();
|
||||
persist();
|
||||
});
|
||||
wrap.appendChild(chip);
|
||||
wrap.appendChild(removeBtn);
|
||||
garlandMainChips.appendChild(wrap);
|
||||
});
|
||||
}
|
||||
|
||||
garlandAddColorBtn?.addEventListener('click', () => {
|
||||
if (garlandMainIdx.length >= garlandMaxColors) { showModal(`Max ${garlandMaxColors} colors.`); return; }
|
||||
if (!window.openColorPicker) return;
|
||||
window.openColorPicker({
|
||||
title: 'Add path color',
|
||||
subtitle: 'Choose a main color',
|
||||
items: (FLAT_COLORS || []).map((c, ci) => ({ label: c.name || c.hex, metaText: c.family || '', idx: ci })),
|
||||
onSelect: (item) => {
|
||||
garlandMainIdx.push(item.idx);
|
||||
renderGarlandMainChips();
|
||||
if (mode === 'garland') requestDraw();
|
||||
persist();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const updateAccentChip = () => {
|
||||
if (!garlandAccentChip) return;
|
||||
const meta = garlandAccentIdx >= 0 ? FLAT_COLORS[garlandAccentIdx] : null;
|
||||
styleChip(garlandAccentChip, meta || { hex: '#f8fafc' });
|
||||
};
|
||||
garlandAccentChip?.addEventListener('click', () => {
|
||||
if (!window.openColorPicker) return;
|
||||
window.openColorPicker({
|
||||
title: 'Accent color',
|
||||
subtitle: 'Choose a 5" accent color',
|
||||
items: (FLAT_COLORS || []).map((c, ci) => ({ label: c.name || c.hex, metaText: c.family || '', idx: ci })),
|
||||
onSelect: (item) => {
|
||||
garlandAccentIdx = item.idx;
|
||||
updateAccentChip();
|
||||
if (mode === 'garland') requestDraw();
|
||||
persist();
|
||||
}
|
||||
});
|
||||
});
|
||||
garlandAccentClearBtn?.addEventListener('click', () => {
|
||||
garlandAccentIdx = -1;
|
||||
updateAccentChip();
|
||||
if (mode === 'garland') requestDraw();
|
||||
persist();
|
||||
});
|
||||
|
||||
// ====== UI Rendering (Palettes) ======
|
||||
function renderAllowedPalette() {
|
||||
if (!paletteBox) return;
|
||||
@ -1789,31 +1886,13 @@
|
||||
if (mode === 'garland') requestDraw();
|
||||
persist();
|
||||
});
|
||||
const handleGarlandColorChange = () => {
|
||||
updateGarlandSwatches();
|
||||
persist();
|
||||
const refreshGarlandColors = () => {
|
||||
renderGarlandMainChips();
|
||||
updateAccentChip();
|
||||
if (mode === 'garland') requestDraw();
|
||||
persist();
|
||||
};
|
||||
garlandColorMain1Sel?.addEventListener('change', e => {
|
||||
garlandMainIdx[0] = parseInt(e.target.value, 10) || -1;
|
||||
handleGarlandColorChange();
|
||||
});
|
||||
garlandColorMain2Sel?.addEventListener('change', e => {
|
||||
garlandMainIdx[1] = parseInt(e.target.value, 10) || -1;
|
||||
handleGarlandColorChange();
|
||||
});
|
||||
garlandColorMain3Sel?.addEventListener('change', e => {
|
||||
garlandMainIdx[2] = parseInt(e.target.value, 10) || -1;
|
||||
handleGarlandColorChange();
|
||||
});
|
||||
garlandColorMain4Sel?.addEventListener('change', e => {
|
||||
garlandMainIdx[3] = parseInt(e.target.value, 10) || -1;
|
||||
handleGarlandColorChange();
|
||||
});
|
||||
garlandColorAccentSel?.addEventListener('change', e => {
|
||||
garlandAccentIdx = parseInt(e.target.value, 10) || -1;
|
||||
handleGarlandColorChange();
|
||||
});
|
||||
refreshGarlandColors();
|
||||
|
||||
deleteSelectedBtn?.addEventListener('click', deleteSelected);
|
||||
duplicateSelectedBtn?.addEventListener('click', duplicateSelected);
|
||||
@ -1957,26 +2036,6 @@
|
||||
updateGarlandSwatches();
|
||||
}
|
||||
|
||||
function updateGarlandSwatches() {
|
||||
const setSw = (sw, idx) => {
|
||||
if (!sw) return;
|
||||
const meta = idx >= 0 ? FLAT_COLORS[idx] : null;
|
||||
if (meta?.image) {
|
||||
sw.style.backgroundImage = `url("${meta.image}")`;
|
||||
sw.style.backgroundColor = meta.hex || '#fff';
|
||||
sw.style.backgroundSize = 'cover';
|
||||
} else {
|
||||
sw.style.backgroundImage = 'none';
|
||||
sw.style.backgroundColor = meta?.hex || '#f1f5f9';
|
||||
}
|
||||
};
|
||||
setSw(garlandSwatchMain1, garlandMainIdx[0]);
|
||||
setSw(garlandSwatchMain2, garlandMainIdx[1]);
|
||||
setSw(garlandSwatchMain3, garlandMainIdx[2]);
|
||||
setSw(garlandSwatchMain4, garlandMainIdx[3]);
|
||||
setSw(garlandSwatchAccent, garlandAccentIdx);
|
||||
}
|
||||
|
||||
const updateReplaceChips = () => {
|
||||
const fromHex = replaceFromSel?.value;
|
||||
const toIdx = parseInt(replaceToSel?.value || '-1', 10);
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
|
||||
// Ensure shared helpers are ready
|
||||
if (!window.shared) return;
|
||||
const { clamp, clamp01 } = window.shared;
|
||||
const { clamp, clamp01, SWATCH_TEXTURE_ZOOM } = window.shared;
|
||||
const { FLAT_COLORS } = window.shared;
|
||||
|
||||
// Modal helpers
|
||||
@ -58,9 +58,10 @@
|
||||
const setChipStyle = (el, meta) => {
|
||||
if (!el || !meta) return;
|
||||
if (meta.image) {
|
||||
const zoom = Math.max(1, meta.imageZoom ?? SWATCH_TEXTURE_ZOOM ?? 2.5);
|
||||
el.style.backgroundImage = `url("${meta.image}")`;
|
||||
el.style.backgroundColor = meta.hex || '#fff';
|
||||
el.style.backgroundSize = 'cover';
|
||||
el.style.backgroundSize = `${100 * zoom}%`;
|
||||
el.style.backgroundPosition = `${(meta.imageFocus?.x ?? 0.5) * 100}% ${(meta.imageFocus?.y ?? 0.5) * 100}%`;
|
||||
} else {
|
||||
el.style.backgroundImage = 'none';
|
||||
@ -526,7 +527,8 @@
|
||||
const isMobileView = () => window.matchMedia('(max-width: 1023px)').matches;
|
||||
const updateMobileActionBarVisibility = () => {
|
||||
if (!mobileActionBar) return;
|
||||
const shouldShow = current === '#tab-organic' && isMobileView();
|
||||
const modalOpen = !!document.querySelector('.color-modal:not(.hidden)');
|
||||
const shouldShow = current === '#tab-organic' && isMobileView() && !modalOpen;
|
||||
mobileActionBar.classList.toggle('hidden', !shouldShow);
|
||||
};
|
||||
const wireMobileActionButtons = () => {
|
||||
|
||||
14
style.css
14
style.css
@ -446,7 +446,7 @@ body[data-active-tab="#tab-wall"] #clear-canvas-btn-top {
|
||||
display: block;
|
||||
}
|
||||
.control-sheet { bottom: 4.5rem; max-height: 55vh; }
|
||||
.control-sheet.minimized { transform: translateY(95%); }
|
||||
.control-sheet.minimized { transform: translateY(115%); }
|
||||
|
||||
/* Larger tap targets and spacing */
|
||||
.tool-btn,
|
||||
@ -480,7 +480,7 @@ body[data-active-tab="#tab-wall"] #clear-canvas-btn-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
z-index: 45;
|
||||
z-index: 20; /* below control sheets (30) and modals (60) */
|
||||
}
|
||||
|
||||
.color-modal {
|
||||
@ -624,6 +624,16 @@ body[data-active-tab="#tab-wall"] #clear-canvas-btn-top {
|
||||
box-shadow: 0 -6px 30px rgba(15, 23, 42, 0.12);
|
||||
border-top: 1px solid rgba(148, 163, 184, 0.25);
|
||||
}
|
||||
.mobile-tabbar.hidden { display: none; }
|
||||
|
||||
@media (max-width: 1023px) {
|
||||
/* Tuck canvases above the tabbar */
|
||||
#classic-display,
|
||||
#wall-display,
|
||||
#balloon-canvas {
|
||||
margin-bottom: 5.5rem;
|
||||
}
|
||||
}
|
||||
.mobile-tabbar .mobile-tab-btn {
|
||||
flex: 1 1 0;
|
||||
display: flex;
|
||||
|
||||
12
wall.js
12
wall.js
@ -92,7 +92,7 @@
|
||||
|
||||
function wallDefaultState() {
|
||||
// Default to wireframes on so empty cells are visible/clickable.
|
||||
return { rows: 7, cols: 9, spacing: 75, bigSize: 52, pattern: 'grid', fillGaps: false, showWireframes: true, outline: false, colors: [], customColors: {}, patternStore: {}, activeColorIdx: 0 };
|
||||
return { rows: 7, cols: 9, spacing: 75, bigSize: 52, pattern: 'grid', fillGaps: false, showWireframes: true, outline: true, colors: [], customColors: {}, patternStore: {}, activeColorIdx: 0 };
|
||||
}
|
||||
|
||||
// Build FLAT_COLORS locally if shared failed to populate (e.g., palette not ready)
|
||||
@ -439,8 +439,8 @@
|
||||
const meta = wallColorMeta(gapIdx);
|
||||
const patId = ensurePattern(meta);
|
||||
const fill = invisible ? hitFill : (patId ? `url(#${patId})` : meta.hex);
|
||||
const stroke = 'none';
|
||||
const strokeW = 0;
|
||||
const stroke = invisible || isEmpty ? 'none' : (showOutline ? '#111827' : 'none');
|
||||
const strokeW = invisible || isEmpty ? 0 : (showOutline ? 0.6 : 0);
|
||||
const filter = invisible || isEmpty ? '' : `filter="url(#${bigShadow})"`;
|
||||
const rGap = bigR * 0.82; // slightly smaller 11" gap balloon
|
||||
const shineGap = isEmpty ? '' : shineNodeRelative(rGap, rGap, meta.hex);
|
||||
@ -498,9 +498,9 @@
|
||||
const patId = ensurePattern(meta);
|
||||
const fill = invisibleLink ? 'rgba(0,0,0,0.001)' : (linkIsEmpty ? 'none' : (patId ? `url(#${patId})` : meta.hex));
|
||||
console.log(`l#-r-c: keyId: ${linkKey}, customIdx: ${linkCustomIdx}, isEmpty: ${linkIsEmpty}, invisible: ${invisibleLink}, fill: ${fill}, meta:`, meta);
|
||||
// Always outline X-pattern link ovals; thicken when outline toggle is on.
|
||||
const stroke = invisibleLink ? 'none' : (showOutline ? '#111827' : '#cbd5e1');
|
||||
const strokeW = invisibleLink ? 0 : (showOutline ? 0.8 : 0.6);
|
||||
// Outline only when filled; light wireframe when empty and wireframes shown.
|
||||
const stroke = invisibleLink ? 'none' : (linkIsEmpty ? (showWireframes ? '#cbd5e1' : 'none') : (showOutline ? '#111827' : 'none'));
|
||||
const strokeW = invisibleLink ? 0 : (linkIsEmpty ? (showWireframes ? 1.2 : 0) : (showOutline ? 0.8 : 0));
|
||||
const filter = invisibleLink || linkIsEmpty ? '' : `filter="url(#${bigShadow})"`;
|
||||
const shine = linkIsEmpty ? '' : shineNodeRelative(linkDims.rx, linkDims.ry, meta.hex);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user