CyberMax-tools commited on
Commit
e45936f
·
verified ·
1 Parent(s): 2452c7c

Deploy tonebox to the hub

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +4 -0
  2. tonebox/app.js +166 -0
  3. tonebox/gallery/lake/arctic.jpg +0 -0
  4. tonebox/gallery/lake/bleach-bypass.jpg +0 -0
  5. tonebox/gallery/lake/blockbuster.jpg +0 -0
  6. tonebox/gallery/lake/blue-hour.jpg +0 -0
  7. tonebox/gallery/lake/blue-tone.jpg +0 -0
  8. tonebox/gallery/lake/bw-green-filter.jpg +0 -0
  9. tonebox/gallery/lake/bw-high-contrast.jpg +0 -0
  10. tonebox/gallery/lake/bw-neutral.jpg +0 -0
  11. tonebox/gallery/lake/bw-red-filter.jpg +0 -0
  12. tonebox/gallery/lake/bw-soft.jpg +0 -0
  13. tonebox/gallery/lake/candlelight.jpg +0 -0
  14. tonebox/gallery/lake/cool-negative.jpg +0 -0
  15. tonebox/gallery/lake/cool-plus.jpg +0 -0
  16. tonebox/gallery/lake/cross-process.jpg +0 -0
  17. tonebox/gallery/lake/crush-blacks.jpg +0 -0
  18. tonebox/gallery/lake/cyanotype.jpg +0 -0
  19. tonebox/gallery/lake/day-for-night.jpg +0 -0
  20. tonebox/gallery/lake/desert-gold.jpg +0 -0
  21. tonebox/gallery/lake/dreamy-pastel.jpg +0 -0
  22. tonebox/gallery/lake/dungeon.jpg +0 -0
  23. tonebox/gallery/lake/dusk.jpg +0 -0
  24. tonebox/gallery/lake/expired-stock.jpg +0 -0
  25. tonebox/gallery/lake/faded-print.jpg +0 -0
  26. tonebox/gallery/lake/fog.jpg +0 -0
  27. tonebox/gallery/lake/frozen-tundra.jpg +0 -0
  28. tonebox/gallery/lake/golden-hour.jpg +0 -0
  29. tonebox/gallery/lake/horror-green.jpg +0 -0
  30. tonebox/gallery/lake/lava.jpg +0 -0
  31. tonebox/gallery/lake/lift-shadows.jpg +0 -0
  32. tonebox/gallery/lake/matte.jpg +0 -0
  33. tonebox/gallery/lake/midday-punch.jpg +0 -0
  34. tonebox/gallery/lake/moody-forest.jpg +0 -0
  35. tonebox/gallery/lake/moonlight.jpg +0 -0
  36. tonebox/gallery/lake/muted.jpg +0 -0
  37. tonebox/gallery/lake/neon.jpg +0 -0
  38. tonebox/gallery/lake/night-city.jpg +0 -0
  39. tonebox/gallery/lake/noir-blue.jpg +0 -0
  40. tonebox/gallery/lake/original.jpg +0 -0
  41. tonebox/gallery/lake/overcast.jpg +0 -0
  42. tonebox/gallery/lake/pastel.jpg +0 -0
  43. tonebox/gallery/lake/punchy.jpg +0 -0
  44. tonebox/gallery/lake/retro-8bit.jpg +0 -0
  45. tonebox/gallery/lake/scifi-clean.jpg +0 -0
  46. tonebox/gallery/lake/selenium.jpg +0 -0
  47. tonebox/gallery/lake/sepia-drama.jpg +0 -0
  48. tonebox/gallery/lake/sepia.jpg +0 -0
  49. tonebox/gallery/lake/silver-retention.jpg +0 -0
  50. tonebox/gallery/lake/slide-punch.jpg +0 -0
.gitattributes CHANGED
@@ -47,3 +47,7 @@ groundcover/screenshot-1.png filter=lfs diff=lfs merge=lfs -text
47
  groundcover/screenshot-2.png filter=lfs diff=lfs merge=lfs -text
48
  groundcover/screenshot-3.png filter=lfs diff=lfs merge=lfs -text
49
  groundcover/screenshot-4.png filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
47
  groundcover/screenshot-2.png filter=lfs diff=lfs merge=lfs -text
48
  groundcover/screenshot-3.png filter=lfs diff=lfs merge=lfs -text
49
  groundcover/screenshot-4.png filter=lfs diff=lfs merge=lfs -text
