PageSourceSearch

https://fatoe.com/suite/doodl/

html fatoe.com collected 2026-09-26 12:41:01 UTC 14,306 bytes, 487 lines download raw bytes

1<!doctype html>
2<html lang="en">
3<head>
4  <meta charset="utf-8" />
5  <meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover" />
6  <title>DOODL</title>
7
8  <!-- Uses your DOODL system tokens + styles -->
9  <link rel="stylesheet" href="./doodl.css" />
10
11  <style>
12    .lp{
13      min-height:100vh;
14      display:flex;
15      align-items:center;
16      justify-content:center;
17      padding:calc(var(--safe-pad) * 2) var(--safe-pad);
18      text-align:center;
19    }
20    .lp-inner{ width:min(600px, 100%); }
21
22    .lp-logo{
23      display:block;
24      width:clamp(320px, 42vw, 460px);
25      height:auto;
26      margin:0 auto 16px;
27      object-fit:contain;
28      object-position:center bottom;
29      display:block;
30      user-select:none;
31      -webkit-user-select:none;
32      -webkit-user-drag:none;
33      pointer-events:none;
34    }
35
36    .lp-tagline{
37      margin:0 auto 28px;
38      color:var(--muted);
39      font-size:13px;
40      letter-spacing:.2px;
41    }
42
43    /* --- Launch Button (premium fill-to-ink) --- */
44    .lp-cta{
45      --btn-bg: #ffffff;
46      --btn-fg: #111111;
47      --btn-ink: #0a0a0a;
48      --btn-radius: 999px;
49
50      position:relative;
51      display:inline-flex;
52      align-items:center;
53      justify-content:center;
54      gap:10px;
55      padding:18px 32px;
56      border-radius:var(--btn-radius);
57      border:1px solid rgba(0,0,0,0.12);
58      background:var(--btn-bg);
59      color:var(--btn-fg);
60      font-weight:650;
61      text-decoration:none;
62      /* custom shadow so we can animate it */
63      box-shadow: 0 14px 32px rgba(0,0,0,0.14), 0 2px 8px rgba(0,0,0,0.06);
64      cursor:pointer;
65
66      overflow:hidden;
67      -webkit-tap-highlight-color: transparent;
68
69      /* no bounce */
70      transform:none;
71      transition: box-shadow 160ms ease, border-color 160ms ease, color 220ms ease;
72      margin-top: 46px; /* lower button / more breathing room */
73    }
74
75    /* Ambient shadow sweep (subtle, premium) */
76    .lp-cta{
77      animation: shadowSweep 2.8s ease-in-out infinite;
78    }
79    .lp-cta.is-launching{ animation: none; }
80    @keyframes shadowSweep{
81      0%   { box-shadow: 0 14px 32px rgba(0,0,0,0.14), 0 2px 8px rgba(0,0,0,0.06); }
82      40%  { box-shadow: 10px 16px 34px rgba(0,0,0,0.13), 0 2px 8px rgba(0,0,0,0.06); }
83      80%  { box-shadow: -10px 16px 34px rgba(0,0,0,0.13), 0 2px 8px rgba(0,0,0,0.06); }
84      100% { box-shadow: 0 14px 32px rgba(0,0,0,0.14), 0 2px 8px rgba(0,0,0,0.06); }
85    }
86
87    /* Hover “blip” (fast, sleek) */
88    .lp-cta::after{
89      content:"";
90      position:absolute;
91      inset:0;
92      background:rgba(10,10,10,0.08);
93      opacity:0;
94      pointer-events:none;
95    }
96    .lp-cta:hover{
97      border-color: rgba(0,0,0,0.18);
98    }
99    .lp-cta:hover::after{
100      animation: blip 240ms ease-out 1;
101    }
102    @keyframes blip{
103      0%{ opacity:0; }
104      30%{ opacity:1; }
105      100%{ opacity:0; }
106    }
107
108    /* Progress fill layer */
109    .lp-cta::before{
110      content:"";
111      position:absolute;
112      inset:0;
113      background: var(--btn-ink);
114      transform: scaleX(0);
115      transform-origin: left center;
116      transition: transform 3000ms cubic-bezier(.2,.9,.2,1);
117      pointer-events:none;
118      z-index:0;
119    }
120
121    /* Content stays above fill */
122    .lp-cta .brush,
123    .lp-cta .label{
124      position:relative;
125      z-index:1;
126    }
127
128    /* Icon: dark by default */
129    .lp-cta .brush{
130      width:18px;
131      height:18px;
132      display:block;
133      filter:none; /* dark on light */
134      opacity:.95;
135      transition: filter 220ms ease, opacity 220ms ease;
136    }
137
138    /* Launch state: fill + invert content */
139    .lp-cta.is-launching{
140      cursor:default;
141      pointer-events:none;
142      color:#ffffff;
143      border-color: rgba(0,0,0,0.20);
144    }
145    .lp-cta.is-launching::before{
146      transform: scaleX(1);
147    }
148    .lp-cta.is-launching .brush{
149      filter: invert(1);
150      opacity:1;
151    }
152
153    /* Reduced motion: instant swap, still clean */
154    @media (prefers-reduced-motion: reduce){
155      .lp-cta{ animation:none; }
156      .lp-cta::before{ transition:none; }
157      .lp-cta:hover::after{ animation:none; }
158    }
159
160
161    /* Subtle default sheen (premium, not quirky) */
162    .lp-cta .gleam{
163      position:absolute;
164      inset:-2px;
165      z-index:0;
166      pointer-events:none;
167      border-radius: var(--btn-radius);
168      background: linear-gradient(110deg,
169        rgba(255,255,255,0) 0%,
170        rgba(255,255,255,0.55) 18%,
171        rgba(255,255,255,0) 36%);
172      transform: translateX(-130%);
173      opacity: 0.6;
174      animation: gleam 3.8s ease-in-out infinite;
175      mix-blend-mode: overlay;
176    }
177    @keyframes gleam{
178      0%{ transform: translateX(-130%); opacity:0.0; }
179      10%{ opacity:0.55; }
180      35%{ transform: translateX(130%); opacity:0.0; }
181      100%{ transform: translateX(130%); opacity:0.0; }
182    }
183    .lp-cta.is-launching .gleam{ opacity:0; animation:none; }
184    
185
186    /* Compatible browsers */
187    .lp-browsers{
188      margin-top: clamp(240px, 24.0vh, 380px);
189      color:var(--muted);
190      font-size:12px;
191      user-select:none;
192      -webkit-user-select:none;
193    }
194    .lp-browser-row{
195      margin-top:18px;
196      display:flex;
197      justify-content:center;
198      gap:34px;
199      align-items:center;
200    }
201
202    /* Browser icons (v3) */
203    .bicon{
204      position:relative;
205      display:inline-flex;
206      align-items: flex-end;
207      justify-content:center;
208      width:85px;
209      height:85px;
210      border-radius:20px;
211      text-decoration:none;
212      outline:none;
213      -webkit-tap-highlight-color: transparent;
214    }
215    .bicon:focus-visible{ box-shadow: 0 0 0 3px rgba(0,0,0,0.18); }
216
217    .bicon img{
218      width:75px;
219      height:75px;
220      object-fit:contain;
221      opacity:.95;
222      transition: transform 120ms ease, opacity 120ms ease;
223    }
224    .bicon:hover img{ transform: translateY(-1px); opacity: 1; }
225    .bicon:active img{ transform: translateY(0px) scale(.98); }
226
227    
228    .btip{
229      position:absolute;
230      left:50%;
231      top: calc(100% + 2px); /* tighter to icon */
232      transform: translate(-50%, 0);
233      background:#0a0a0a;
234      color:#fff;
235      font-size:11px;
236      padding:7px 10px;
237      border-radius:10px;
238      white-space:nowrap;
239      opacity:0;
240      pointer-events:none;
241      transition: opacity 120ms ease;
242      box-shadow: var(--shadow);
243    }
244    .btip::before{
245      content:"";
246      position:absolute;
247      left:50%;
248      top:-6px;
249      transform: translateX(-50%);
250      width:0; height:0;
251      border-left:6px solid transparent;
252      border-right:6px solid transparent;
253      border-bottom:6px solid #0a0a0a;
254    }
255    .bicon:hover .btip,
256    .bicon:focus-visible .btip{
257      opacity:1;
258    }
259
260.lp-foot{
261      position:fixed;
262      left: var(--safe-pad);
263      bottom: var(--safe-pad);
264      z-index:4;
265      color: var(--muted);
266      font-size:12px;
267      user-select:none;
268      -webkit-user-select:none;
269    }
270  
271    /* --- Mobile viewport safety: prevent overlap with fixed footer + info button --- */
272    @media (max-width: 520px), (max-height: 760px){
273      /* Give the main column extra breathing room above fixed UI */
274      .lp{
275        padding-bottom: calc(var(--safe-pad) * 7);
276      }
277
278      /* Pull the browser section UP so it doesn't collide with footer/info */
279      .lp-browsers{
280        margin-top: clamp(90px, 11vh, 170px);
281      }
282
283      /* Slightly reduce icon footprint on small screens */
284      .bicon{
285        width: 72px;
286        height: 72px;
287      }
288      .bicon img{
289        width: 62px;
290        height: 62px;
291      }
292
293      /* Nudge fixed elements to respect safe areas */
294      .lp-foot{
295        bottom: calc(var(--safe-pad) + env(safe-area-inset-bottom));
296      }
297      .info-wrap{
298        bottom: calc(var(--safe-pad) + env(safe-area-inset-bottom));
299      }
300    }
301
302  
303    /* --- Page wipe transition (launch -> app) --- */
304    .page-wipe{
305      position: fixed;
306      inset: 0;
307      background: var(--bg, #f5f5f5);
308      transform: translateX(-110%);
309      z-index: 9999;
310      pointer-events: none;
311      transition: transform 480ms cubic-bezier(.2,.9,.2,1);
312    }
313    .page-wipe.is-active{
314      transform: translateX(0%);
315    }
316    .page-wipe.is-flash{
317      background: #ffffff;
318      transition: background 140ms ease;
319    }
320    @media (prefers-reduced-motion: reduce){
321      .page-wipe{ transition: none; }
322    }
323
324  </style>
325
326  <meta name="description" content="DOODL — a simple web-based doodle pad. Draw anywhere, anytime." />
327
328  <link rel="canonical" href="https://fatoe.com/suite/doodl/" />
329
330  <meta property="og:url" content="https://fatoe.com/suite/doodl/" />
331</head>
332
333<body>
334  <div class="page-wipe" id="pageWipe" aria-hidden="true"></div>
335  <main class="lp">
336    <div class="lp-inner">
337      <img id="lpLogo" class="lp-logo" alt="DOODL" />
338      <p id="lpTagline" class="lp-tagline">A simple web-based doodle pad.</p>
339
340      <!-- Launch DOODL (click triggers fill, then navigates) -->
341      <a class="lp-cta" href="./app/" id="launchBtn" aria-label="Launch DOODL"><span class="gleam" aria-hidden="true"></span>
342        <img class="brush" alt="" src="https://fatoe.com/suite/doodl/assets/brush_icon.svg" />
343        <span class="label">Launch DOODL</span>
344      </a>
345
346      <div class="lp-browsers" aria-label="Compatible browsers">
347        <div>Compatible browsers</div>
348
349        <div class="lp-browser-row">
350          <a class="bicon" href="https://www.google.com/chrome/" target="_blank" rel="noopener noreferrer"
351             aria-label="Open Chrome download page">
352            <img alt="Chrome" src="https://fatoe.com/suite/doodl/assets/logo_chrome.png" />
353            <span class="btip" role="tooltip">Chrome</span>
354          </a>
355
356          <a class="bicon" href="https://www.mozilla.org/firefox/new/" target="_blank" rel="noopener noreferrer"
357             aria-label="Open Firefox download page">
358            <img alt="Firefox" src="https://fatoe.com/suite/doodl/assets/logo_firefox.png" />
359            <span class="btip" role="tooltip">Firefox</span>
360          </a>
361
362          <a class="bicon" href="https://chatgpt.com/atlas" target="_blank" rel="noopener noreferrer"
363             aria-label="Open Atlas browser website">
364            <img alt="Atlas" src="https://fatoe.com/suite/doodl/assets/logo_atlas.png" />
365            <span class="btip" role="tooltip">Atlas</span>
366          </a>
367        </div>
368      </div>
369    </div>
370  </main>
371
372  <div class="lp-foot">© 2026 Fatoe. Los Angeles, CA. Est. Y2K.</div>
373
374  <div class="info-wrap">
375    <button class="info-btn" id="infoBtn" aria-label="Info" title="Info">i</button>
376    <div class="tooltip" id="tooltip" data-open="false">
377      <span class="tip-title">DOODL</span>
378      <span class="tip-body">
379        Best experience: Chrome, Firefox, and Atlas.<br />
380        Developer note: Safari support still in development.
381      </span>
382      <span class="tip-sub">Tap Launch to begin.</span>
383    </div>
384  </div>
385
386  
386<script>
387    // Random logo per load (avoid repeating last in this session)
388    (function(){
389      const logos = [
390        "https://fatoe.com/suite/doodl/assets/doodl_01.png",
391        "https://fatoe.com/suite/doodl/assets/doodl_02.png",
392        "https://fatoe.com/suite/doodl/assets/doodl_03.png",
393        "https://fatoe.com/suite/doodl/assets/doodl_04.png"
394      ];
395      const last = Number(sessionStorage.getItem("doodl_lp_logo")) || -1;
396      let idx = Math.floor(Math.random() * logos.length);
397      if (logos.length > 1 && idx === last) idx = (idx + 1) % logos.length;
398
399      sessionStorage.setItem("doodl_lp_logo", String(idx));
400      const img = document.getElementById("lpLogo");
401      if (img) img.src = logos[idx];
402    })();
403
404    // Random tagline per load (avoid repeating last)
405    (function(){
406      const taglines = [
407        "A simple web-based doodle pad.",
408        "Draw anywhere, anytime.",
409        "Make something small. Make it yours.",
410        "Quick ideas, clean output.",
411        "A pocket sketchbook for the web."
412      ];
413      const last = Number(sessionStorage.getItem("doodl_lp_tag")) || -1;
414      let idx = Math.floor(Math.random() * taglines.length);
415      if (taglines.length > 1 && idx === last) idx = (idx + 1) % taglines.length;
416
417      sessionStorage.setItem("doodl_lp_tag", String(idx));
418      const el = document.getElementById("lpTagline");
419      if (el) el.textContent = taglines[idx];
420    })();
421
422    // Info tooltip toggle
423    (function(){
424      const btn = document.getElementById("infoBtn");
425      const tip = document.getElementById("tooltip");
426      if (!btn || !tip) return;
427
428      function close(){ tip.setAttribute("data-open","false"); }
429      function toggle(){
430        const open = tip.getAttribute("data-open") === "true";
431        tip.setAttribute("data-open", open ? "false" : "true");
432      }
433
434      btn.addEventListener("click", function(e){
435        e.stopPropagation();
436        toggle();
437      });
438
439      document.addEventListener("click", close);
440      document.addEventListener("keydown", function(e){
441        if (e.key === "Escape") close();
442      });
443    })();
444
445
446    // Launch button: click -> fill-to-ink -> page wipe -> navigate
447    (function(){
448      const a = document.getElementById("launchBtn");
449      const wipe = document.getElementById("pageWipe");
450      if (!a) return;
451
452      const reduceMotion = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
453
454      // Total pacing target ~3s
455      const FILL_MS = reduceMotion ? 0 : 2400;
456      const WIPE_MS = reduceMotion ? 0 : 480;
457      const FLASH_MS = reduceMotion ? 0 : 140;
458
459      a.addEventListener("click", function(e){
460        if (a.classList.contains("is-launching")) return;
461        e.preventDefault();
462
463        a.classList.add("is-launching");
464        a.setAttribute("aria-disabled", "true");
465
466        window.setTimeout(function(){
467          if (!wipe){
468            window.location.href = a.getAttribute("href");
469            return;
470          }
471
472          wipe.classList.add("is-active");
473
474          window.setTimeout(function(){
475            wipe.classList.add("is-flash");
476            window.setTimeout(function(){
477              window.location.href = a.getAttribute("href");
478            }, FLASH_MS);
479          }, Math.max(0, WIPE_MS - 160));
480
481        }, FILL_MS);
482      });
483    })();
484
485</script>
485
486</body>
487</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.