Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Angel Tarot Card App</title> | |
<style> | |
body { | |
margin: 0; | |
font-family: Arial, sans-serif; | |
display: flex; | |
background: #222; | |
color: #fff; | |
} | |
#canvas-container { | |
flex: 1; | |
height: 100vh; | |
border-right: 2px solid #444; | |
} | |
#canvas { | |
display: block; | |
} | |
#sidebar { | |
width: 300px; | |
padding: 20px; | |
overflow-y: auto; | |
background: #333; | |
} | |
#sidebar h2 { | |
margin-top: 0; | |
color: #ffd700; | |
} | |
#svg-preview { | |
width: 100%; | |
height: 400px; | |
background: #fff; | |
border: 2px solid #ffd700; | |
margin-bottom: 10px; | |
} | |
#download-link { | |
display: block; | |
margin: 10px 0; | |
padding: 10px; | |
background: #ffd700; | |
color: #000; | |
text-align: center; | |
text-decoration: none; | |
border-radius: 5px; | |
} | |
#download-link:hover { | |
background: #ffeb3b; | |
} | |
#card-details { | |
font-size: 14px; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="canvas-container"> | |
<canvas id="canvas"></canvas> | |
</div> | |
<div id="sidebar"> | |
<h2>Selected Card</h2> | |
<div id="svg-preview"></div> | |
<a id="download-link" href="#" download="card.svg">Download SVG</a> | |
<div id="card-details">Select a card to view details.</div> | |
</div> | |
<script> | |
// Tarot deck data with updated names | |
const majorArcanaNames = [ | |
"The Dreamer", "The Magician", "The High Priestess", "The Empress", "The Emperor", | |
"The Hierophant", "The Lovers", "The Chariot", "Strength", "The Hermit", | |
"Wheel of Fortune", "Justice", "The Hanged Man", "Death", "Temperance", | |
"The Devil", "The Tower", "The Star", "The Moon", "The Sun", | |
"Judgement", "The World" | |
]; | |
const minorArcanaRanks = ["Ace", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Page", "Knight", "Queen", "King"]; | |
const cards = [ | |
{ name: "0 - The Dreamer", baseName: "Ariel", description: "Oversees nature, environmental balance", quotes: ["Guides wildlife harmony", "Protects earth’s balance", "Instinctive environmental wisdom"], type: "Major", suit: "", number: 0 }, | |
{ name: "1 - The Magician", baseName: "Gabriel", description: "Delivers divine messages", quotes: ["Delivers divine revelations", "Speaks truth clearly", "Inspired communicative clarity"], type: "Major", suit: "", number: 1 }, | |
{ name: "2 - The High Priestess", baseName: "Haniel", description: "Enhances intuition, feminine energy", quotes: ["Unveils hidden truths", "Honors intuitive guidance", "Radiant spiritual joy"], type: "Major", suit: "", number: 2 }, | |
{ name: "3 - The Empress", baseName: "Chamuel", description: "Fosters love, harmonious relationships", quotes: ["Builds peaceful bonds", "Promotes compassionate unity", "Loving relational grace"], type: "Major", suit: "", number: 3 }, | |
{ name: "4 - The Emperor", baseName: "Michael", description: "Protects against evil", quotes: ["Defeats cosmic evil", "Upholds divine justice", "Courageous protective strength"], type: "Major", suit: "", number: 4 }, | |
{ name: "5 - The Hierophant", baseName: "Metatron", description: "Records life events, ascension", quotes: ["Chronicles spiritual journeys", "Teaches sacred wisdom", "Divinely ordered insight"], type: "Major", suit: "", number: 5 }, | |
{ name: "6 - The Lovers", baseName: "Zadkiel", description: "Promotes forgiveness, spiritual growth", quotes: ["Heals relational rifts", "Advocates merciful love", "Forgiving spiritual grace"], type: "Major", suit: "", number: 6 }, | |
{ name: "7 - The Chariot", baseName: "Raphael", description: "Heals body, mind, spirit", quotes: ["Restores holistic health", "Guides healing paths", "Compassionate restorative power"], type: "Major", suit: "", number: 7 }, | |
{ name: "8 - Strength", baseName: "Uriel", description: "Illuminates wisdom, prophecy", quotes: ["Reveals prophetic light", "Guides with wisdom", "Resilient divine clarity"], type: "Major", suit: "", number: 8 }, | |
{ name: "9 - The Hermit", baseName: "Raziel", description: "Reveals divine mysteries", quotes: ["Unlocks esoteric mysteries", "Seeks divine knowledge", "Mystical insightful depth"], type: "Major", suit: "", number: 9 }, | |
{ name: "10 - Wheel of Fortune", baseName: "Sandalphon", description: "Carries prayers, nurtures music", quotes: ["Elevates human prayers", "Harmonizes cosmic rhythms", "Musical spiritual flow"], type: "Major", suit: "", number: 10 }, | |
{ name: "11 - Justice", baseName: "Raguel", description: "Ensures justice, fairness", quotes: ["Restores angelic harmony", "Upholds cosmic justice", "Equitable divine balance"], type: "Major", suit: "", number: 11 }, | |
{ name: "12 - The Hanged Man", baseName: "Jeremiel", description: "Assists life reviews, transformation", quotes: ["Guides soul reviews", "Encourages inner growth", "Transformative spiritual insight"], type: "Major", suit: "", number: 12 }, | |
{ name: "13 - Death", baseName: "Azrael", description: "Transitions souls, embraces change", quotes: ["Guides departing souls", "Embraces life’s cycles", "Gentle transitional peace"], type: "Major", suit: "", number: 13 }, | |
{ name: "14 - Temperance", baseName: "Jophiel", description: "Inspires creativity, divine wisdom", quotes: ["Inspires divine art", "Cultivates aesthetic harmony", "Creative spiritual balance"], type: "Major", suit: "", number: 14 }, | |
{ name: "15 - The Devil", baseName: "Temptation", description: "Challenges morality, tests resolve", quotes: ["Exposes inner shadows", "Confronts personal ethics", "Resilient moral strength"], type: "Major", suit: "", number: 15 }, | |
{ name: "16 - The Tower", baseName: "Disruption", description: "Breaks illusions, sparks awakening", quotes: ["Shatters false beliefs", "Demands honest reflection", "Courageous transformative clarity"], type: "Major", suit: "", number: 16 }, | |
{ name: "17 - The Star", baseName: "Hope", description: "Guides through darkness, inspires faith", quotes: ["Illuminates hopeful paths", "Fosters unwavering trust", "Radiant optimistic spirit"], type: "Major", suit: "", number: 17 }, | |
{ name: "18 - The Moon", baseName: "Intuition", description: "Reveals subconscious, guides dreams", quotes: ["Unveils hidden insights", "Trusts inner wisdom", "Mystical intuitive depth"], type: "Major", suit: "", number: 18 }, | |
{ name: "19 - The Sun", baseName: "Joy", description: "Radiates vitality, celebrates life", quotes: ["Spreads boundless light", "Embraces pure happiness", "Vibrant joyful energy"], type: "Major", suit: "", number: 19 }, | |
{ name: "20 - Judgement", baseName: "Awakening", description: "Calls for renewal, reckoning", quotes: ["Ignites spiritual rebirth", "Judges with fairness", "Redemptive divine clarity"], type: "Major", suit: "", number: 20 }, | |
{ name: "21 - The World", baseName: "Completion", description: "Unifies all, fulfills destiny", quotes: ["Completes cosmic cycles", "Honors universal unity", "Holistic divine harmony"], type: "Major", suit: "", number: 21 }, | |
{ name: "Ace of Fire", baseName: "Uriel", description: "Ignites wisdom, prophetic light", quotes: ["Reveals divine truth", "Guides with clarity", "Fiery spiritual insight"], type: "Minor", suit: "Fire", number: 1 }, | |
{ name: "Two of Fire", baseName: "Jophiel", description: "Sparks creative inspiration", quotes: ["Inspires artistic beauty", "Cultivates aesthetic truth", "Creative divine spark"], type: "Minor", suit: "Fire", number: 2 }, | |
{ name: "Three of Fire", baseName: "Sachiel", description: "Fuels wealth, charity", quotes: ["Attracts abundant prosperity", "Shares generous wealth", "Charitable fiery spirit"], type: "Minor", suit: "Fire", number: 3 }, | |
{ name: "Four of Fire", baseName: "Barachiel", description: "Ignites divine blessings", quotes: ["Distributes sacred gifts", "Spreads divine favor", "Blessed fiery grace"], type: "Minor", suit: "Fire", number: 4 }, | |
{ name: "Five of Fire", baseName: "Camael", description: "Burns with courage", quotes: ["Strengthens bold resolve", "Upholds fearless honor", "Courageous fiery spirit"], type: "Minor", suit: "Fire", number: 5 }, | |
{ name: "Six of Fire", baseName: "Lugh", description: "Radiates heroic light", quotes: ["Leads with skill", "Honors heroic duty", "Fiery heroic valor"], type: "Minor", suit: "Fire", number: 6 }, | |
{ name: "Seven of Fire", baseName: "Thor", description: "Strikes with power", quotes: ["Defends with might", "Protects with strength", "Powerful fiery resolve"], type: "Minor", suit: "Fire", number: 7 }, | |
{ name: "Eight of Fire", baseName: "Pele", description: "Erupts with volcanic force", quotes: ["Transforms through fire", "Respects nature’s power", "Fiery creative energy"], type: "Minor", suit: "Fire", number: 8 }, | |
{ name: "Nine of Fire", baseName: "Indra", description: "Commands thunderous energy", quotes: ["Wields cosmic storms", "Leads with authority", "Thunderous fiery might"], type: "Minor", suit: "Fire", number: 9 }, | |
{ name: "Ten of Fire", baseName: "Kū", description: "Fuels warlike passion", quotes: ["Drives fierce strength", "Honors warrior code", "Fiery martial spirit"], type: "Minor", suit: "Fire", number: 10 }, | |
{ name: "Page of Fire", baseName: "Valkyrie", description: "Explores fiery paths", quotes: ["Guides warrior souls", "Seeks bold truth", "Fiery adventurous spirit"], type: "Minor", suit: "Fire", number: 11 }, | |
{ name: "Knight of Fire", baseName: "Xian", description: "Pursues transformative quests", quotes: ["Seeks divine immortality", "Follows fiery path", "Questing fiery soul"], type: "Minor", suit: "Fire", number: 12 }, | |
{ name: "Queen of Fire", baseName: "Freyja", description: "Rules with passionate magic", quotes: ["Weaves love’s fire", "Guides with passion", "Fiery magical grace"], type: "Minor", suit: "Fire", number: 13 }, | |
{ name: "King of Fire", baseName: "Odin", description: "Masters fiery wisdom", quotes: ["Leads with insight", "Rules with honor", "Fiery divine wisdom"], type: "Minor", suit: "Fire", number: 14 }, | |
{ name: "Ace of Air", baseName: "Gabriel", description: "Initiates divine communication", quotes: ["Delivers sacred messages", "Speaks divine truth", "Clear airy wisdom"], type: "Minor", suit: "Air", number: 1 }, | |
{ name: "Two of Air", baseName: "Raguel", description: "Balances cosmic fairness", quotes: ["Restores angelic justice", "Ensures equitable truth", "Airy balanced clarity"], type: "Minor", suit: "Air", number: 2 }, | |
{ name: "Three of Air", baseName: "Anael", description: "Inspires intellectual love", quotes: ["Fosters loving thoughts", "Guides relational truth", "Airy romantic wisdom"], type: "Minor", suit: "Air", number: 3 }, | |
{ name: "Four of Air", baseName: "Tennin", description: "Carries celestial messages", quotes: ["Guides with grace", "Shares divine insights", "Airy celestial lightness"], type: "Minor", suit: "Air", number: 4 }, | |
{ name: "Five of Air", baseName: "Morrígan", description: "Foretells intellectual fate", quotes: ["Predicts strategic outcomes", "Honors fated truth", "Airy prophetic vision"], type: "Minor", suit: "Air", number: 5 }, | |
{ name: "Six of Air", baseName: "Yéil", description: "Tricks with cleverness", quotes: ["Weaves cunning plans", "Values sharp wit", "Airy trickster mind"], type: "Minor", suit: "Air", number: 6 }, | |
{ name: "Seven of Air", baseName: "Nanabozho", description: "Teaches through stories", quotes: ["Shares wise tales", "Teaches through wit", "Airy narrative wisdom"], type: "Minor", suit: "Air", number: 7 }, | |
{ name: "Eight of Air", baseName: "Susanoo", description: "Stirs intellectual storms", quotes: ["Drives dynamic thoughts", "Challenges with truth", "Airy stormy intellect"], type: "Minor", suit: "Air", number: 8 }, | |
{ name: "Nine of Air", baseName: "Devas", description: "Enlightens with divine ideas", quotes: ["Illuminates cosmic truths", "Guides with clarity", "Airy divine insight"], type: "Minor", suit: "Air", number: 9 }, | |
{ name: "Ten of Air", baseName: "Raqib", description: "Records intellectual deeds", quotes: ["Chronicles good thoughts", "Values honest records", "Airy truthful scribe"], type: "Minor", suit: "Air", number: 10 }, | |
{ name: "Page of Air", baseName: "Álfar", description: "Explores airy realms", quotes: ["Seeks ethereal truths", "Honors airy freedom", "Airy curious spirit"], type: "Minor", suit: "Air", number: 11 }, | |
{ name: "Knight of Air", baseName: "Atid", description: "Pursues truthful records", quotes: ["Tracks honest deeds", "Upholds truthful justice", "Airy diligent scribe"], type: "Minor", suit: "Air", number: 12 }, | |
{ name: "Queen of Air", baseName: "Amaterasu", description: "Illuminates with clarity", quotes: ["Shines divine light", "Guides with truth", "Airy radiant wisdom"], type: "Minor", suit: "Air", number: 13 }, | |
{ name: "King of Air", baseName: "Gitchi Manitou", description: "Masters airy spirit", quotes: ["Guides cosmic intellect", "Rules with wisdom", "Airy divine clarity"], type: "Minor", suit: "Air", number: 14 }, | |
{ name: "Ace of Water", baseName: "Raphael", description: "Initiates emotional healing", quotes: ["Heals heart’s wounds", "Guides compassionate paths", "Watery healing grace"], type: "Minor", suit: "Water", number: 1 }, | |
{ name: "Two of Water", baseName: "Chamuel", description: "Deepens loving connections", quotes: ["Fosters heartfelt bonds", "Promotes loving unity", "Watery compassionate love"], type: "Minor", suit: "Water", number: 2 }, | |
{ name: "Three of Water", baseName: "Zadkiel", description: "Flows with forgiveness", quotes: ["Heals through mercy", "Advocates forgiving love", "Watery merciful grace"], type: "Minor", suit: "Water", number: 3 }, | |
{ name: "Four of Water", baseName: "Haniel", description: "Stirs intuitive depths", quotes: ["Reveals inner truths", "Honors intuitive flow", "Watery spiritual joy"], type: "Minor", suit: "Water", number: 4 }, | |
{ name: "Five of Water", baseName: "Apsaras", description: "Dances with emotional grace", quotes: ["Guides soul’s dance", "Embraces emotional beauty", "Watery graceful spirit"], type: "Minor", suit: "Water", number: 5 }, | |
{ name: "Six of Water", baseName: "Brigid", description: "Nurtures emotional healing", quotes: ["Heals with poetry", "Fosters emotional peace", "Watery poetic grace"], type: "Minor", suit: "Water", number: 6 }, | |
{ name: "Seven of Water", baseName: "Lono", description: "Soothes with peace", quotes: ["Brings tranquil harmony", "Cultivates peaceful flow", "Watery serene spirit"], type: "Minor", suit: "Water", number: 7 }, | |
{ name: "Eight of Water", baseName: "Orca Spirit", description: "Guides emotional depths", quotes: ["Navigates soul’s waters", "Protects emotional truth", "Watery guardian spirit"], type: "Minor", suit: "Water", number: 8 }, | |
{ name: "Nine of Water", baseName: "Nafanua", description: "Empowers emotional strength", quotes: ["Inspires warrior heart", "Honors emotional courage", "Watery fierce spirit"], type: "Minor", suit: "Water", number: 9 }, | |
{ name: "Ten of Water", baseName: "Lailah", description: "Guards emotional dreams", quotes: ["Protects nightly visions", "Nurtures soul’s dreams", "Watery dreamy grace"], type: "Minor", suit: "Water", number: 10 }, | |
{ name: "Page of Water", baseName: "Aos Sí", description: "Explores emotional realms", quotes: ["Guides heart’s paths", "Honors emotional truth", "Watery mystical spirit"], type: "Minor", suit: "Water", number: 11 }, | |
{ name: "Knight of Water", baseName: "Gandharvas", description: "Pursues emotional harmony", quotes: ["Sings soul’s music", "Shares emotional beauty", "Watery melodic grace"], type: "Minor", suit: "Water", number: 12 }, | |
{ name: "Queen of Water", baseName: "Ngen", description: "Rules emotional nature", quotes: ["Protects watery realms", "Guides with care", "Watery nurturing spirit"], type: "Minor", suit: "Water", number: 13 }, | |
{ name: "King of Water", baseName: "Vishnu", description: "Masters emotional preservation", quotes: ["Preserves cosmic balance", "Protects with love", "Watery divine grace"], type: "Minor", suit: "Water", number: 14 }, | |
{ name: "Ace of Earth", baseName: "Ariel", description: "Grounds with nature’s balance", quotes: ["Protects earth’s harmony", "Honors natural balance", "Earthy environmental wisdom"], type: "Minor", suit: "Earth", number: 1 }, | |
{ name: "Two of Earth", baseName: "Sandalphon", description: "Anchors prayers to earth", quotes: ["Carries grounded prayers", "Harmonizes earthly rhythms", "Earthy musical spirit"], type: "Minor", suit: "Earth", number: 2 }, | |
{ name: "Three of Earth", baseName: "Cassiel", description: "Stabilizes with discipline", quotes: ["Guides steady resolve", "Upholds patient duty", "Earthy disciplined strength"], type: "Minor", suit: "Earth", number: 3 }, | |
{ name: "Four of Earth", baseName: "Tzadkiel", description: "Roots in righteousness", quotes: ["Upholds divine justice", "Honors righteous path", "Earthy moral strength"], type: "Minor", suit: "Earth", number: 4 }, | |
{ name: "Five of Earth", baseName: "Kāne", description: "Creates earthly life", quotes: ["Fosters life’s growth", "Nurtures earthly creation", "Earthy generative spirit"], type: "Minor", suit: "Earth", number: 5 }, | |
{ name: "Six of Earth", baseName: "Viracocha", description: "Builds cosmic foundations", quotes: ["Shapes earthly order", "Honors cosmic stability", "Earthy divine structure"], type: "Minor", suit: "Earth", number: 6 }, | |
{ name: "Seven of Earth", baseName: "Inti", description: "Radiates earthly vitality", quotes: ["Illuminates earthly life", "Honors solar truth", "Earthy radiant spirit"], type: "Minor", suit: "Earth", number: 7 }, | |
{ name: "Eight of Earth", baseName: "Kakunupmawa", description: "Anchors solar stability", quotes: ["Guides earthly cycles", "Honors solar balance", "Earthy solar wisdom"], type: "Minor", suit: "Earth", number: 8 }, | |
{ name: "Nine of Earth", baseName: "Breath Maker", description: "Grounds spiritual essence", quotes: ["Breathes life’s spirit", "Nurtures earthly soul", "Earthy vital spirit"], type: "Minor", suit: "Earth", number: 9 }, | |
{ name: "Ten of Earth", baseName: "Shen", description: "Protects earthly realms", quotes: ["Guards natural order", "Honors earthly harmony", "Earthy protective spirit"], type: "Minor", suit: "Earth", number: 10 }, | |
{ name: "Page of Earth", baseName: "Disir", description: "Explores earthly paths", quotes: ["Guides ancestral ways", "Honors earthy roots", "Earthy ancestral wisdom"], type: "Minor", suit: "Earth", number: 11 }, | |
{ name: "Knight of Earth", baseName: "Coyote", description: "Pursues earthly cunning", quotes: ["Navigates earthy tricks", "Values clever survival", "Earthy cunning spirit"], type: "Minor", suit: "Earth", number: 12 }, | |
{ name: "Queen of Earth", baseName: "Corn Mother", description: "Nurtures earthly sustenance", quotes: ["Provides life’s bounty", "Nurtures earthy growth", "Earthy fertile grace"], type: "Minor", suit: "Earth", number: 13 }, | |
{ name: "King of Earth", baseName: "Tagaloa", description: "Masters earthly creation", quotes: ["Shapes cosmic earth", "Rules with stability", "Earthy divine order"], type: "Minor", suit: "Earth", number: 14 } | |
]; | |
// Canvas setup | |
const canvas = document.getElementById('canvas'); | |
const ctx = canvas.getContext('2d'); | |
const container = document.getElementById('canvas-container'); | |
canvas.width = container.clientWidth; | |
canvas.height = container.clientHeight; | |
// Scroll variables | |
let scrollY = 0; | |
const cardHeight = 120; | |
const cardWidth = canvas.width - 20; | |
const cardSpacing = 10; | |
let selectedCard = null; | |
// Generate SVG for a card | |
function generateSVG(card) { | |
const bgColor = card.type === "Major" ? "#FFD700" : (card.suit === "Fire" ? "#FF4500" : card.suit === "Air" ? "#87CEEB" : card.suit === "Water" ? "#1E90FF" : "#228B22"); | |
const name = card.name.replace(/"/g, '"'); // Escape quotes | |
const halfCircle = card.type === "Major" ? ` | |
<path d="M50 30 A50 50 0 0 1 150 30 L150 0 L50 0 Z" fill="#000" stroke="#FFF" stroke-width="1"/> | |
<text x="100" y="25" font-family="Arial" font-size="14" font-weight="bold" text-anchor="middle" fill="#FFF">${card.number}</text> | |
` : ''; | |
return ` | |
<svg width="200" height="300" xmlns="http://www.w3.org/2000/svg"> | |
<rect x="0" y="0" width="200" height="300" fill="${bgColor}" stroke="#000" stroke-width="2"/> | |
<rect x="10" y="30" width="180" height="260" fill="#FFF" stroke="#000" stroke-width="1"/> | |
${halfCircle} | |
<text x="100" y="60" font-family="Arial" font-size="16" font-weight="bold" text-anchor="middle">${name}</text> | |
<text x="100" y="90" font-family="Arial" font-size="12" text-anchor="middle">${card.description}</text> | |
<text x="100" y="130" font-family="Arial" font-size="10" text-anchor="middle">Merits: ${card.quotes[0]}</text> | |
<text x="100" y="150" font-family="Arial" font-size="10" text-anchor="middle">Morals: ${card.quotes[1]}</text> | |
<text x="100" y="170" font-family="Arial" font-size="10" text-anchor="middle">Virtues: ${card.quotes[2]}</text> | |
${card.suit ? `<text x="100" y="200" font-family="Arial" font-size="12" text-anchor="middle">Suit: ${card.suit}</text>` : ''} | |
</svg>`; | |
} | |
// Update sidebar with selected card | |
function updateSidebar(card) { | |
if (!card) { | |
document.getElementById('svg-preview').innerHTML = ''; | |
document.getElementById('download-link').style.display = 'none'; | |
document.getElementById('card-details').textContent = 'Select a card to view details.'; | |
return; | |
} | |
const svg = generateSVG(card); | |
document.getElementById('svg-preview').innerHTML = svg; | |
const blob = new Blob([svg], { type: 'image/svg+xml' }); | |
const url = URL.createObjectURL(blob); | |
const downloadLink = document.getElementById('download-link'); | |
downloadLink.href = url; | |
downloadLink.download = `${card.name.replace(/\s+/g, '_')}.svg`; | |
downloadLink.style.display = 'block'; | |
document.getElementById('card-details').innerHTML = ` | |
<strong>Name:</strong> ${card.name}<br> | |
<strong>Base Name:</strong> ${card.baseName}<br> | |
<strong>Description:</strong> ${card.description}<br> | |
<strong>Merits:</strong> ${card.quotes[0]}<br> | |
<strong>Morals:</strong> ${card.quotes[1]}<br> | |
<strong>Virtues:</strong> ${card.quotes[2]}<br> | |
${card.suit ? `<strong>Suit:</strong> ${card.suit}` : ''} | |
`; | |
} | |
// Draw cards on canvas | |
function drawCards() { | |
ctx.fillStyle = '#222'; | |
ctx.fillRect(0, 0, canvas.width, canvas.height); | |
cards.forEach((card, index) => { | |
const y = index * (cardHeight + cardSpacing) - scrollY; | |
if (y + cardHeight < 0 || y > canvas.height) return; // Skip off-screen cards | |
// Draw card background | |
ctx.fillStyle = card.type === "Major" ? '#FFD700' : (card.suit === "Fire" ? '#FF4500' : card.suit === "Air" ? '#87CEEB' : card.suit === "Water" ? '#1E90FF' : '#228B22'); | |
ctx.fillRect(10, y, cardWidth, cardHeight); | |
ctx.strokeStyle = '#000'; | |
ctx.strokeRect(10, y, cardWidth, cardHeight); | |
// Draw half-circle for Major Arcana | |
if (card.type === "Major") { | |
ctx.beginPath(); | |
ctx.arc(canvas.width / 2, y + 15, 20, Math.PI, 0); // Half-circle | |
ctx.lineTo(canvas.width / 2 + 20, y); | |
ctx.lineTo(canvas.width / 2 - 20, y); | |
ctx.closePath(); | |
ctx.fillStyle = '#000'; | |
ctx.fill(); | |
ctx.strokeStyle = '#FFF'; | |
ctx.stroke(); | |
ctx.fillStyle = '#FFF'; | |
ctx.font = '12px Arial'; | |
ctx.textAlign = 'center'; | |
ctx.fillText(card.number, canvas.width / 2, y + 20); | |
} | |
// Draw card text | |
ctx.fillStyle = '#000'; | |
ctx.font = 'bold 16px Arial'; | |
ctx.textAlign = 'left'; | |
ctx.fillText(card.name, 20, y + 40); | |
ctx.font = '12px Arial'; | |
ctx.fillText(card.description, 20, y + 60); | |
ctx.fillText(`Merits: ${card.quotes[0]}`, 20, y + 80); | |
ctx.fillText(`Morals: ${card.quotes[1]}`, 20, y + 100); | |
if (card.suit) { | |
ctx.fillText(`Suit: ${card.suit}`, 20, y + 120); | |
} | |
}); | |
} | |
// Scroll handling | |
let isDragging = false; | |
let startY = 0; | |
canvas.addEventListener('mousedown', (e) => { | |
isDragging = true; | |
startY = e.clientY; | |
}); | |
canvas.addEventListener('mousemove', (e) => { | |
if (isDragging) { | |
const deltaY = startY - e.clientY; | |
scrollY = Math.max(0, Math.min(scrollY + deltaY, cards.length * (cardHeight + cardSpacing) - canvas.height)); | |
startY = e.clientY; | |
drawCards(); | |
} | |
}); | |
canvas.addEventListener('mouseup', () => { | |
isDragging = false; | |
}); | |
canvas.addEventListener('wheel', (e) => { | |
scrollY = Math.max(0, Math.min(scrollY + e.deltaY, cards.length * (cardHeight + cardSpacing) - canvas.height)); | |
drawCards(); | |
}); | |
// Click to select card | |
canvas.addEventListener('click', (e) => { | |
const rect = canvas.getBoundingClientRect(); | |
const y = e.clientY - rect.top + scrollY; | |
const index = Math.floor(y / (cardHeight + cardSpacing)); | |
if (index >= 0 && index < cards.length) { | |
selectedCard = cards[index]; | |
updateSidebar(selectedCard); | |
} | |
}); | |
// Initial draw | |
drawCards(); | |
updateSidebar(null); | |
// Handle window resize | |
window.addEventListener('resize', () => { | |
canvas.width = container.clientWidth; | |
canvas.height = container.clientHeight; | |
drawCards(); | |
}); | |
</script> | |
</body> | |
</html> |