Skip to content

Commit a779cc2

Browse files
Update color use related to alphabet size
1 parent cb727d4 commit a779cc2

3 files changed

Lines changed: 104 additions & 611 deletions

File tree

public/app.mjs

Lines changed: 36 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -171,115 +171,43 @@ function syncControls(config) {
171171
}
172172

173173
// Interpolate between two hex colors
174-
function interpolateColor(color1, color2, factor) {
175-
const c1 = parseInt(color1.slice(1), 16);
176-
const c2 = parseInt(color2.slice(1), 16);
177-
const r1 = (c1 >> 16) & 255, g1 = (c1 >> 8) & 255, b1 = c1 & 255;
178-
const r2 = (c2 >> 16) & 255, g2 = (c2 >> 8) & 255, b2 = c2 & 255;
179-
const r = Math.round(r1 + (r2 - r1) * factor);
180-
const g = Math.round(g1 + (g2 - g1) * factor);
181-
const b = Math.round(b1 + (b2 - b1) * factor);
182-
return `#${((r << 16) | (g << 8) | b).toString(16).padStart(6, '0')}`;
183-
}
184-
185-
// Get color from gradient at a given position (0-1)
186-
function getGradientColor(position, colors, positions) {
187-
if (!colors || colors.length === 0) return '#ffffff';
188-
if (colors.length === 1) return colors[0];
189-
if (!positions || positions.length !== colors.length) return colors[0];
190-
191-
// Normalize position to 0-1
192-
const t = Math.max(0, Math.min(1, position));
193-
194-
// Find the two stops this position falls between
195-
let startIdx = 0;
196-
for (let i = 0; i < positions.length - 1; i++) {
197-
const pos1 = positions[i] / 100;
198-
const pos2 = positions[i + 1] / 100;
199-
if (t >= pos1 && t <= pos2) {
200-
startIdx = i;
201-
break;
202-
}
203-
}
204-
205-
// Clamp to valid indices
206-
startIdx = Math.min(startIdx, positions.length - 2);
207-
const endIdx = Math.min(startIdx + 1, positions.length - 1);
208-
209-
const pos1 = positions[startIdx] / 100;
210-
const pos2 = positions[endIdx] / 100;
211-
const range = pos2 - pos1;
212-
const factor = range === 0 ? 0 : (t - pos1) / range;
174+
const DEFAULT_PALETTES = {
175+
2: ["#0066ff", "#ff6b35"],
176+
3: ["#0066ff", "#00ff41", "#ff6b35"],
177+
4: ["#0066ff", "#00aaff", "#00ff41", "#ff6b35"],
178+
5: ["#0066ff", "#00aaff", "#00ff41", "#ffaa00", "#ff6b35"],
179+
6: ["#0066ff", "#00aaff", "#00ffaa", "#00ff41", "#ffaa00", "#ff6b35"],
180+
8: ["#0066ff", "#00aaff", "#00ddff", "#00ff41", "#ffff00", "#ffaa00", "#ff6b35", "#ff0055"],
181+
};
213182

214-
return interpolateColor(colors[startIdx], colors[endIdx], factor);
183+
function getDefaultPalette(alphabetSize) {
184+
return DEFAULT_PALETTES[alphabetSize] || (DEFAULT_PALETTES[alphabetSize] =
185+
Array.from({ length: alphabetSize }, (_, i) => {
186+
const hue = (i / alphabetSize) * 360;
187+
return `hsl(${Math.round(hue)}, 100%, 50%)`;
188+
})
189+
);
215190
}
216191

217-
function colorFor(value, config, rowIndex, colIndex, channels) {
192+
function colorFor(value, config, channels) {
218193
const visualValue = channels && channels.length > 1 ? channels[1] : value;
219194
const alphabet = config.alphabet_sortie || config.alphabet_entree || [0, 1];
220195
let index = alphabet.findIndex((item) => String(item) === String(visualValue));
221196

222-
// Use gradient if available
223-
const gradient = config.rendu.gradient;
224-
if (gradient && gradient.colors && gradient.colors.length > 0) {
225-
let position = 0;
226-
if (index >= 0) {
227-
position = index / Math.max(1, alphabet.length - 1);
228-
} else {
229-
position = (Math.abs(Number(visualValue) || Number(value) || 0) % 100) / 100;
230-
}
231-
232-
// Apply gradient based on type
233-
if (gradient.type === 'linear') {
234-
position = (colIndex / (config.largeur || 100)) * 0.5 + (rowIndex / (config.hauteur || 100)) * 0.5;
235-
} else if (gradient.type === 'radial') {
236-
const centerX = (config.largeur || 100) / 2;
237-
const centerY = (config.hauteur || 100) / 2;
238-
const dist = Math.sqrt(Math.pow(colIndex - centerX, 2) + Math.pow(rowIndex - centerY, 2));
239-
const maxDist = Math.sqrt(Math.pow(centerX, 2) + Math.pow(centerY, 2));
240-
position = Math.min(1, dist / maxDist);
241-
} else if (gradient.type === 'conic') {
242-
const centerX = (config.largeur || 100) / 2;
243-
const centerY = (config.hauteur || 100) / 2;
244-
const angle = Math.atan2(rowIndex - centerY, colIndex - centerX);
245-
position = ((angle + Math.PI) / (2 * Math.PI));
246-
}
247-
248-
return getGradientColor(position, gradient.colors, gradient.positions);
249-
}
197+
if (index < 0) index = Math.abs(Number(visualValue) || Number(value) || 0) % alphabet.length;
250198

251-
// Fallback to palette if no gradient
252-
const palette = config.rendu.palette || ["#07121f", "#ff9d4d", "#53b0ff", "#f5f7ff"];
253-
if (index < 0) index = Math.abs(Number(visualValue) || Number(value) || 0) % palette.length;
254-
const drift = (rowIndex + colIndex) % Math.max(1, palette.length - 1);
255-
return palette[(index + drift) % palette.length] || palette[0];
199+
const palette = config.rendu.palette || getDefaultPalette(alphabet.length);
200+
return palette[index % palette.length] || palette[0];
256201
}
257202

258-
window.applyGradientToPalette = function(colors, type, positions) {
203+
window.setPaletteColor = function(alphabetIndex, color) {
259204
if (!state.config) return;
260205
state.config.rendu = state.config.rendu || {};
261-
262-
const finalColors = colors || ["#07121f", "#ff9d4d", "#53b0ff", "#f5f7ff"];
263-
const finalPositions = positions || [0, 50, 100];
264-
265-
// Ensure colors and positions arrays have the same length
266-
const length = Math.min(finalColors.length, finalPositions.length);
267-
const syncedColors = finalColors.slice(0, length);
268-
const syncedPositions = finalPositions.slice(0, length);
269-
270-
// If arrays were mismatched, pad with defaults
271-
if (syncedColors.length < 2) {
272-
syncedColors.push("#ff9d4d", "#f5f7ff");
273-
syncedPositions.push(50, 100);
206+
const alphabet = state.config.alphabet_sortie || state.config.alphabet_entree || [0, 1];
207+
if (!state.config.rendu.palette) {
208+
state.config.rendu.palette = getDefaultPalette(alphabet.length);
274209
}
275-
276-
state.config.rendu.gradient = {
277-
colors: syncedColors,
278-
type: type || 'linear',
279-
positions: syncedPositions.map(Number)
280-
};
281-
// Keep palette as fallback
282-
state.config.rendu.palette = syncedColors;
210+
state.config.rendu.palette[alphabetIndex] = color;
283211
render();
284212
};
285213

@@ -294,7 +222,7 @@ function drawUniverseToCanvas(targetCanvas, universe, maxWidth = 240, maxHeight
294222
lignes.forEach((ligne, y) => {
295223
ligne.forEach((value, x) => {
296224
if (String(value) === String(configuration.alphabet_entree[0]) && !configuration.rendu.afficher_zero) return;
297-
context.fillStyle = colorFor(value, configuration, y, x, sorties?.[y]?.[x]);
225+
context.fillStyle = colorFor(value, configuration, sorties?.[y]?.[x]);
298226
context.fillRect(x * cell, y * cell, cell, cell);
299227
});
300228
});
@@ -316,7 +244,7 @@ function render() {
316244
lignes.forEach((ligne, y) => {
317245
ligne.forEach((value, x) => {
318246
if (String(value) === String(configuration.alphabet_entree[0]) && !configuration.rendu.afficher_zero) return;
319-
ctx.fillStyle = colorFor(value, configuration, y, x, sorties?.[y]?.[x]);
247+
ctx.fillStyle = colorFor(value, configuration, sorties?.[y]?.[x]);
320248
ctx.fillRect(x * cell, y * cell, cell, cell);
321249
});
322250
});
@@ -343,6 +271,9 @@ function applyConfig(config, { updateJson = true, updateControls = true } = {})
343271
if (updateJson) controls.json.value = JSON.stringify(normalized, null, 2);
344272
describe(normalized);
345273
render();
274+
if (typeof window.updatePaletteEditor === 'function') {
275+
window.updatePaletteEditor();
276+
}
346277
return true;
347278
}
348279

@@ -448,6 +379,13 @@ document.querySelector("#apply-json").addEventListener("click", () => {
448379
document.querySelector("#reset-json").addEventListener("click", () => {
449380
controls.json.value = JSON.stringify(state.lastValidConfig || state.config, null, 2);
450381
});
382+
383+
// Expose API for palette editor
384+
window.AutomaginariumApp = {
385+
state,
386+
render,
387+
getDefaultPalette,
388+
};
451389
controls.importJson.addEventListener("change", async () => {
452390
const file = controls.importJson.files[0];
453391
if (!file) return;

0 commit comments

Comments
 (0)