feat: adjust max and step values for sharpen, edgeThreshold, and scanlines controls.
This commit is contained in:
15
Caddyfile
Normal file
15
Caddyfile
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
email me@syntaxbullet.com
|
||||||
|
}
|
||||||
|
|
||||||
|
yourdomain.com {
|
||||||
|
reverse_proxy web:4321
|
||||||
|
|
||||||
|
# Enable compression
|
||||||
|
encode zstd gzip
|
||||||
|
|
||||||
|
# Robust logging
|
||||||
|
log {
|
||||||
|
output file /var/log/caddy/access.log
|
||||||
|
}
|
||||||
|
}
|
||||||
17
Dockerfile
17
Dockerfile
@@ -1,10 +1,17 @@
|
|||||||
|
# Build stage
|
||||||
|
FROM node:22-alpine AS build
|
||||||
|
WORKDIR /app
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm install
|
||||||
|
COPY . .
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Runtime stage
|
||||||
FROM node:22-alpine AS runtime
|
FROM node:22-alpine AS runtime
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
COPY --from=build /app/dist ./dist
|
||||||
COPY . .
|
COPY --from=build /app/package*.json ./
|
||||||
|
COPY --from=build /app/node_modules ./node_modules
|
||||||
RUN npm install
|
|
||||||
RUN npm run build
|
|
||||||
|
|
||||||
ENV HOST=0.0.0.0
|
ENV HOST=0.0.0.0
|
||||||
ENV PORT=4321
|
ENV PORT=4321
|
||||||
|
|||||||
@@ -1,8 +1,27 @@
|
|||||||
services:
|
services:
|
||||||
web:
|
web:
|
||||||
build: .
|
build: .
|
||||||
ports:
|
restart: always
|
||||||
- "4321:4321"
|
|
||||||
environment:
|
environment:
|
||||||
- PORT=4321
|
- PORT=4321
|
||||||
- HOST=0.0.0.0
|
- HOST=0.0.0.0
|
||||||
|
|
||||||
|
caddy:
|
||||||
|
image: caddy:latest
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
- "443:443/udp"
|
||||||
|
volumes:
|
||||||
|
- ./Caddyfile:/etc/caddy/Caddyfile
|
||||||
|
- caddy_data:/data
|
||||||
|
- caddy_config:/config
|
||||||
|
- caddy_logs:/var/log/caddy
|
||||||
|
depends_on:
|
||||||
|
- web
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
caddy_data:
|
||||||
|
caddy_config:
|
||||||
|
caddy_logs:
|
||||||
|
|||||||
10
package-lock.json
generated
10
package-lock.json
generated
@@ -11,6 +11,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/check": "^0.9.6",
|
"@astrojs/check": "^0.9.6",
|
||||||
"@astrojs/node": "^9.5.2",
|
"@astrojs/node": "^9.5.2",
|
||||||
|
"@lucide/astro": "^0.563.0",
|
||||||
"astro": "^5.17.1",
|
"astro": "^5.17.1",
|
||||||
"gifuct-js": "^2.1.2",
|
"gifuct-js": "^2.1.2",
|
||||||
"pngjs": "^7.0.0",
|
"pngjs": "^7.0.0",
|
||||||
@@ -1181,6 +1182,15 @@
|
|||||||
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@lucide/astro": {
|
||||||
|
"version": "0.563.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@lucide/astro/-/astro-0.563.0.tgz",
|
||||||
|
"integrity": "sha512-X9fNJvRR6pLJfkIEAFQkizWaNVvcduunJoFyR3fwPu30Y6jOu5S9k4k7HTSk3ZrEfqK2eFEqrBqqWH4fwSNKCg==",
|
||||||
|
"license": "ISC",
|
||||||
|
"peerDependencies": {
|
||||||
|
"astro": "^4 || ^5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@oslojs/encoding": {
|
"node_modules/@oslojs/encoding": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz",
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/check": "^0.9.6",
|
"@astrojs/check": "^0.9.6",
|
||||||
"@astrojs/node": "^9.5.2",
|
"@astrojs/node": "^9.5.2",
|
||||||
|
"@lucide/astro": "^0.563.0",
|
||||||
"astro": "^5.17.1",
|
"astro": "^5.17.1",
|
||||||
"gifuct-js": "^2.1.2",
|
"gifuct-js": "^2.1.2",
|
||||||
"pngjs": "^7.0.0",
|
"pngjs": "^7.0.0",
|
||||||
|
|||||||
4
public/favicon.svg
Normal file
4
public/favicon.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||||
|
<rect width="100" height="100" fill="black"/>
|
||||||
|
<text x="50" y="70" font-family="monospace" font-size="70" fill="white" text-anchor="middle" font-weight="900">S</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 240 B |
4
public/robots.txt
Normal file
4
public/robots.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
User-agent: *
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
Sitemap: https://syntaxbullet.com/sitemap-index.xml
|
||||||
@@ -3,24 +3,13 @@ import TuiSlider from "./TuiSlider.astro";
|
|||||||
import TuiSegment from "./TuiSegment.astro";
|
import TuiSegment from "./TuiSegment.astro";
|
||||||
import TuiToggle from "./TuiToggle.astro";
|
import TuiToggle from "./TuiToggle.astro";
|
||||||
import TuiButton from "./TuiButton.astro";
|
import TuiButton from "./TuiButton.astro";
|
||||||
|
import { ChevronDown } from "@lucide/astro";
|
||||||
---
|
---
|
||||||
|
|
||||||
<footer id="tui-controls" class="control-panel">
|
<footer id="tui-controls" class="control-panel">
|
||||||
<div class="mobile-controls-header">
|
<div class="mobile-controls-header">
|
||||||
<span class="mobile-controls-title">CONTROLS</span>
|
<span class="mobile-controls-title">CONTROLS</span>
|
||||||
<svg
|
<ChevronDown class="mobile-toggle-icon" size={24} />
|
||||||
class="mobile-toggle-icon"
|
|
||||||
width="24"
|
|
||||||
height="24"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
>
|
|
||||||
<polyline points="6 9 12 15 18 9"></polyline>
|
|
||||||
</svg>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="control-panel-inner">
|
<div class="control-panel-inner">
|
||||||
@@ -569,6 +558,10 @@ import TuiButton from "./TuiButton.astro";
|
|||||||
.sliders-grid {
|
.sliders-grid {
|
||||||
grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
|
grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.shortcuts-hint {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tui-color-btn {
|
.tui-color-btn {
|
||||||
|
|||||||
@@ -1,23 +1,11 @@
|
|||||||
---
|
---
|
||||||
|
import { ChevronDown, Zap, FileText, Mail } from "@lucide/astro";
|
||||||
---
|
---
|
||||||
|
|
||||||
<aside class="sidebar">
|
<aside class="sidebar">
|
||||||
<div class="mobile-header">
|
<div class="mobile-header">
|
||||||
<span class="mobile-brand">SYNTAXBULLET</span>
|
<span class="mobile-brand">SYNTAXBULLET</span>
|
||||||
<svg
|
<ChevronDown class="mobile-toggle-icon" size={24} />
|
||||||
class="mobile-toggle-icon"
|
|
||||||
width="24"
|
|
||||||
height="24"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
>
|
|
||||||
<polyline points="6 9 12 15 18 9"></polyline>
|
|
||||||
</svg>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="sidebar-content">
|
<div class="sidebar-content">
|
||||||
<div class="brand-group">
|
<div class="brand-group">
|
||||||
@@ -38,25 +26,24 @@
|
|||||||
|
|
||||||
<div class="sidebar-actions">
|
<div class="sidebar-actions">
|
||||||
<a href="/" class="sidebar-link">
|
<a href="/" class="sidebar-link">
|
||||||
<span class="icon">⚡</span> GENERATE
|
<span class="icon"><Zap size={20} /></span> GENERATE
|
||||||
</a>
|
</a>
|
||||||
<a href="/blog" class="sidebar-link">
|
<a href="/blog" class="sidebar-link">
|
||||||
<span class="icon">📝</span> BLOG
|
<span class="icon"><FileText size={20} /></span> BLOG
|
||||||
</a>
|
</a>
|
||||||
<a href="mailto:me@syntaxbullet.com" class="sidebar-link">
|
<a href="mailto:me@syntaxbullet.com" class="sidebar-link">
|
||||||
<span class="icon">✉️</span> CONTACT
|
<span class="icon"><Mail size={20} /></span> CONTACT
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="sidebar-social">
|
<div class="sidebar-social">
|
||||||
<a
|
<a
|
||||||
href="https://github.com/syntaxbullet"
|
href="https://git.ayau.me/syntaxbullet"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
aria-label="GitHub"
|
aria-label="Git"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="20"
|
width="20"
|
||||||
height="20"
|
height="20"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
@@ -65,19 +52,20 @@
|
|||||||
stroke-width="2"
|
stroke-width="2"
|
||||||
stroke-linecap="round"
|
stroke-linecap="round"
|
||||||
stroke-linejoin="round"
|
stroke-linejoin="round"
|
||||||
><path
|
|
||||||
d="M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4"
|
|
||||||
></path><path d="M9 18c-4.51 2-5-2.64-5-2.64"></path></svg
|
|
||||||
>
|
>
|
||||||
|
<path
|
||||||
|
d="M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4"
|
||||||
|
></path>
|
||||||
|
<path d="M9 18c-4.51 2-5-2-7-2"></path>
|
||||||
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
href="https://linkedin.com/in/syntaxbullet"
|
href="https://www.linkedin.com/in/ivan-jovanovic-51b319187/"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
aria-label="LinkedIn"
|
aria-label="LinkedIn"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="20"
|
width="20"
|
||||||
height="20"
|
height="20"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
@@ -86,32 +74,13 @@
|
|||||||
stroke-width="2"
|
stroke-width="2"
|
||||||
stroke-linecap="round"
|
stroke-linecap="round"
|
||||||
stroke-linejoin="round"
|
stroke-linejoin="round"
|
||||||
><path
|
>
|
||||||
|
<path
|
||||||
d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z"
|
d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z"
|
||||||
></path><rect width="4" height="12" x="2" y="9"
|
></path>
|
||||||
></rect><circle cx="4" cy="4" r="2"></circle></svg
|
<rect width="4" height="12" x="2" y="9"></rect>
|
||||||
>
|
<circle cx="4" cy="4" r="2"></circle>
|
||||||
</a>
|
</svg>
|
||||||
<a
|
|
||||||
href="https://twitter.com/syntaxbullet"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
aria-label="Twitter"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="20"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
><path
|
|
||||||
d="M22 4s-.7 2.1-2 3.4c1.6 10-9.4 17.3-18 11.6 2.2.1 4.4-.6 6-2C3 15.5.5 9.6 3 5c2.2 2.6 5.6 4.1 9 4-.9-4.2 4-6.6 7-3.8 1.1 0 3-1.2 3-1.2z"
|
|
||||||
></path></svg
|
|
||||||
>
|
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
20
src/content/blog/coming-soon.md
Normal file
20
src/content/blog/coming-soon.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
title: "The Future of Syntaxbullet"
|
||||||
|
description: "A glimpse into what's coming next for this digital garden."
|
||||||
|
pubDate: "2026-02-10"
|
||||||
|
heroImage: "/blog-placeholder-1.jpg"
|
||||||
|
---
|
||||||
|
|
||||||
|
# Welcome to my Website
|
||||||
|
|
||||||
|
This digital garden is currently sprouting.
|
||||||
|
|
||||||
|
I'm working on a series of articles that explore the intersection of **engineering, design, and artificial intelligence**.
|
||||||
|
|
||||||
|
Upcoming topics will include:
|
||||||
|
- Deep dives into the ASCII art generation techniques used on the homepage.
|
||||||
|
- Modern web performance optimization strategies.
|
||||||
|
- Thoughts on the evolving role of AI in software development.
|
||||||
|
- Case studies of successful AI-powered software projects and papers.
|
||||||
|
|
||||||
|
Stay tuned for updates. In the meantime, feel free to play with the [generator](/).
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
---
|
|
||||||
title: 'System Initialization'
|
|
||||||
description: 'Bootstrapping the Neko ASCII Generator.'
|
|
||||||
pubDate: '2026-02-08'
|
|
||||||
heroImage: '/blog/boot.png'
|
|
||||||
---
|
|
||||||
|
|
||||||
## Initializing Core Systems...
|
|
||||||
|
|
||||||
The Neko ASCII Auto-Generator has been successfully migrated to the Astro framework.
|
|
||||||
|
|
||||||
### Features
|
|
||||||
- Real-time image processing
|
|
||||||
- CLI-inspired controls
|
|
||||||
- Dynamic font scaling
|
|
||||||
- Automatic parameter tuning based on image histogram
|
|
||||||
|
|
||||||
### Changelog v2.0
|
|
||||||
- Migrated from vanilla HTML/JS to Astro
|
|
||||||
- Added Blog module
|
|
||||||
- Improved mobile responsiveness
|
|
||||||
|
|
||||||
Running diagnostics... **OK**
|
|
||||||
Systems online.
|
|
||||||
@@ -12,6 +12,10 @@ const { title, showScroll = false } = Astro.props;
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<meta
|
||||||
|
name="description"
|
||||||
|
content="Syntaxbullet - Full Stack Engineer & Creative Technologist. Building high-performance digital experiences with a focus on engineering, design, and AI."
|
||||||
|
/>
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
|||||||
@@ -14,8 +14,33 @@ import ControlPanel from "../components/ControlPanel.astro";
|
|||||||
<!-- Canvas Layer -->
|
<!-- Canvas Layer -->
|
||||||
<div class="canvas-layer">
|
<div class="canvas-layer">
|
||||||
<div id="loading">Loading...</div>
|
<div id="loading">Loading...</div>
|
||||||
<pre id="ascii-result">Initializing...</pre>
|
<pre id="ascii-result"></pre>
|
||||||
<canvas id="ascii-canvas"></canvas>
|
<canvas id="ascii-canvas"></canvas>
|
||||||
|
|
||||||
|
<!-- Landing Screen -->
|
||||||
|
<div id="landing-screen" class="landing-overlay">
|
||||||
|
<div class="landing-content">
|
||||||
|
<h1>ASCII Art Generator</h1>
|
||||||
|
<p>
|
||||||
|
Generate stunning ASCII art from images. Pull a
|
||||||
|
random image from an anime API or upload your own to
|
||||||
|
get started.
|
||||||
|
</p>
|
||||||
|
<div class="landing-buttons">
|
||||||
|
<button id="btn-start-api" class="landing-btn"
|
||||||
|
>Anime API</button
|
||||||
|
>
|
||||||
|
<button id="btn-start-upload" class="landing-btn"
|
||||||
|
>Upload Image</button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<p class="disclaimer">
|
||||||
|
<b>Disclaimer:</b> Images loaded via the API are not my
|
||||||
|
own and are not filtered or curated. In rare cases, they
|
||||||
|
might contain sensitive material.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ControlPanel />
|
<ControlPanel />
|
||||||
@@ -114,10 +139,35 @@ import ControlPanel from "../components/ControlPanel.astro";
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============= Initialize UI and Load First Image =============
|
// ============= Initialize UI =============
|
||||||
ui.init();
|
ui.init();
|
||||||
loadNewImage().then(() => {
|
|
||||||
queue.ensureFilled();
|
// ============= Landing Screen Logic =============
|
||||||
|
const landingScreen = document.getElementById("landing-screen");
|
||||||
|
const btnStartApi = document.getElementById("btn-start-api");
|
||||||
|
const btnStartUpload = document.getElementById("btn-start-upload");
|
||||||
|
const fileInput = document.getElementById(
|
||||||
|
"file-upload",
|
||||||
|
) as HTMLInputElement;
|
||||||
|
|
||||||
|
const hideLanding = () => {
|
||||||
|
landingScreen?.classList.add("hidden");
|
||||||
|
};
|
||||||
|
|
||||||
|
btnStartApi?.addEventListener("click", () => {
|
||||||
|
hideLanding();
|
||||||
|
loadNewImage().then(() => {
|
||||||
|
queue.ensureFilled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
btnStartUpload?.addEventListener("click", () => {
|
||||||
|
fileInput?.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Hide landing screen when an image is imported (manual upload)
|
||||||
|
document.addEventListener("ascii-image-imported", () => {
|
||||||
|
hideLanding();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<Tooltip />
|
<Tooltip />
|
||||||
@@ -189,6 +239,114 @@ import ControlPanel from "../components/ControlPanel.astro";
|
|||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Landing Overlay */
|
||||||
|
.landing-overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(0, 0, 0, 0.85);
|
||||||
|
backdrop-filter: blur(12px);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 100;
|
||||||
|
transition:
|
||||||
|
opacity 0.6s cubic-bezier(0.4, 0, 0.2, 1),
|
||||||
|
visibility 0.6s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-overlay.hidden {
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-content {
|
||||||
|
max-width: 440px;
|
||||||
|
padding: 2.5rem;
|
||||||
|
text-align: center;
|
||||||
|
background: rgba(15, 15, 15, 0.9);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 30px 60px rgba(0, 0, 0, 0.6);
|
||||||
|
animation: landing-in 0.8s cubic-bezier(0.16, 1, 0.3, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes landing-in {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(20px) scale(0.95);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0) scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-content h1 {
|
||||||
|
font-size: 1.75rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-content p {
|
||||||
|
font-size: 0.95rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: rgba(255, 255, 255, 0.6);
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.75rem;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-btn {
|
||||||
|
padding: 0.75rem 1.25rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.landing-btn:hover {
|
||||||
|
background: #fff;
|
||||||
|
color: #000;
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 4px 12px rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#btn-start-api {
|
||||||
|
background: #fff;
|
||||||
|
color: #000;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#btn-start-api:hover {
|
||||||
|
background: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disclaimer {
|
||||||
|
font-size: 0.7rem !important;
|
||||||
|
color: rgba(255, 255, 255, 0.3) !important;
|
||||||
|
line-height: 1.4 !important;
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
text-align: left;
|
||||||
|
padding-top: 1.5rem;
|
||||||
|
border-top: 1px solid rgba(255, 255, 255, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
/* Responsive */
|
/* Responsive */
|
||||||
@media (max-width: 1024px) {
|
@media (max-width: 1024px) {
|
||||||
.split-layout {
|
.split-layout {
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ export class AsciiExporter {
|
|||||||
const b = pixels[i + 2];
|
const b = pixels[i + 2];
|
||||||
|
|
||||||
// 1. Calculate Luma
|
// 1. Calculate Luma
|
||||||
let luma = (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255;
|
// 1. Calculate Luma (skipped, using adjusted color luma below)
|
||||||
|
|
||||||
// 2. Apply Adjustments
|
// 2. Apply Adjustments
|
||||||
// Note: For color mode, we might want to keep original color
|
// Note: For color mode, we might want to keep original color
|
||||||
|
|||||||
@@ -472,6 +472,8 @@ export class UIBindings {
|
|||||||
this.updateUI();
|
this.updateUI();
|
||||||
await this.controller.generate();
|
await this.controller.generate();
|
||||||
this.controller.hideLoading();
|
this.controller.hideLoading();
|
||||||
|
// Notify that an image was successfully imported
|
||||||
|
document.dispatchEvent(new CustomEvent('ascii-image-imported'));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Import failed:", err);
|
console.error("Import failed:", err);
|
||||||
this.controller.hideLoading();
|
this.controller.hideLoading();
|
||||||
|
|||||||
@@ -2,8 +2,11 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ES2020",
|
"target": "ES2020",
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "bundler",
|
||||||
"lib": ["ES2020", "DOM"],
|
"lib": [
|
||||||
|
"ES2020",
|
||||||
|
"DOM"
|
||||||
|
],
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
@@ -16,6 +19,11 @@
|
|||||||
"outDir": "./dist",
|
"outDir": "./dist",
|
||||||
"rootDir": "./src"
|
"rootDir": "./src"
|
||||||
},
|
},
|
||||||
"include": ["src/**/*"],
|
"include": [
|
||||||
"exclude": ["node_modules", "dist"]
|
"src/**/*"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"dist"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user