50
+ tonebox/icon-512.png filter=lfs diff=lfs merge=lfs -text
51
+ tonebox/og.png filter=lfs diff=lfs merge=lfs -text
52
+ tonebox/samples/lake.jpg filter=lfs diff=lfs merge=lfs -text
53
+ tonebox/samples/market.jpg filter=lfs diff=lfs merge=lfs -text
tonebox/app.js ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Tonebox previewer. Photos and .cube files stay in the browser. © 2026 CyberMax. All rights reserved. */
2
+ (function () {
3
+ "use strict";
4
+ var CHECKOUT = "https://buy.polar.sh/polar_cl_MiDtlpQOhXytyuuOkWflnzvDFprMR1WRDE0LQ30bQPr"; // Polar checkout link (revenue/packs/polar/tonebox/polar.json)
5
+ var MAX_SIDE = 1600; // preview resolution; the download uses the full photo up to 6000 px
6
+ var $ = function (s) { return document.querySelector(s); };
7
+ var state = { looks: [], luts: {}, custom: null, current: "teal-orange", sample: "market", img: null, intensity: 1, fileName: "photo" };
8
+ var before = $("#before"), after = $("#after"), stage = $("#stage");
9
+
10
+ function toast(msg) { var t = $("#toast"); t.textContent = msg; t.classList.add("show"); clearTimeout(toast.t); toast.t = setTimeout(function () { t.classList.remove("show"); }, 2600); }
11
+ function warn(msg) { $("#warn").textContent = msg || ""; }
12
+ function lookById(id) { for (var i = 0; i < state.looks.length; i++) if (state.looks[i].id === id) return state.looks[i]; return null; }
13
+ function activeLut() { return state.current === "custom" ? state.custom : state.luts[state.current]; }
14
+ function activeName() { return state.current === "custom" ? (state.custom.title || "Your LUT") : (lookById(state.current) || {}).name; }
15
+
16
+ function drawScaled(img, canvas, maxSide) {
17
+ var s = Math.min(1, maxSide / Math.max(img.naturalWidth || img.width, img.naturalHeight || img.height));
18
+ canvas.width = Math.max(1, Math.round((img.naturalWidth || img.width) * s));
19
+ canvas.height = Math.max(1, Math.round((img.naturalHeight || img.height) * s));
20
+ var ctx = canvas.getContext("2d", { willReadFrequently: true });
21
+ ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
22
+ return ctx;
23
+ }
24
+
25
+ var base = null; // original pixels at preview size
26
+ function setImage(img) {
27
+ state.img = img;
28
+ var ctx = drawScaled(img, before, MAX_SIDE);
29
+ base = ctx.getImageData(0, 0, before.width, before.height);
30
+ after.width = before.width; after.height = before.height;
31
+ render();
32
+ }
33
+ var pending = false;
34
+ function render() {
35
+ if (!base || pending) return;
36
+ pending = true;
37
+ requestAnimationFrame(function () {
38
+ pending = false;
39
+ var lut = activeLut();
40
+ var out = new ImageData(new Uint8ClampedArray(base.data), base.width, base.height);
41
+ if (lut) ToneboxLUT.applyLut(out.data, lut, state.intensity);
42
+ after.getContext("2d").putImageData(out, 0, 0);
43
+ $("#tag-look").textContent = activeName() || "";
44
+ document.body.setAttribute("data-rendered", state.current + ":" + Math.round(state.intensity * 100));
45
+ });
46
+ }
47
+
48
+ function loadSample(name) {
49
+ state.sample = name; state.fileName = name;
50
+ var img = new Image();
51
+ img.onload = function () { setImage(img); };
52
+ img.src = "samples/" + name + ".jpg";
53
+ document.querySelectorAll("#samples .chip").forEach(function (b) { b.classList.toggle("on", b.getAttribute("data-sample") === name); });
54
+ document.querySelectorAll("#gallery img").forEach(function (im) { im.src = "gallery/" + name + "/" + im.getAttribute("data-id") + ".jpg"; });
55
+ document.querySelectorAll("#free-looks img").forEach(function (im) { im.src = "gallery/" + name + "/" + im.getAttribute("data-id") + ".jpg"; });
56
+ }
57
+
58
+ function openPhoto(file) {
59
+ if (!file || !/^image\//.test(file.type)) { warn("That file is not an image."); return; }
60
+ var url = URL.createObjectURL(file), img = new Image();
61
+ img.onload = function () { state.fileName = file.name.replace(/\.[^.]+$/, "") || "photo"; setImage(img); warn(""); document.querySelectorAll("#samples .chip").forEach(function (b) { b.classList.remove("on"); }); };
62
+ img.onerror = function () { warn("This browser can't open that image format. Try a JPG or PNG."); };
63
+ img.src = url;
64
+ }
65
+ function openCube(file) {
66
+ var r = new FileReader();
67
+ r.onload = function () {
68
+ try {
69
+ var lut = ToneboxLUT.parseCube(r.result);
70
+ lut.title = lut.title || file.name.replace(/\.cube$/i, "");
71
+ state.custom = lut; select("custom");
72
+ warn(""); toast("Loaded " + lut.title + " (" + lut.n + "-point)");
73
+ } catch (e) { warn("Couldn't read that LUT: " + e.message); }
74
+ };
75
+ r.readAsText(file);
76
+ }
77
+
78
+ function select(id) {
79
+ state.current = id;
80
+ document.querySelectorAll("#free-looks .look").forEach(function (b) { b.classList.toggle("on", b.getAttribute("data-id") === id); });
81
+ render();
82
+ }
83
+
84
+ function save() {
85
+ if (!state.img) return;
86
+ var c = document.createElement("canvas"), ctx = drawScaled(state.img, c, 6000);
87
+ var id = ctx.getImageData(0, 0, c.width, c.height), lut = activeLut();
88
+ if (lut) ToneboxLUT.applyLut(id.data, lut, state.intensity);
89
+ ctx.putImageData(id, 0, 0);
90
+ c.toBlob(function (blob) {
91
+ var a = document.createElement("a");
92
+ a.href = URL.createObjectURL(blob);
93
+ a.download = state.fileName + "-" + (activeName() || "graded").toLowerCase().replace(/[^a-z0-9]+/g, "-") + ".jpg";
94
+ document.body.appendChild(a); a.click(); a.remove();
95
+ toast("Saved " + c.width + "×" + c.height + " JPG");
96
+ }, "image/jpeg", 0.92);
97
+ }
98
+
99
+ function buildUI(meta) {
100
+ state.looks = meta.looks;
101
+ var free = $("#free-looks");
102
+ meta.free.forEach(function (id) {
103
+ var l = lookById(id), b = document.createElement("button");
104
+ b.className = "look" + (id === state.current ? " on" : ""); b.setAttribute("data-id", id); b.type = "button";
105
+ b.innerHTML = '<img alt="" loading="lazy" data-id="' + id + '" src="gallery/market/' + id + '.jpg"><span></span>';
106
+ b.querySelector("span").textContent = l.name;
107
+ b.addEventListener("click", function () { select(id); });
108
+ free.appendChild(b);
109
+ });
110
+ var cols = ["All"].concat(meta.looks.map(function (l) { return l.collection; }).filter(function (c, i, a) { return a.indexOf(c) === i; }));
111
+ var filters = $("#filters");
112
+ cols.forEach(function (c, i) {
113
+ var b = document.createElement("button"); b.className = "chip" + (i ? "" : " on"); b.type = "button"; b.textContent = c;
114
+ b.addEventListener("click", function () {
115
+ filters.querySelectorAll(".chip").forEach(function (x) { x.classList.toggle("on", x === b); });
116
+ document.querySelectorAll("#gallery figure").forEach(function (f) { f.hidden = !(c === "All" || f.getAttribute("data-col") === c); });
117
+ });
118
+ filters.appendChild(b);
119
+ });
120
+ var g = $("#gallery");
121
+ meta.looks.forEach(function (l) {
122
+ var f = document.createElement("figure"); f.className = "g-item"; f.setAttribute("data-col", l.collection);
123
+ f.innerHTML = '<img alt="" loading="lazy" width="480" height="320" data-id="' + l.id + '" src="gallery/market/' + l.id + '.jpg"><figcaption><b></b><small></small></figcaption>';
124
+ f.querySelector("img").alt = l.name + " LUT preview";
125
+ f.querySelector("b").textContent = (l.free ? "🔓 " : "") + l.name;
126
+ f.querySelector("small").textContent = l.collection + " · " + l.desc;
127
+ if (l.free) { f.style.cursor = "pointer"; f.addEventListener("click", function () { select(l.id); window.scrollTo({ top: 0, behavior: "smooth" }); }); }
128
+ g.appendChild(f);
129
+ });
130
+ }
131
+
132
+ function wire() {
133
+ $("#samples").addEventListener("click", function (e) { var s = e.target.getAttribute("data-sample"); if (s) loadSample(s); });
134
+ $("#photo").addEventListener("change", function (e) { openPhoto(e.target.files[0]); e.target.value = ""; });
135
+ $("#cube").addEventListener("change", function (e) { if (e.target.files[0]) openCube(e.target.files[0]); e.target.value = ""; });
136
+ $("#intensity").addEventListener("input", function (e) { state.intensity = e.target.value / 100; $("#int-val").textContent = e.target.value + "%"; render(); });
137
+ $("#split").addEventListener("input", function (e) {
138
+ var v = e.target.value;
139
+ $("#before-clip").style.clipPath = "inset(0 " + (100 - v) + "% 0 0)";
140
+ $("#handle").style.left = v + "%";
141
+ });
142
+ $("#btn-save").addEventListener("click", save);
143
+ ["dragenter", "dragover"].forEach(function (ev) { stage.addEventListener(ev, function (e) { e.preventDefault(); stage.classList.add("drag"); }); });
144
+ ["dragleave", "drop"].forEach(function (ev) { stage.addEventListener(ev, function (e) { e.preventDefault(); stage.classList.remove("drag"); }); });
145
+ stage.addEventListener("drop", function (e) {
146
+ var f = e.dataTransfer.files[0]; if (!f) return;
147
+ if (/\.cube$/i.test(f.name)) openCube(f); else openPhoto(f);
148
+ });
149
+ var buy = $("#buy");
150
+ if (/^https:\/\//.test(CHECKOUT)) { buy.href = CHECKOUT; $("#top-buy").href = "#pack"; }
151
+ else { buy.textContent = "Coming soon"; buy.removeAttribute("href"); buy.classList.add("ghost"); }
152
+ }
153
+
154
+ if (/[?&]thanks=1/.test(location.search)) setTimeout(function () { toast("Thanks for your order! Your download link is in the Polar receipt email."); }, 800);
155
+ window.toneboxApp = { state: state, select: select, openCube: openCube, save: save };
156
+ wire();
157
+ Promise.all([
158
+ fetch("luts/looks.json").then(function (r) { return r.json(); }),
159
+ fetch("luts/preview.bin").then(function (r) { return r.arrayBuffer(); }),
160
+ ]).then(function (res) {
161
+ var meta = res[0], luts = ToneboxLUT.parsePreviewBin(res[1]);
162
+ meta.free.forEach(function (id, i) { state.luts[id] = luts[i]; });
163
+ buildUI(meta);
164
+ loadSample("market");
165
+ }).catch(function (e) { warn("Couldn't load the looks: " + e.message); });
166
+ })();
tonebox/gallery/lake/arctic.jpg ADDED
tonebox/gallery/lake/bleach-bypass.jpg ADDED
tonebox/gallery/lake/blockbuster.jpg ADDED
tonebox/gallery/lake/blue-hour.jpg ADDED
tonebox/gallery/lake/blue-tone.jpg ADDED
tonebox/gallery/lake/bw-green-filter.jpg ADDED
tonebox/gallery/lake/bw-high-contrast.jpg ADDED
tonebox/gallery/lake/bw-neutral.jpg ADDED
tonebox/gallery/lake/bw-red-filter.jpg ADDED
tonebox/gallery/lake/bw-soft.jpg ADDED
tonebox/gallery/lake/candlelight.jpg ADDED
tonebox/gallery/lake/cool-negative.jpg ADDED
tonebox/gallery/lake/cool-plus.jpg ADDED
tonebox/gallery/lake/cross-process.jpg ADDED
tonebox/gallery/lake/crush-blacks.jpg ADDED
tonebox/gallery/lake/cyanotype.jpg ADDED
tonebox/gallery/lake/day-for-night.jpg ADDED
tonebox/gallery/lake/desert-gold.jpg ADDED
tonebox/gallery/lake/dreamy-pastel.jpg ADDED
tonebox/gallery/lake/dungeon.jpg ADDED
tonebox/gallery/lake/dusk.jpg ADDED
tonebox/gallery/lake/expired-stock.jpg ADDED
tonebox/gallery/lake/faded-print.jpg ADDED
tonebox/gallery/lake/fog.jpg ADDED
tonebox/gallery/lake/frozen-tundra.jpg ADDED
tonebox/gallery/lake/golden-hour.jpg ADDED
tonebox/gallery/lake/horror-green.jpg ADDED
tonebox/gallery/lake/lava.jpg ADDED
tonebox/gallery/lake/lift-shadows.jpg ADDED
tonebox/gallery/lake/matte.jpg ADDED
tonebox/gallery/lake/midday-punch.jpg ADDED
tonebox/gallery/lake/moody-forest.jpg ADDED
tonebox/gallery/lake/moonlight.jpg ADDED
tonebox/gallery/lake/muted.jpg ADDED
tonebox/gallery/lake/neon.jpg ADDED
tonebox/gallery/lake/night-city.jpg ADDED
tonebox/gallery/lake/noir-blue.jpg ADDED
tonebox/gallery/lake/original.jpg ADDED
tonebox/gallery/lake/overcast.jpg ADDED
tonebox/gallery/lake/pastel.jpg ADDED
tonebox/gallery/lake/punchy.jpg ADDED
tonebox/gallery/lake/retro-8bit.jpg ADDED
tonebox/gallery/lake/scifi-clean.jpg ADDED
tonebox/gallery/lake/selenium.jpg ADDED
tonebox/gallery/lake/sepia-drama.jpg ADDED
tonebox/gallery/lake/sepia.jpg ADDED
tonebox/gallery/lake/silver-retention.jpg ADDED
tonebox/gallery/lake/slide-punch.jpg ADDED