User prompt
make it when ever the same item collides with another of the same item it upgrades āŖš” Consider importing and using the following plugins: @upit/tween.v1
User prompt
make the stone/wood spawn every 2 seconds
User prompt
make the stone/wood spawn every .5 seconds
User prompt
make grid 6x8
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'to')' in or related to this line: 'tween(self).to({' Line Number: 59 āŖš” Consider importing and using the following plugins: @upit/tween.v1
User prompt
make the dag n drop feters better
User prompt
make only stone and wood spawn randomely
User prompt
make a all new items apear on any grid cells
User prompt
make the grid 12x12
User prompt
make the items apear on a 3x3 grid
User prompt
its not working
Code edit (1 edits merged)
Please save this source code
User prompt
Fanatic Craft
Initial prompt
ifanate craft
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var CraftItem = Container.expand(function (itemType) { var self = Container.call(this); self.itemType = itemType; self.gridX = -1; self.gridY = -1; self.isDragging = false; self.startX = 0; self.startY = 0; // Create visual representation var itemGraphics = self.attachAsset(itemType, { anchorX: 0.5, anchorY: 0.5 }); // Add item type text var itemText = new Text2(getItemDisplayName(itemType), { size: 16, fill: 0xFFFFFF }); itemText.anchor.set(0.5, 0.5); itemText.y = 50; self.addChild(itemText); self.down = function (x, y, obj) { self.startX = self.x; self.startY = self.y; self.startGridX = self.gridX; self.startGridY = self.gridY; if (self.gridX !== -1 && self.gridY !== -1) { // Remove from grid grid[self.gridY][self.gridX] = null; } self.isDragging = true; // Bring to front and add visual feedback self.parent.addChild(self); tween(self, { scaleX: 1.1, scaleY: 1.1, alpha: 0.8 }, { duration: 200 }); }; return self; }); var GridCell = Container.expand(function (gridX, gridY) { var self = Container.call(this); self.gridX = gridX; self.gridY = gridY; var cellGraphics = self.attachAsset('grid_cell', { anchorX: 0.5, anchorY: 0.5 }); cellGraphics.alpha = 0.3; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a1a }); /**** * Game Code ****/ // Sounds // Grid cell // Magical artifacts // Advanced items // Tools // Basic materials // Game constants var GRID_WIDTH = 6; var GRID_HEIGHT = 8; var CELL_SIZE = 85; var GRID_START_X = 2048 / 2 - GRID_WIDTH * CELL_SIZE / 2; var GRID_START_Y = 600; // Game state var grid = []; var items = []; var draggedItem = null; var score = 0; // Crafting recipes var recipes = { 'wood': 'stick', 'stick': 'axe', 'stone': 'iron', 'iron': 'pickaxe', 'axe': 'sword', 'pickaxe': 'shield', 'sword': 'crystal', 'shield': 'crystal', 'crystal': 'enchanted_sword' }; // Item values var itemValues = { 'wood': 1, 'stone': 1, 'stick': 3, 'iron': 3, 'axe': 10, 'pickaxe': 10, 'sword': 25, 'shield': 25, 'crystal': 50, 'enchanted_sword': 100 }; // Initialize grid for (var y = 0; y < GRID_HEIGHT; y++) { grid[y] = []; for (var x = 0; x < GRID_WIDTH; x++) { grid[y][x] = null; // Create visual grid cell var cell = new GridCell(x, y); cell.x = GRID_START_X + x * CELL_SIZE; cell.y = GRID_START_Y + y * CELL_SIZE; game.addChild(cell); } } // Score display var scoreTxt = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Instructions var instructionTxt = new Text2('Drag identical items together to combine them!', { size: 40, fill: 0xFFFF00 }); instructionTxt.anchor.set(0.5, 0); instructionTxt.y = 100; game.addChild(instructionTxt); function getItemDisplayName(itemType) { var names = { 'wood': 'Wood', 'stone': 'Stone', 'stick': 'Stick', 'iron': 'Iron', 'axe': 'Axe', 'pickaxe': 'Pick', 'sword': 'Sword', 'shield': 'Shield', 'crystal': 'Crystal', 'enchanted_sword': 'Magic' }; return names[itemType] || itemType; } function getGridPosition(x, y) { var gridX = Math.floor((x - GRID_START_X + CELL_SIZE / 2) / CELL_SIZE); var gridY = Math.floor((y - GRID_START_Y + CELL_SIZE / 2) / CELL_SIZE); if (gridX >= 0 && gridX < GRID_WIDTH && gridY >= 0 && gridY < GRID_HEIGHT) { return { x: gridX, y: gridY }; } return null; } function isValidGridPosition(gridX, gridY) { return gridX >= 0 && gridX < GRID_WIDTH && gridY >= 0 && gridY < GRID_HEIGHT; } function placeItemInGrid(item, gridX, gridY) { if (!isValidGridPosition(gridX, gridY) || grid[gridY][gridX] !== null) { return false; } grid[gridY][gridX] = item; item.gridX = gridX; item.gridY = gridY; item.x = GRID_START_X + gridX * CELL_SIZE + CELL_SIZE / 2; item.y = GRID_START_Y + gridY * CELL_SIZE + CELL_SIZE / 2; return true; } function findEmptyGridSlot() { for (var y = 0; y < GRID_HEIGHT; y++) { for (var x = 0; x < GRID_WIDTH; x++) { if (grid[y][x] === null) { return { x: x, y: y }; } } } return null; } function spawnRandomItem() { var itemTypes = ['wood', 'stone']; var randomType = itemTypes[Math.floor(Math.random() * itemTypes.length)]; var emptySlot = findEmptyGridSlot(); if (emptySlot) { var newItem = new CraftItem(randomType); game.addChild(newItem); items.push(newItem); placeItemInGrid(newItem, emptySlot.x, emptySlot.y); LK.getSound('place').play(); } } function checkForCombinations(item) { if (item.gridX === -1 || item.gridY === -1) return false; var itemType = item.itemType; var gridX = item.gridX; var gridY = item.gridY; // Check adjacent cells for same item type var directions = [{ dx: 0, dy: -1 }, // up { dx: 1, dy: 0 }, // right { dx: 0, dy: 1 }, // down { dx: -1, dy: 0 } // left ]; for (var i = 0; i < directions.length; i++) { var dir = directions[i]; var checkX = gridX + dir.dx; var checkY = gridY + dir.dy; if (isValidGridPosition(checkX, checkY) && grid[checkY][checkX]) { var otherItem = grid[checkY][checkX]; if (otherItem.itemType === itemType && recipes[itemType]) { // Combine items var newItemType = recipes[itemType]; // Remove both items grid[gridY][gridX] = null; grid[checkY][checkX] = null; // Remove from items array var itemIndex = items.indexOf(item); if (itemIndex !== -1) items.splice(itemIndex, 1); var otherIndex = items.indexOf(otherItem); if (otherIndex !== -1) items.splice(otherIndex, 1); // Destroy old items item.destroy(); otherItem.destroy(); // Create new item var newItem = new CraftItem(newItemType); game.addChild(newItem); items.push(newItem); placeItemInGrid(newItem, gridX, gridY); // Update score score += itemValues[newItemType] || 1; scoreTxt.setText('Score: ' + score); // Play sound LK.getSound('combine').play(); // Flash effect LK.effects.flashObject(newItem, 0x00ff00, 500); return true; } } } return false; } // Spawn initial items for (var i = 0; i < 4; i++) { spawnRandomItem(); } // Game event handlers var dragOffsetX = 0; var dragOffsetY = 0; game.move = function (x, y, obj) { if (draggedItem) { draggedItem.x = x - dragOffsetX; draggedItem.y = y - dragOffsetY; } }; game.down = function (x, y, obj) { // Find if we clicked on an item for (var i = items.length - 1; i >= 0; i--) { var item = items[i]; // Check if click is within item bounds (using center-anchored 60x60 items) var itemLeft = item.x - 35; var itemRight = item.x + 35; var itemTop = item.y - 35; var itemBottom = item.y + 35; if (x >= itemLeft && x <= itemRight && y >= itemTop && y <= itemBottom) { draggedItem = item; // Calculate offset for smooth dragging dragOffsetX = x - item.x; dragOffsetY = y - item.y; item.down(x, y, obj); break; } } }; game.up = function (x, y, obj) { if (draggedItem) { // Reset visual feedback tween(draggedItem, { scaleX: 1, scaleY: 1, alpha: 1 }, { duration: 200 }); var adjustedX = x - dragOffsetX; var adjustedY = y - dragOffsetY; var gridPos = getGridPosition(adjustedX, adjustedY); var placed = false; if (gridPos && grid[gridPos.y][gridPos.x] === null) { // Place in grid with smooth animation placed = placeItemInGrid(draggedItem, gridPos.x, gridPos.y); if (placed) { // Smooth placement animation tween(draggedItem, { x: GRID_START_X + gridPos.x * CELL_SIZE + CELL_SIZE / 2, y: GRID_START_Y + gridPos.y * CELL_SIZE + CELL_SIZE / 2 }, { duration: 150 }); // Check for combinations checkForCombinations(draggedItem); LK.getSound('place').play(); } } else if (gridPos && grid[gridPos.y][gridPos.x] !== null) { // Check if dropping on same item type for instant upgrade var targetItem = grid[gridPos.y][gridPos.x]; if (targetItem.itemType === draggedItem.itemType && recipes[draggedItem.itemType]) { // Combine items instantly var newItemType = recipes[draggedItem.itemType]; // Remove target item from grid grid[gridPos.y][gridPos.x] = null; // Remove both items from items array var draggedIndex = items.indexOf(draggedItem); if (draggedIndex !== -1) items.splice(draggedIndex, 1); var targetIndex = items.indexOf(targetItem); if (targetIndex !== -1) items.splice(targetIndex, 1); // Destroy old items draggedItem.destroy(); targetItem.destroy(); // Create new upgraded item var newItem = new CraftItem(newItemType); game.addChild(newItem); items.push(newItem); placeItemInGrid(newItem, gridPos.x, gridPos.y); // Update score score += itemValues[newItemType] || 1; scoreTxt.setText('Score: ' + score); // Play sound and visual effects LK.getSound('combine').play(); LK.effects.flashObject(newItem, 0x00ff00, 500); placed = true; } } if (!placed) { // Return to original position or find empty slot if (draggedItem.startGridX !== -1 && draggedItem.startGridY !== -1 && grid[draggedItem.startGridY][draggedItem.startGridX] === null) { // Return to original grid position placeItemInGrid(draggedItem, draggedItem.startGridX, draggedItem.startGridY); tween(draggedItem, { x: draggedItem.startX, y: draggedItem.startY }, { duration: 300 }); } else { // Find new empty slot var emptySlot = findEmptyGridSlot(); if (emptySlot) { placeItemInGrid(draggedItem, emptySlot.x, emptySlot.y); tween(draggedItem, { x: GRID_START_X + emptySlot.x * CELL_SIZE + CELL_SIZE / 2, y: GRID_START_Y + emptySlot.y * CELL_SIZE + CELL_SIZE / 2 }, { duration: 300 }); } else { // Return to start position tween(draggedItem, { x: draggedItem.startX, y: draggedItem.startY }, { duration: 300 }); } } } draggedItem.isDragging = false; draggedItem = null; dragOffsetX = 0; dragOffsetY = 0; } }; // Spawn timer var spawnTimer = 0; var spawnInterval = 120; // 2 seconds at 60fps game.update = function () { spawnTimer++; if (spawnTimer >= spawnInterval) { spawnRandomItem(); spawnTimer = 0; // Gradually increase spawn rate if (spawnInterval > 120) { spawnInterval--; } } // Check for game over (grid full) var gridFull = true; for (var y = 0; y < GRID_HEIGHT && gridFull; y++) { for (var x = 0; x < GRID_WIDTH && gridFull; x++) { if (grid[y][x] === null) { gridFull = false; } } } if (gridFull) { LK.showGameOver(); } // Win condition - score threshold if (score >= 1000) { LK.showYouWin(); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var CraftItem = Container.expand(function (itemType) {
var self = Container.call(this);
self.itemType = itemType;
self.gridX = -1;
self.gridY = -1;
self.isDragging = false;
self.startX = 0;
self.startY = 0;
// Create visual representation
var itemGraphics = self.attachAsset(itemType, {
anchorX: 0.5,
anchorY: 0.5
});
// Add item type text
var itemText = new Text2(getItemDisplayName(itemType), {
size: 16,
fill: 0xFFFFFF
});
itemText.anchor.set(0.5, 0.5);
itemText.y = 50;
self.addChild(itemText);
self.down = function (x, y, obj) {
self.startX = self.x;
self.startY = self.y;
self.startGridX = self.gridX;
self.startGridY = self.gridY;
if (self.gridX !== -1 && self.gridY !== -1) {
// Remove from grid
grid[self.gridY][self.gridX] = null;
}
self.isDragging = true;
// Bring to front and add visual feedback
self.parent.addChild(self);
tween(self, {
scaleX: 1.1,
scaleY: 1.1,
alpha: 0.8
}, {
duration: 200
});
};
return self;
});
var GridCell = Container.expand(function (gridX, gridY) {
var self = Container.call(this);
self.gridX = gridX;
self.gridY = gridY;
var cellGraphics = self.attachAsset('grid_cell', {
anchorX: 0.5,
anchorY: 0.5
});
cellGraphics.alpha = 0.3;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a1a
});
/****
* Game Code
****/
// Sounds
// Grid cell
// Magical artifacts
// Advanced items
// Tools
// Basic materials
// Game constants
var GRID_WIDTH = 6;
var GRID_HEIGHT = 8;
var CELL_SIZE = 85;
var GRID_START_X = 2048 / 2 - GRID_WIDTH * CELL_SIZE / 2;
var GRID_START_Y = 600;
// Game state
var grid = [];
var items = [];
var draggedItem = null;
var score = 0;
// Crafting recipes
var recipes = {
'wood': 'stick',
'stick': 'axe',
'stone': 'iron',
'iron': 'pickaxe',
'axe': 'sword',
'pickaxe': 'shield',
'sword': 'crystal',
'shield': 'crystal',
'crystal': 'enchanted_sword'
};
// Item values
var itemValues = {
'wood': 1,
'stone': 1,
'stick': 3,
'iron': 3,
'axe': 10,
'pickaxe': 10,
'sword': 25,
'shield': 25,
'crystal': 50,
'enchanted_sword': 100
};
// Initialize grid
for (var y = 0; y < GRID_HEIGHT; y++) {
grid[y] = [];
for (var x = 0; x < GRID_WIDTH; x++) {
grid[y][x] = null;
// Create visual grid cell
var cell = new GridCell(x, y);
cell.x = GRID_START_X + x * CELL_SIZE;
cell.y = GRID_START_Y + y * CELL_SIZE;
game.addChild(cell);
}
}
// Score display
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Instructions
var instructionTxt = new Text2('Drag identical items together to combine them!', {
size: 40,
fill: 0xFFFF00
});
instructionTxt.anchor.set(0.5, 0);
instructionTxt.y = 100;
game.addChild(instructionTxt);
function getItemDisplayName(itemType) {
var names = {
'wood': 'Wood',
'stone': 'Stone',
'stick': 'Stick',
'iron': 'Iron',
'axe': 'Axe',
'pickaxe': 'Pick',
'sword': 'Sword',
'shield': 'Shield',
'crystal': 'Crystal',
'enchanted_sword': 'Magic'
};
return names[itemType] || itemType;
}
function getGridPosition(x, y) {
var gridX = Math.floor((x - GRID_START_X + CELL_SIZE / 2) / CELL_SIZE);
var gridY = Math.floor((y - GRID_START_Y + CELL_SIZE / 2) / CELL_SIZE);
if (gridX >= 0 && gridX < GRID_WIDTH && gridY >= 0 && gridY < GRID_HEIGHT) {
return {
x: gridX,
y: gridY
};
}
return null;
}
function isValidGridPosition(gridX, gridY) {
return gridX >= 0 && gridX < GRID_WIDTH && gridY >= 0 && gridY < GRID_HEIGHT;
}
function placeItemInGrid(item, gridX, gridY) {
if (!isValidGridPosition(gridX, gridY) || grid[gridY][gridX] !== null) {
return false;
}
grid[gridY][gridX] = item;
item.gridX = gridX;
item.gridY = gridY;
item.x = GRID_START_X + gridX * CELL_SIZE + CELL_SIZE / 2;
item.y = GRID_START_Y + gridY * CELL_SIZE + CELL_SIZE / 2;
return true;
}
function findEmptyGridSlot() {
for (var y = 0; y < GRID_HEIGHT; y++) {
for (var x = 0; x < GRID_WIDTH; x++) {
if (grid[y][x] === null) {
return {
x: x,
y: y
};
}
}
}
return null;
}
function spawnRandomItem() {
var itemTypes = ['wood', 'stone'];
var randomType = itemTypes[Math.floor(Math.random() * itemTypes.length)];
var emptySlot = findEmptyGridSlot();
if (emptySlot) {
var newItem = new CraftItem(randomType);
game.addChild(newItem);
items.push(newItem);
placeItemInGrid(newItem, emptySlot.x, emptySlot.y);
LK.getSound('place').play();
}
}
function checkForCombinations(item) {
if (item.gridX === -1 || item.gridY === -1) return false;
var itemType = item.itemType;
var gridX = item.gridX;
var gridY = item.gridY;
// Check adjacent cells for same item type
var directions = [{
dx: 0,
dy: -1
},
// up
{
dx: 1,
dy: 0
},
// right
{
dx: 0,
dy: 1
},
// down
{
dx: -1,
dy: 0
} // left
];
for (var i = 0; i < directions.length; i++) {
var dir = directions[i];
var checkX = gridX + dir.dx;
var checkY = gridY + dir.dy;
if (isValidGridPosition(checkX, checkY) && grid[checkY][checkX]) {
var otherItem = grid[checkY][checkX];
if (otherItem.itemType === itemType && recipes[itemType]) {
// Combine items
var newItemType = recipes[itemType];
// Remove both items
grid[gridY][gridX] = null;
grid[checkY][checkX] = null;
// Remove from items array
var itemIndex = items.indexOf(item);
if (itemIndex !== -1) items.splice(itemIndex, 1);
var otherIndex = items.indexOf(otherItem);
if (otherIndex !== -1) items.splice(otherIndex, 1);
// Destroy old items
item.destroy();
otherItem.destroy();
// Create new item
var newItem = new CraftItem(newItemType);
game.addChild(newItem);
items.push(newItem);
placeItemInGrid(newItem, gridX, gridY);
// Update score
score += itemValues[newItemType] || 1;
scoreTxt.setText('Score: ' + score);
// Play sound
LK.getSound('combine').play();
// Flash effect
LK.effects.flashObject(newItem, 0x00ff00, 500);
return true;
}
}
}
return false;
}
// Spawn initial items
for (var i = 0; i < 4; i++) {
spawnRandomItem();
}
// Game event handlers
var dragOffsetX = 0;
var dragOffsetY = 0;
game.move = function (x, y, obj) {
if (draggedItem) {
draggedItem.x = x - dragOffsetX;
draggedItem.y = y - dragOffsetY;
}
};
game.down = function (x, y, obj) {
// Find if we clicked on an item
for (var i = items.length - 1; i >= 0; i--) {
var item = items[i];
// Check if click is within item bounds (using center-anchored 60x60 items)
var itemLeft = item.x - 35;
var itemRight = item.x + 35;
var itemTop = item.y - 35;
var itemBottom = item.y + 35;
if (x >= itemLeft && x <= itemRight && y >= itemTop && y <= itemBottom) {
draggedItem = item;
// Calculate offset for smooth dragging
dragOffsetX = x - item.x;
dragOffsetY = y - item.y;
item.down(x, y, obj);
break;
}
}
};
game.up = function (x, y, obj) {
if (draggedItem) {
// Reset visual feedback
tween(draggedItem, {
scaleX: 1,
scaleY: 1,
alpha: 1
}, {
duration: 200
});
var adjustedX = x - dragOffsetX;
var adjustedY = y - dragOffsetY;
var gridPos = getGridPosition(adjustedX, adjustedY);
var placed = false;
if (gridPos && grid[gridPos.y][gridPos.x] === null) {
// Place in grid with smooth animation
placed = placeItemInGrid(draggedItem, gridPos.x, gridPos.y);
if (placed) {
// Smooth placement animation
tween(draggedItem, {
x: GRID_START_X + gridPos.x * CELL_SIZE + CELL_SIZE / 2,
y: GRID_START_Y + gridPos.y * CELL_SIZE + CELL_SIZE / 2
}, {
duration: 150
});
// Check for combinations
checkForCombinations(draggedItem);
LK.getSound('place').play();
}
} else if (gridPos && grid[gridPos.y][gridPos.x] !== null) {
// Check if dropping on same item type for instant upgrade
var targetItem = grid[gridPos.y][gridPos.x];
if (targetItem.itemType === draggedItem.itemType && recipes[draggedItem.itemType]) {
// Combine items instantly
var newItemType = recipes[draggedItem.itemType];
// Remove target item from grid
grid[gridPos.y][gridPos.x] = null;
// Remove both items from items array
var draggedIndex = items.indexOf(draggedItem);
if (draggedIndex !== -1) items.splice(draggedIndex, 1);
var targetIndex = items.indexOf(targetItem);
if (targetIndex !== -1) items.splice(targetIndex, 1);
// Destroy old items
draggedItem.destroy();
targetItem.destroy();
// Create new upgraded item
var newItem = new CraftItem(newItemType);
game.addChild(newItem);
items.push(newItem);
placeItemInGrid(newItem, gridPos.x, gridPos.y);
// Update score
score += itemValues[newItemType] || 1;
scoreTxt.setText('Score: ' + score);
// Play sound and visual effects
LK.getSound('combine').play();
LK.effects.flashObject(newItem, 0x00ff00, 500);
placed = true;
}
}
if (!placed) {
// Return to original position or find empty slot
if (draggedItem.startGridX !== -1 && draggedItem.startGridY !== -1 && grid[draggedItem.startGridY][draggedItem.startGridX] === null) {
// Return to original grid position
placeItemInGrid(draggedItem, draggedItem.startGridX, draggedItem.startGridY);
tween(draggedItem, {
x: draggedItem.startX,
y: draggedItem.startY
}, {
duration: 300
});
} else {
// Find new empty slot
var emptySlot = findEmptyGridSlot();
if (emptySlot) {
placeItemInGrid(draggedItem, emptySlot.x, emptySlot.y);
tween(draggedItem, {
x: GRID_START_X + emptySlot.x * CELL_SIZE + CELL_SIZE / 2,
y: GRID_START_Y + emptySlot.y * CELL_SIZE + CELL_SIZE / 2
}, {
duration: 300
});
} else {
// Return to start position
tween(draggedItem, {
x: draggedItem.startX,
y: draggedItem.startY
}, {
duration: 300
});
}
}
}
draggedItem.isDragging = false;
draggedItem = null;
dragOffsetX = 0;
dragOffsetY = 0;
}
};
// Spawn timer
var spawnTimer = 0;
var spawnInterval = 120; // 2 seconds at 60fps
game.update = function () {
spawnTimer++;
if (spawnTimer >= spawnInterval) {
spawnRandomItem();
spawnTimer = 0;
// Gradually increase spawn rate
if (spawnInterval > 120) {
spawnInterval--;
}
}
// Check for game over (grid full)
var gridFull = true;
for (var y = 0; y < GRID_HEIGHT && gridFull; y++) {
for (var x = 0; x < GRID_WIDTH && gridFull; x++) {
if (grid[y][x] === null) {
gridFull = false;
}
}
}
if (gridFull) {
LK.showGameOver();
}
// Win condition - score threshold
if (score >= 1000) {
LK.showYouWin();
}
};
iron ingot. In-Game asset. 2d. High contrast. No shadows
christal. In-Game asset. 2d. High contrast. No shadows
sheild. In-Game asset. 2d. High contrast. No shadows
pickaxe. In-Game asset. 2d. High contrast. No shadows
stone. In-Game asset. 2d. High contrast. No shadows
netherite sword. In-Game asset. 2d. High contrast. No shadows