Code edit (1 edits merged)
Please save this source code
Code edit (5 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: groundLevel is not defined' in or related to this line: 't.y = groundLevel + 20;' Line Number: 739
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (11 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'width')' in or related to this line: 'barricade.x = 2048 + spikeTrap.width;' Line Number: 454
Code edit (1 edits merged)
Please save this source code
User prompt
give all text a black outline
User prompt
the +10 signs should fly off to the left side of the screen and be destroyed after a few seconds
User prompt
show a +10 sign and play a sound effect when player picks up a collectible
User prompt
Increase score by 10 when player picks up a collectible
User prompt
add a scorelabel top center of the scree
Code edit (12 edits merged)
Please save this source code
User prompt
make a class for the dustparticle and use its update method instead of running the spread and alpha in an interval
User prompt
the dust particles should spread and go transparent before they disappear
User prompt
use a separate dustparticle asset for the dustparticles
User prompt
Please fix the bug: 'Timeout.tick error: Cannot read properties of undefined (reading 'destroy')' in or related to this line: 'particle.destroy();' Line Number: 169
User prompt
the dustparticle effect should be a small aprticle explosion looking like dust that rises from the ground on jump takeoff and landing
User prompt
make a dustparticle effect when player jumps and lands
Code edit (1 edits merged)
Please save this source code
/**** * Classes ****/ /*** TODO: - Feature creep ideas: the occassional treasure chest on the ground or animal. - Music - Sound effects - Title, description, hashtags, icon and banner image. Måske Endless Dwarven Run i stedet for Viking. */ var ArrowVolley = Container.expand(function () { var self = Container.call(this); //var assetTypes = ['snacks', 'snacks2', 'snacks3', 'snacks4', 'snacks5', 'snacks6', 'snacks7']; //var randomAsset = assetTypes[Math.floor(Math.random() * assetTypes.length)]; for (var i = 0; i < 5; i++) { for (var j = 0; j < 17; j++) { var t = self.attachAsset('arrow', { anchorX: 0.5, anchorY: 0.5, x: i * 250, y: j * 123 }); } } self.speed = 5; self.dead = false; self.passed = false; self.update = function () { // update logic if needed }; }); var BrokenPallisade = Container.expand(function (x, y) { var self = Container.call(this); self.speed = 2 + Math.random() * 2; var ran = Math.ceil(Math.random() * 2); var t = self.attachAsset('brokenPallisade' + ran, { anchorX: 0.5, anchorY: 0.5 }); self.x = Math.random() * 200 - 50 + x; self.y = Math.random() * 1000 - 500 + y; self.rotation = Math.PI * 4 * Math.random(); self.rotationStep = Math.random() * 0.08 - 0.04; self.update = function () { self.rotation += self.rotationStep; self.y += 32; self.x += gameSpeed / 2; if (self.y > 3600) { self.destroy(); } }; }); var Collectible = Container.expand(function () { var self = Container.call(this); var assetTypes = ['snacks', 'snacks2', 'snacks3', 'snacks4', 'snacks5', 'snacks6', 'snacks7']; var rewards = [10, 25, 50, 100, 250, 500, 1000]; self.rand = Math.floor(Math.random() * assetTypes.length); var randomAsset = assetTypes[self.rand]; var collectibleGraphics = self.attachAsset(randomAsset, { anchorX: 0.5, anchorY: 0.5 }); self.scoreVal = rewards[self.rand]; self.speed = 2 + Math.random() * 2; self.update = function () { // Collectible update logic if needed }; }); var DustParticle = Container.expand(function () { var self = Container.call(this); var dustParticleGraphics = self.attachAsset('dustParticle', { anchorX: 0.5, anchorY: 0.5 }); self.spreadX = (Math.random() - 0.5) * 10; self.spreadY = (Math.random() - 0.5) * 10; self.fadeStep = 0.02; self.update = function () { if (self.alpha > 0) { self.x += self.spreadX; self.y += self.spreadY; self.alpha -= self.fadeStep; } else { self.destroy(); } }; }); var GameLogo = Container.expand(function () { var self = Container.call(this); var b = self.attachAsset('gameLogo', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.1, scaleY: 1.1, tint: '#000000', alpha: 0.8 }); var t = self.attachAsset('gameLogo', { anchorX: 0.5, anchorY: 0.5 }); self.x = 2048 / 2; self.y = 2732 / 2; self.update = function () {}; }); var Obstacle = Container.expand(function () { var self = Container.call(this); var obstacleGraphics = self.attachAsset('spikeTrap', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 5; self.update = function () { self.y += self.speed; if (self.y > 2732) { self.destroy(); } }; }); //<Assets used in the game will automatically appear here> // Class for the player character var Player = Container.expand(function () { var self = Container.call(this); self.playerWalkGraphics = self.attachAsset('playerWalk', { anchorX: 0.5, anchorY: 0.5 }); self.playerJumpGraphics = self.attachAsset('playerJump', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }); self.playerDuckGraphics = self.attachAsset('playerDuck', { anchorX: 0.5, anchorY: 0.3, alpha: 0 }); self.playerDashGraphics = self.attachAsset('playerDash', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }); self.speed = 10; self.velocityY = 0; self.deathY = 5; self.jumping = false; self.dashing = false; self.ducking = false; self.actionTimer = 0; self.actionTimerMax = 120; self.update = function () { if (gameOver) { self.rotation -= 0.02; self.y += self.deathY; self.deathY += 0.2; for (var i = game.children.length - 1; i >= 0; i--) { var child = game.children[i]; if (child instanceof Collectible) { game.addChild(child); child.y += self.deathY; child.y.rotation -= 0.2; } } game.addChild(self); if (self.y > 4800) { self.destroy(); LK.showGameOver(); } return; } if (gameStarted) { if (self.jumping) { // Update position based on velocityY self.y -= self.velocityY; // Apply gravity self.velocityY -= 0.75; // Prevent player from falling below the ground if (self.y > groundY) { self.y = groundY; self.velocityY = 0; self.jumping = false; self.playerWalkGraphics.alpha = 1; self.playerJumpGraphics.alpha = 0; gameSpeedBoost = 0; // Create dust particle effect when landing for (var i = 0; i < 20; i++) { var dustParticle = new DustParticle(); dustParticle.x = self.x + (Math.random() * 20 - 10); dustParticle.y = self.y + self.playerWalkGraphics.height / 2 + (Math.random() * 20 - 10); dustParticle.alpha = 0.8; game.addChild(dustParticle); } } } else if (self.dashing) { self.actionTimer++; for (var i = 0; i < 2; i++) { var dustParticle = new DustParticle(); dustParticle.x = self.x - self.width / 4 + (Math.random() * 300 - 150); dustParticle.y = self.y + self.playerWalkGraphics.height / 2 + 30 + (Math.random() * 20 - 10); dustParticle.alpha = 0.8; dustParticle.spreadY = Math.random() * -5; dustParticle.spreadX = Math.random() * -10; game.addChild(dustParticle); } //gameSpeedBoost -= 0.1; if (self.actionTimer >= self.actionTimerMax) { self.y = groundY; self.dashing = false; self.playerWalkGraphics.alpha = 1; self.playerDashGraphics.alpha = 0; self.actionTimer = 0; gameSpeedBoost = 0; } } else if (self.ducking) { self.actionTimer++; for (var i = 0; i < 2; i++) { var dustParticle = new DustParticle(); dustParticle.x = self.x - self.width / 4 + (Math.random() * 300 - 150); dustParticle.y = self.y + self.playerWalkGraphics.height / 2 + 30 + (Math.random() * 20 - 10); dustParticle.alpha = 0.8; dustParticle.spreadY = Math.random() * -5; dustParticle.spreadX = Math.random() * -10; game.addChild(dustParticle); } //gameSpeedBoost -= 0.1; if (self.actionTimer >= self.actionTimerMax) { self.y = groundY; self.ducking = false; self.playerWalkGraphics.alpha = 1; self.playerDuckGraphics.alpha = 0; self.actionTimer = 0; gameSpeedBoost = 0; } } // Just walking if (!self.jumping && !self.dashing && !self.ducking) { // Bobbing and bumping animation self.y += Math.sin(LK.ticks / 3) * 2; self.rotation = Math.sin(LK.ticks / 20) * 0.1; if (LK.ticks % 10 == 0) { for (var i = 0; i < 2; i++) { var dustParticle = new DustParticle(); dustParticle.x = self.x - self.width / 4 + (Math.random() * 300 - 150); dustParticle.y = self.y + self.playerWalkGraphics.height / 2 + 30 + (Math.random() * 20 - 10); dustParticle.alpha = 0.8; dustParticle.spreadY = Math.random() * -3; dustParticle.spreadX = Math.random() * -5; game.addChild(dustParticle); } } } } }; self.jump = function () { if (!self.jumping) { gameSpeedBoost = defaultBoostAmount; self.velocityY = 50; self.jumping = true; self.playerWalkGraphics.alpha = 0; self.playerDashGraphics.alpha = 0; self.playerJumpGraphics.alpha = 1; self.playerDuckGraphics.alpha = 0; // Create dust particle effect when jumping for (var i = 0; i < 20; i++) { var dustParticle = new DustParticle(); dustParticle.x = self.x + (Math.random() * 20 - 10); dustParticle.y = self.y + self.playerWalkGraphics.height / 2 + (Math.random() * 20 - 10); dustParticle.alpha = 0.8; game.addChild(dustParticle); } } }; self.dash = function () { if (!self.dashing) { gameSpeedBoost = defaultBoostAmount; self.dashing = true; self.playerWalkGraphics.alpha = 0; self.playerDashGraphics.alpha = 1; self.playerJumpGraphics.alpha = 0; self.playerDuckGraphics.alpha = 0; } }; self.duck = function () { if (!self.ducking) { gameSpeedBoost = defaultBoostAmount; self.ducking = true; self.playerWalkGraphics.alpha = 0; self.playerDashGraphics.alpha = 0; self.playerJumpGraphics.alpha = 0; self.playerDuckGraphics.alpha = 1; } }; }); var ScoreSign = Container.expand(function (scoreAmount) { var self = Container.call(this); var scoreSignGraphics = new Text2('+' + scoreAmount, { size: 120, fill: "#ffffff", stroke: "#000000", strokeThickness: 8 }); scoreSignGraphics.anchor.set(0.5, 0.5); self.addChild(scoreSignGraphics); self.speedX = -5; self.lifeSpan = 60; // 1 second at 60 FPS self.update = function () { self.x += self.speedX; self.lifeSpan--; if (self.lifeSpan <= 0) { self.destroy(); } }; }); var Shrubbery = Container.expand(function () { var self = Container.call(this); var assetType = Math.random() < 0.3 ? 'shrubbery' : Math.random() < 0.5 ? 'pine' : 'berrybush'; var shrubberyGraphics = self.attachAsset(assetType, { anchorX: 0.5, anchorY: 1 }); self.speed = 0; self.update = function () { // Shrubbery update logic if needed }; }); var SpikeTrap = Container.expand(function () { var self = Container.call(this); var spikeTrapGraphics = self.attachAsset('spikeTrap', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 0; self.dead = false; }); var TallBarricade = Container.expand(function () { var self = Container.call(this); var obstacleGraphics = self.attachAsset('tallBarricade', { anchorX: 0.5, anchorY: 0.5 }); var obstacleGraphicsTop = self.attachAsset('tallBarricadeTop', { anchorX: 0.5, anchorY: 0.5 }); obstacleGraphicsTop.y = -obstacleGraphicsTop.height; self.speed = 0; self.dead = false; self.breakApart = function () { self.dead = true; for (var i = 0; i < 8; i++) { var t = new BrokenPallisade(self.x, self.y); game.addChild(t); } }; }); var TreasureChest = Container.expand(function () { var self = Container.call(this); var collectibleGraphics = self.attachAsset('treasureChest', { anchorX: 0.5, anchorY: 0.5 }); self.scoreVal = 3000; self.speed = 0; self.update = function () { // Collectible update logic if needed }; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB // Sky blue background }); /**** * Game Code ****/ // Create and add score label to the top center of the screen var scoreLabel = new Text2('0', { size: 120, fill: "#ffffff", stroke: "#000000", strokeThickness: 8 }); scoreLabel.anchor.set(0.5, 0); // Center the score label horizontally LK.gui.top.addChild(scoreLabel); var gameStarted = false; var gameOver = false; var gamePaused = false; var obstacles = []; var colectibles = []; var gameSpeed = 20; var baseGameSpeed = gameSpeed; var gameSpeedBoost = 0; var defaultBoostAmount = 10; var touchStartX = 0; var touchStartY = 0; var groundY = 2200; //1810; //2732 - 510; var groundLevel = groundY; // Define groundLevel based on groundY var ARROWS_SEEN = false; var PALLISADES_SEEN = false; var SPIKETRAP_SEEN = false; var instructionsLabel = new Text2('', { size: 120, fill: "#ffffff", stroke: "#000000", strokeThickness: 8, align: 'center' }); // Add background image var background = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 }); game.addChild(background); // Add first path image var path1 = LK.getAsset('path', { anchorX: 0, anchorY: 0, x: 0, //y: 2732 - 400 y: groundY + 130 }); game.addChild(path1); // Add second path image var path2 = LK.getAsset('path', { anchorX: 0, anchorY: 0, x: 2048, //y: 2732 - 400 y: groundY + 130 }); game.addChild(path2); var fgFill = LK.getAsset('foreground_filler', { anchorX: 0, anchorY: 0, x: 0, y: groundY + 430, width: 2048, height: 500 }); game.addChild(fgFill); // Function to place x amount of shrubberies evenly spaced function placeShrubberies(count) { var spacing = 4096 / (count + 1); for (var i = 1; i <= count; i++) { var shrubbery = new Shrubbery(); shrubbery.x = spacing * i + (Math.random() * 100 - 50); // Add randomness to x position shrubbery.y = groundY + 160 + (Math.random() * 30 - 15); // Add randomness to y position game.addChild(shrubbery); } } // Place 5 shrubberies as an example placeShrubberies(32); // Initialize player var player = new Player(); player.x = 350; //player.y = 2732 - 510; player.y = groundY; //2732 - 510; player.scale.x = player.scale.y = 1.2; game.addChild(player); var cover = game.attachAsset('cover', {}); cover.alpha = 0.4; cover.x = 0; //2048 / 2; cover.y = 0; //2732 / 2; var logo = new GameLogo(); logo.x = 2048 / 2; logo.y = 2732 / 2; game.addChild(logo); function gameOverAnimation() { if (!gameOver) { gameOver = true; } } ; function pauseAndShowInstructions(type) { LK.setTimeout(function () { // Your function code here gamePaused = true; /*var label = new Text2('0', { size: 120, fill: "#ffffff", stroke: "#000000", strokeThickness: 8, align: 'center' });*/ var label = instructionsLabel; label.anchor.set(0.5, 0.5); label.x = 2048 / 2; label.y = 2832 / 2; if (type == 1) { label.setText('SWIPE UP\nTO JUMP OVER THE SPIKES'); } else if (type == 2) { label.setText('SWIPE FORWARD\nTO BASH THROUGH THE BARICADES'); } else if (type == 3) { label.setText('SWIPE DOWN\nTO DUCK THE ARROWS'); } game.addChild(label); //}, 1000 * (gameSpeed / baseGameSpeed)); }, 1000); } ; // Handle touch events for player movement game.down = function (x, y, obj) { if (!gameStarted) { gameStarted = true; cover.destroy(); logo.x = 1800; logo.y = 250; logo.width = 400; logo.height = 400; } //player.velocityY = 50; touchStartX = x; touchStartY = y; }; game.up = function (x, y, obj) { if (gamePaused) { gamePaused = false; game.removeChild(instructionsLabel); } var deltaX = x - touchStartX; var deltaY = y - touchStartY; if (Math.abs(deltaX) > Math.abs(deltaY)) { if (deltaX > 0) { console.log("Swipe Right"); // Add logic for right swipe player.dash(); } } else { if (deltaY > 0) { console.log("Swipe Down"); // Add logic for down swipe player.duck(); } else { console.log("Swipe Up"); // Add logic for up swipe player.jump(); } } }; // Update game logic game.update = function () { if (gamePaused) { return; } if (gameOver == true) { player.update(); } if (gameStarted && !gameOver) { // Update player player.update(); // Update score label text scoreLabel.setText('' + LK.getScore()); // Update dust particles and score signs for (var i = game.children.length - 1; i >= 0; i--) { var child = game.children[i]; if (child instanceof DustParticle || child instanceof ScoreSign) { child.update(); } } // Move paths to the left path1.x -= gameSpeed + gameSpeedBoost; path2.x -= gameSpeed + gameSpeedBoost; // Reset path positions for seamless scrolling if (path1.x <= -2048) { path1.x = path2.x + 2048; } if (path2.x <= -2048) { path2.x = path1.x + 2048; } // Move shrubberies to the left for (var i = game.children.length - 1; i >= 0; i--) { var child = game.children[i]; if (child instanceof Shrubbery) { child.x -= gameSpeed + gameSpeedBoost + child.speed; if (child.x <= -child.width) { child.x = 2048 + child.width; } } else if (child instanceof Collectible) { child.x -= gameSpeed + gameSpeedBoost + child.speed; if (child.x <= -child.width) { //child.x = 2048 + child.width; child.destroy(); } if (child.intersects(player)) { LK.setScore(LK.getScore() + child.scoreVal); scoreLabel.setText('' + LK.getScore()); // Show +10 sign var scoreSign = new ScoreSign(child.scoreVal); scoreSign.x = player.x; scoreSign.y = player.y - 100; game.addChild(scoreSign); // Play sound effect for collectible pickup LK.getSound('collectiblePickup').play(); child.destroy(); } } } // Update obstacles for (var i = obstacles.length - 1; i >= 0; i--) { var child = obstacles[i]; child.x -= gameSpeed + gameSpeedBoost + child.speed; //obstacles[i].update(); if (child.intersects(player)) { if (child instanceof TallBarricade && player.dashing) { if (!child.dead) { child.breakApart(); LK.setScore(LK.getScore() + 50); scoreLabel.setText('' + LK.getScore()); // Show +10 sign var scoreSign = new ScoreSign(50); scoreSign.x = player.x; scoreSign.y = player.y - 100; game.addChild(scoreSign); // Play sound effect for collectible pickup //LK.getSound('collectiblePickup').play(); child.destroy(); } } else if (child instanceof ArrowVolley && player.ducking) { if (!child.passed) { //child.dead = true; child.passed = true; child.speed = 30; LK.setScore(LK.getScore() + 50); scoreLabel.setText('' + LK.getScore()); // Show +10 sign var scoreSign = new ScoreSign(50); scoreSign.x = player.x; scoreSign.y = player.y - 100; game.addChild(scoreSign); } } else { LK.effects.flashScreen(0xff0000, 200); gameOverAnimation(); } } else { if (child.x < 0 - child.width) { child.destroy(); obstacles.splice(i, 1); } } if (child.dead) { child.destroy(); obstacles.splice(i, 1); } } // Spawn new obstacles if (LK.ticks % 300 == 0) { // 5 seconds at 60 FPS var ran = Math.random(); if (ran < 0.33 || !SPIKETRAP_SEEN) { var spikeTrap = new SpikeTrap(); spikeTrap.x = 2048 + spikeTrap.width; spikeTrap.y = groundY; game.addChild(spikeTrap); obstacles.push(spikeTrap); if (!SPIKETRAP_SEEN) { // plan delay to show swipe movement pauseAndShowInstructions(1); SPIKETRAP_SEEN = true; } } else if (ran < 0.66 || !PALLISADES_SEEN) { var barricade = new TallBarricade(); barricade.x = 2048 + barricade.width; barricade.y = groundY - barricade.height / 2 + 450; game.addChild(barricade); obstacles.push(barricade); if (!PALLISADES_SEEN) { // plan delay to show swipe movement pauseAndShowInstructions(2); PALLISADES_SEEN = true; } } else { var volley = new ArrowVolley(); volley.x = 2048 + volley.width; volley.y = 0; game.addChild(volley); obstacles.push(volley); if (!ARROWS_SEEN) { // plan delay to show swipe movement pauseAndShowInstructions(3); ARROWS_SEEN = true; } } } // Spawn new collectible every 30 ticks if (LK.ticks % 40 == 0) { var collectible = new Collectible(); collectible.x = 2048 + collectible.width; //collectible.y = 300 + Math.random() * (2032 - collectible.height); collectible.y = 2250 - collectible.rand * 300; // + Math.random() * (2032 - collectible.height); game.addChild(collectible); } if (LK.ticks % 600 == 0) { gameSpeed += 2; } if (LK.ticks % 120 == 0) { var t = new TreasureChest(); t.x = 2048 + t.width; t.y = groundLevel + 20; game.addChild(t); } } // endif gameStarted };
===================================================================
--- original.js
+++ change.js
@@ -2,12 +2,13 @@
* Classes
****/
/***
TODO:
+ - Feature creep ideas: the occassional treasure chest on the ground or animal.
- Music
- Sound effects
- Title, description, hashtags, icon and banner image. Måske Endless Dwarven Run i stedet for Viking.
- */
+ */
var ArrowVolley = Container.expand(function () {
var self = Container.call(this);
//var assetTypes = ['snacks', 'snacks2', 'snacks3', 'snacks4', 'snacks5', 'snacks6', 'snacks7'];
//var randomAsset = assetTypes[Math.floor(Math.random() * assetTypes.length)];
@@ -91,9 +92,9 @@
anchorY: 0.5,
scaleX: 1.1,
scaleY: 1.1,
tint: '#000000',
- alpha: 0.5
+ alpha: 0.8
});
var t = self.attachAsset('gameLogo', {
anchorX: 0.5,
anchorY: 0.5
@@ -351,8 +352,20 @@
game.addChild(t);
}
};
});
+var TreasureChest = Container.expand(function () {
+ var self = Container.call(this);
+ var collectibleGraphics = self.attachAsset('treasureChest', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.scoreVal = 3000;
+ self.speed = 0;
+ self.update = function () {
+ // Collectible update logic if needed
+ };
+});
/****
* Initialize Game
****/
@@ -383,8 +396,9 @@
var defaultBoostAmount = 10;
var touchStartX = 0;
var touchStartY = 0;
var groundY = 2200; //1810; //2732 - 510;
+var groundLevel = groundY; // Define groundLevel based on groundY
var ARROWS_SEEN = false;
var PALLISADES_SEEN = false;
var SPIKETRAP_SEEN = false;
var instructionsLabel = new Text2('', {
@@ -682,12 +696,13 @@
game.addChild(collectible);
}
if (LK.ticks % 600 == 0) {
gameSpeed += 2;
- /*var scoreSign = new ScoreSign('SPEED');
- scoreSign.x = 2048 / 2;
- scoreSign.y = 2732 / 2;
- game.addChild(scoreSign);
- */
}
+ if (LK.ticks % 120 == 0) {
+ var t = new TreasureChest();
+ t.x = 2048 + t.width;
+ t.y = groundLevel + 20;
+ game.addChild(t);
+ }
} // endif gameStarted
};
\ No newline at end of file
A background illstration for a game, rich in style, medieval fantasy themed, of a landscape seen from a great distance, like froma mountain ridge with mountains and forests and lakes and lots of features.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A spritesheet with various poses for a heavily armored little dwarven warrior with an axe in various poses for use in an endless runner game. Te poses should include walking, eating, jumping, ducking low, and chargingforward. Sprites should be laid out in a rectangular grid wih blank space between them. Style should be medieval fantasy.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A game logo for a game called 'Endless Viking Run' using norse font on a background of a viking shield and crossed axes. Muted colors.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.