Rotation around a point causes weird glitches in THREE.js - javascript

Every element from my scene is made of a chain of 3 Object3Ds. The order parent-to-child is cellPivot -> modifier -> setup
setup's purpose is to permanently align a loaded object by resizing / giving some padding that must always be there. It is not supposed to be changed once set
modifier's purpose is to actually perform the real transformation on the object
cellPivot's purpose is to allow me to drag modifier into a cell grid
An example why all this is needed: let's say I have a vertical door in an orthographic perspective that I wanna fit in a 1x1 space, so I give some padding on the x-axis to align the door in the center, similar to the picture below where the orange block is the door
Since I want to move this in any cell in the map, I use cellPivot's position to decide where. I can't use right away modifier since sometimes I wanna rotate the model inside the cell, which requires to modify both position and rotation (since my models are not built around (0, 0, 0), but along +X and +Z)
I have succesfully managed to rotate these doors by rotating modifier around the center of the model (which acts as a pivot). Here's the functions that does the rotation:
three.Object3D.prototype.pivot = function(pivot, f) {
pivot = lib.VecToVector3(three, pivot); // just a conversion between libs
this.position.sub(pivot);
f(this);
this.position.add(pivot);
return this;
};
three.Object3D.prototype.pivotRotate = function(pivot, axis, theta, rotational = false, abs = false) {
if(abs)
theta -= this.rotation.y; /// not good, handles only y
this.pivot(pivot, () => this.position.applyAxisAngle(axis, theta));
if(rotational)
this.rotateOnAxis(axis, theta);
return this;
};
The line that rotates the door and works:
this.o3d.userData.modifier.pivotRotate(this.o3d.userData.center, new three.Vector3(0, 1, 0), this.rot, true);
I'm now trying to do something similar with the player too. I record what keys are pressed, I calculate the normal of the vector of desired direction (if I press W and D I'll get (1, 1), if I press just W I'll get (0, 1)), after which I use the following line to detect the angle at which the user wanna move:
Math.atan2(-normal[1], normal[0]);
I have already tested that the angle is correct. On top of that, the codebase before "rotating around a pivot" used the same code and it worked fine
Everytime there's actually a direction the user wanna go, I'll run the following line:
this.o3d.userData.modifier.pivotRotate(this.o3d.userData.center, new three.Vector3(0, 1, 0), Math.atan2(-normal[1], normal[0]), true, true);
If the user just keeps a key pressed, then abs will make sure that no visible rotation is made (since theta will be 0)
Here's the problem: everytime I press A, be it in combination with W or S or not, the character will rotate like insane. I put after the line from above the following code to see what's happening:
com.log(new three.Euler().setFromQuaternion(this.o3d.userData.setup.getWorldQuaternion(new three.Quaternion())));
I'm getting this:
As you can see, x and z are reaching -pi, and y bouces back and forth. This does not happen for any other combination that does not contain key A

Update after 2 days:
I have rewrote my function like this:
I got these in console while trying to move in the problematic positions:
As it can be seen in the first log, my target is at rotation 0 and is going for -2.35..., but rotAfterRot is showing weird results..: -pi and -.78...
This is the result of running this.rotateOnAxis(axis, theta). I have changed this exact line with this.rotation.y += theta. Now everything is working as it should be: no weird -pi and rotAfterRot.y is actually theta
My guess is that rotateOnAxis is also counting other features of the object, like position, but still can't figure how it spits that -pi

Related

Agar.io clone using P5JS not ejecting (W) the right direction

I have attempted to make an agar.io clone using javaScript along with p5js. Here's the link on github for the full source of this project. Now, I've got the basic gist of the game, but now I'm trying to add an eject/split (In the game, by pressing W an ejection happens). But the ejection/w, is not working correctly— Basically, it's firing the w in the wrong direction, usually close to the blob. Here's the part for the ejection(W)'s position relative to the blob's position (the position where the W is fired, [should fire towards the direction of the mouse]):
this.update = function() {
let newvel = createVector(mouseX-width/2, mouseY-height/2);
newvel.setMag(speed);
this.vel.lerp(newvel, 0.2);
this.pos.add(this.vel);
}
let pos = createVector(mouseX - (this.pos.x + this.vel.x), mouseY - (this.pos.y + this.vel.y));
Don't worry about the few extra variables/uncalled functions (lerp, createVector, setMag, & add are all p5JS functions), the code is too long so I only put the part with the update function and the "setting the W's position" part of the code. "this.vel" is basically the velocity, so I included it in the W's new position, because as the blob is moving, the W might be eaten instantly.
But it still fires W the wrong direction.... Really need to fix this ...
I tried everything like
pos = createVector(mouseX - width/2, mouseY - height/2);
But nevertheless, it still fires the W the wrong direction. Unfortunately, I'm not really sure how to approach this the logical way :( NOTE:
I have also used the translate function to centre the blobs from initial position (0, 0)to translate(width / 2, height / 2)
The way you wrote it, it won't hurt to initialize the ejected blob at mouseX and mouseY with a translation of n-displacement, along with the constrain function limiting the blob's position on the current viewport of the map, subtracted by the distance between the blob and the cursor (by using the dist function). If you would like the animation process to be smoother, and slightly more accurate curvature-wise you can use the lerp function on top of it. Figuring out how to order these steps is simple. First get the regular plane coordinate working by translating before rendering, then integrating the curves using lerp to avoid omitting accuracy (after the calculations and constrains have been made).

Javascript spring physics: Apply direction vector to spring

I'm implementing spring physics in Javascript, inspired by this blog post. My system uses Hooke's Law formula to calculate spring forces:
F = -k(|x|-d)(x/|x|) - bv
I made a CodePen that shows the implementation of a spring between two points. The CodePen has two points connected by a spring, and every 2 seconds the point positions are randomized. You can see the points bounce on the spring towards each other.
If you look at the source, you can see I've defined a direction vector for my spring:
var spring = {
length: 100,
direction: {
x: 1, y: 1
}
};
I'm trying to make it so that the spring always "resolves" in this direction. Put another way, I'd like the spring to always be "pointing" up and to the right. If this were implemented in the CodePen, it means the resting orientation of the points would always be the green point on the bottom left, and the blue point on the top right. No matter where the points start, they should end up in the following orientation (which matches the direction vector):
I've tried multiplying the normals by the spring vector:
norm1 = multiplyVectors( normalize( sub1 ), spring.direction ),
However this is a noop because the vector is (1,1). I've been hacking on this system for a few days now and I'm stuck. How can I constrain my 2d spring to a specific direction?
Spring forces are central just like gravity, which means that the total angular momentum of the system is conserved. Since you start with zero initial velocities, the angular momentum of the system is initially zero. The spring interaction keeps it zero, therefore the final orientation of the spring equals its initial orientation - the weights only move along the line connecting them.
To have the system rotate into the desired final position, you should also apply torque. The easiest way is to give the blue weight a positive charge and the green weight a negative one and then apply a constant external field in direction (1,1). That way the two charges will form a dipole and the interaction with the external field will generate the desired torque.
I don't get along with JavaScript, but I tried to write something based on your initial code here. The force that an external field with intensity E exerts on charge q is F = q * E, with both F and E being vectors. By adjusting q and E you can control how quickly the dipole will orient in the direction of the external field.
The force now becomes F = -k(|x|-d)(x/|x|) + qE - bv.
This has the probably undesired side effect that the final length of the spring will be slightly longer by delta, where delta = 2 * |q||E| / k. You can always adjust for that by reducing the length of the spring. Also, there is a little problem with that approach. Namely, there are two equilibrium states: one with the dipole facing the direction of the field (stable equilibrium) and one with the dipole facing the opposite direction (unstable equilibrium). A bit of random noise in the initial steps of the simulation will prevent the dipole from being trapped into the latter state.

Tile Filling Algorithm for Game

Background:
I am working on a tile-based game in Javascript where a character freely moves around the map (no diagonal - Left/Right/Up/Down) and fills in tiles as he moves around the map. There are three tile types -- tiles you've filled (blue), your current path (red), and empty ones (black). There are also enemies (stars) that move around the map as well, but only in empty areas. The objective is to fill as much of the map as possible.
Map is sized as roughly 40x40 tiles. There is a 1 tile thick border around the entire outside of the map that is already "filled" (blue).
I have established that a flood-fill algorithm will work for filling up areas of tiles when needed. However, my problem is as follows:
PROBLEM STATEMENT:
I want to only fill a sectioned-off part of the map if there are no enemies in it.
My Question:
I could run flood-fill algorithm and stop it if it reaches a tile occupied by an enemy -- however, is this the most efficient approach (for a real time game)?
IF YES, how do I determine where to start the algorithm from in a systematic way since there are multiple areas to check and the character doesn't have to move in a perfectly straight line (can zig-zag up/down/right/left, but can't move diagonally).
Picture Example 1 (pics explain better):
Note: red areas turn blue (filled) once you reach another filled area. In example below, there are no enemies in the contained area, so the area is filled.
Picture Example 2:
In this second example, there is an enemy within the contained area (and on the outside area - not shown) so nothing but the line is filled.
Summary: What is the best approach for doing this type of filling? Is flood fill the best choice for determining whether to fill or not -- 40x40 makes for a pretty large calculation. If yes, how do I determine what tile do I start with?
Let me suggest a different way of looking at your problem.
Going by the description of your game, it seems like the user's main, perhaps only, "verb" (in game design terms) is to draw a line that divides the open area of the field into two sections. If either of these two sections is free of enemies, that section gets filled in; if neither section is free of enemies, the line remains but both sections remain open. There are no other conditions determining whether a section gets filled or not, right?
So the most efficient way to solve this problem, I would think, is simply to draw a continuous line, which may make corners but only moves in horizontal or vertical directions, from one of your enemies to every other enemy in turn. We'll call this line the "probe line". From here on, we're using the approach of Derek's suggested "Ray casting algorithm": We look at the number of times the "probe line" crosses the "border line", and if the number of crossings is ever odd, it means you have at least one enemy on each side of the line, and there's no filling.
Note, though, that there's a difference between the two lines coinciding and the two lines crossing. Picture a probe line that goes from the coordinates (0,10) to (39,10) , and a border line that goes down from (5,0) to (5,10) and then goes right to (13,10). If it goes down from there towards (13,39), the two lines are crossing; if instead it goes upwards toward (13,0), they're not.
After a lot of thought, I strongly suggest that you store the "border line", and construct the "probe line", in terms of line segments - rather than trying to determine from which cells are filled which line segments created them. That will make it much harder than it has to be.
Finally, one odd game design note to be aware of: unless you constrict the user's control so that he cannot bring the border line back to within one cell of itself, then a single border line drawn by a user might end up sectioning off the field into more than two sections - there could be sections created by the border line looping right back on itself. If you allow that, it could very drastically complicate the calculation of where to fill. Check the following diagram I made via Derek's fiddle (thank you, Derek!):
As you can see, one border line has actually created three sections: one on the upper side of the line, one below the line, and one formed by the line itself. I'm still thinking about how that would affect things algorithmically, for that to be possible.
EDIT: With a) time to think about the above creation-of-multiple-sections-by-loops, and b) the Simulation of Simplicity resource brought up by Derek, I think I can outline the simplest and most efficient algorithm that you're likely to get.
There's one subproblem to it which I'll leave to you, and that is determining what your new sections are after the player's actions have drawn a new line. I leave that to you because it's one that would have had to be solved before a solution to your original problem (how to tell if there are enemies within those sections) could have been called.
The solution, presented here as pseudocode, assumes you have the border of each section stored as line segments between coordinates.
Create a list of the sections.
Create a list of the enemies.
Continue as long as neither list is empty:
For each enemy in the enemy list:
Designate "Point A" as the coordinates of the enemy, PLUS 0.5 to both x and y.
For each section in the section list:
Designate "Point B" as the upper-left-most coordinate, PLUS 0.5 to both x and y.
Count how many of the section border segments cross a line between A and B.
If the answer is even:
remove this section from the section list
skip forward to the next enemy
If any sections remain in the list, they are free of enemies. Fill them in.
The addition of the 0.5 to the coordinates of the "probe line" are thanks to Derek's SoS resource; they eliminate the difficult case where the lines coincide rather than simply crossing or not crossing.
If you have the points of the border of your shape that lies on the same y as the enemy, then you can simply count the number of borders, starting from either left or right to the enemy. If it's odd then it's inside. If it's even then it's outside.
Since you are using a grid system this should be easy to implement (and very fast). This algorithm is called the Ray casting algorithm.
Here's a simple example I created: http://jsfiddle.net/DerekL/8QBz6/ (can't deal with degenerate cases)
function testInside(){
var passedBorder = 0,
passingBorder = false;
for(var x = 0; x <= enemy[0]; x++){
if(board[x][enemy[1]] === 1) passingBorder = true;
else if(board[x][enemy[1]] === 0 && passingBorder){
passingBorder = false;
passedBorder++;
}
}
return !!(passedBorder%2);
}
For example, you have this shape which you have determined:
removed
Guess what I found, (slightly modified)
//simple enough, it only needs the x,y of your testing point and the wall.
//no direction or anything else
function testInside3() {
var i, j, c = 0;
for (i = 0, j = wallList.length-1; i < wallList.length; j = i++) {
if ( ((wallList[i][1]>enemy[1]) ^ (wallList[j][1]>enemy[1])) &&
(enemy[0] < (wallList[j][0]-wallList[i][0]) * (enemy[1]-wallList[i][1]) / (wallList[j][1]-wallList[i][1]) + wallList[i][0]) )
c = !c;
}
return !!c;
}
http://jsfiddle.net/DerekL/NvLcK/
This is using the same ray casting algorithm I mentioned, but this time the "ray" is now mathematical using the following inequality for x and a condition for y:
(X2 - X1)(Py - Y1)
Px < ────────────────── + X1
Y2 - Y1
which is derived by combining these two:
Ray:
x(t) = Px + t, y(t) = Py, where t > 0 (the ray goes to the right)
Edge:
x(u) = (X2 - X1)u + X1, y(u) = (Y2 - Y1)u + Y1, where 0 <= u <= 1
And the condition for y:
(Y1 > Py) ⊕ (Y2 > Py)
which is equivalent to:
(Y1 ≥ Py > Y2) ∨ (Y2 ≥ Py > Y1)
and yadi yadi yada some other interesting technical stuff.
Seems like this is the default algorithm in many native libraries. The method used to dealing with degenerate cases is called Simulation of Simplicity, described in this paper (section 5.1).
Nevertheless, here's the result generated with the algorithm testing every coordinate:
If it's easy to determine where the borders of a region to possibly fill are, you can use the following approach:
Assign each edge a clockwise directionality. That is, construct a vector for each edge that starts on its corners and has a direction such that a clockwise path around the region is described by these vectors.
For each enemy:
Construct a vector starting from the enemy and ending on the closest edge. We'll call this an enemy_vector.
Calculate the cross product of the enemy_vector and the vector corresponding to the closest edge. The sign of the cross product will tell you whether the enemy is inside the region: if it's positive, the enemy is outside of it, and if it's negative it isn't!
EXAMPLE:
Suppose we have the following region and enemy to evaluate the inside-ness of.
We can encode the region as a series of vectors that give it a clockwise orientation, like so:
So how do we use that to determine the side of the region inhabited by the enemy? We draw a vector from it (which I've colored red) to the nearest edge (which I've colored green)...
...and take the cross product of the red vector and the green vector. Application of the right-hand rule tells us that (red) x (green) > 0, so the enemy must be outside the region!

First person simulation with three.js using keyboard arrows

For my source, visit http://jsfiddle.net/fYtwf/
Background
I have a simple 3d simulation using three.js where the camera is surrounded in 3 dimensions by cubes. These cubes are to help visualise where the camera is looking until the view controls are coded and tested. I want to create a simple 3D application, where the camera is controlled via up, down, left and right keys. Just like moving your head
Issues
In my current application, when facing forward, and starting to look up, we are successful. However when we turn left 90 degrees, and we press the up arrow... The wrong thing happens. the camera increments the x axis, but because we're facing another direction, modifying the x axis ALONE is WRONG...
Now I'm assuming this is because some trigonometry is required to calculate the correct values for the z axis. However, my trig isn't brilliant.
Current
To get a better understanding of what i mean, please visit my jsfiddle : http://jsfiddle.net/fYtwf/
UP key ONLY increments X
DOWN key ONLY decrements X
LEFT key ONLY increments Y
RIGHT key ONLY decrements Y
Q key ONLY increments Z
W key ONLY decrements Z
( Q and W were only coded to try and help me understand. )
From my current understanding, when I press the UP key, X must increment and the Z axis must be modified based on what the current Y axis is. However I don't know the algorithm :(
So X and Z must be modified in the KEYUP code ( I think, please correct me if I am wrong )
// setRotateX, getRotateX, setRotateY and getRotateY are extended
// camera functions I wrote so I could work with degrees. Solution
// IS NOT required to use them, they just helped me
switch( key )
{
case KEYUP:
if ( camera.getRotateX() < 90 ){ // restrict so they cannot look overhead
camera.setRotateX( camera.getRotateX() + VIEW_INCREMENT );
}
break;
case KEYDOWN:
if ( camera.getRotateX() > -90 ){ // restrict so they cannot look under feet
camera.setRotateX( camera.getRotateX() - VIEW_INCREMENT );
}
break;
case KEYLEFT:
camera.setRotateY( camera.getRotateY() + VIEW_INCREMENT );
break;
case KEYRIGHT:
camera.setRotateY( camera.getRotateY() - VIEW_INCREMENT );
break;
}
There are a number of solutions to this problem, but since you only want the camera to rotate up, down, left, and right, the answer in this case is easy.
You just need to set the camera Euler order to "YXZ" like so:
camera.rotation.order = "YXZ"; // three.js r.65
If you do that, everything becomes very intuitive.
Here is an updated fiddle: http://jsfiddle.net/fYtwf/3/ (this demo is using r.54, however)
Once you change camera.rotation.z from it's default value of zero, things will become very confusing. So don't do that. :-)
three.js r.65
While this does not directly fix your code, I thought I'd mention that Three.js provides two ready-made controllers to navigate in FPS mode. They both use mouse for looking and can move, but should be rather simple to adapt to keyboard look and remove movement if needed. They are:
FirstPersonControls
PointerLockControls
I'd recommend the latter as a starting point because it's rather simple and the former confusingly has the looking code twice, probably as an artifact from old features.

How can a large canvas have an animated 'viewable area'

The question title may be vague. Basically, imagine a racing game built in canvas. The track takes up 10,000 x 10,000 pixels of screen space. However the browser window is 500 x 500 pixels. The car should stay centered in the browser and the 'viewable' area of the 10,000 x 10,000 canvas will change. Otherwise the car would just drive off the edge at disappear.
Does this technique have a name?
What are the basic principles to make this happen?
If the car should stay at the same position (relative to the canvas' position), then you should not move the car. Instead, move the background picture/track/map to the other side.
Causing your eyes to think the car moves right can be done by either moving the car to the right, or by moving the map to the left. The second option seems to be what you want, since the car won't move whereas the viewable area (i.e. the map) will.
This is a quick demo from scratch: http://jsfiddle.net/vXsqM/.
It comes down to altering the map's position the other way round:
$("body").on("keydown", function(e) {
if(e.which === 37) pos.x += speed; // left key, so move map to the right
if(e.which === 38) pos.y += speed;
if(e.which === 39) pos.x -= speed;
if(e.which === 40) pos.y -= speed;
// make sure you can't move the map too far.
// clamp does: if x < -250 return -250
// if x > 0 return 0
// else it's allowed, so just return x
pos.x = clamp(pos.x, -250, 0);
pos.y = clamp(pos.y, -250, 0);
draw();
});
You can then draw the map with the position saved:
ctx.drawImage(img, pos.x, pos.y);
If you're looking for a way to actually move the car when the map cannot be moved any further (because you're driving the car close to a side of the map), then you'd have to extend the clamping and also keep track of when the car should be moved and how far: http://jsfiddle.net/vXsqM/1/.
// for x coordinate:
function clamp2(x, y, a, b) { // x = car x, y = map x, a = min map x, b = max map x
return y > b ? -y : y < a ? a - y : x;
}
The position clamping then becomes a little more complex:
// calculate how much car should be moved
posCar.x = clamp2(posCar.x, posMap.x, -250, 0);
posCar.y = clamp2(posCar.y, posMap.y, -250, 0);
// also don't allow the car to be moved off the map
posCar.x = clamp(posCar.x, -100, 100);
posCar.y = clamp(posCar.y, -100, 100);
// calculate where the map should be drawn
posMapReal.x = clamp(posMap.x, -250, 0);
posMapReal.y = clamp(posMap.y, -250, 0);
// keep track of where the map virtually is, to calculate car position
posMap.x = clamp(posMap.x, -250 - 100, 0 + 100);
posMap.y = clamp(posMap.y, -250 - 100, 0 + 100);
// the 100 is because the car (circle in demo) has a radius of 25 and can
// be moved max 100 pixels to the left and right (it then hits the side)
Two things:
Canvas transformation methods
First, the canvas transformation methods (along with context.save() and context.restore() are your friends and will greatly simplify the math needed to view a portion of a large 'world`. If you use this approach, you can get the desired behavior just by specifying the portion of the world that is visible and the world-coordinates of everything you want to draw.
This is not the only way of doing things* but the transformation methods are meant for exactly this kind of problem. You can use them or you can reinvent them by manually keeping track of where your background should be drawn, etc., etc.
Here's an example of how to use them, adapted from a project of mine:
function(outer, inner, ctx, drawFunction) {
//Save state so we can return to a clean transform matrix.
ctx.save();
//Clip so that we cannot draw outside of rectangle defined by `outer`
ctx.beginPath();
ctx.moveTo(outer.left, outer.top);
ctx.lineTo(outer.right, outer.top);
ctx.lineTo(outer.right, outer.bottom);
ctx.lineTo(outer.left, outer.bottom);
ctx.closePath();
//draw a border before clipping so we can see our viewport
ctx.stroke();
ctx.clip();
//transform the canvas so that the rectangle defined by `inner` fills the
//rectangle defined by `outer`.
var ratioWidth = (outer.right - outer.left) / (inner.right - inner.left);
var ratioHeight = (outer.bottom - outer.top) / (inner.bottom - inner.top);
ctx.translate(outer.left, outer.top);
ctx.scale(ratioWidth, ratioHeight);
ctx.translate(-inner.left, -inner.top);
//here I assume that your drawing code is a function that takes the context
//and draws your world into it. For performance reasons, you should
//probably pass `inner` as an argument too; if your draw function knows what
//portion of the world it is drawing, it can ignore things outside of that
//region.
drawFunction(ctx);
//go back to the previous canvas state.
ctx.restore();
};
If you are clever, you can use this to create multiple viewports, picture-in-pictures, etc. of different sizes and zoom in and out on stuff.
Performance
Second, as I commented in the code, you should make sure your drawing code knows what portion of your larger 'world' will be visible so that you don't do a lot of work trying to draw things that will not be visible.
The canvas transformation methods are meant for solving exactly this kind of problem. Use 'em!
*You will likely have problems if your world is so large that its coordinates cannot fit in an appropriate integer. You'll hit that problem roughly when your world exceeds billion (10^9) or a long trillion (10^18) pixels in any dimension, depending on whether the integers are 32- or 64-bit. If your world isn't measured in pixels but in 'world units', you'll run into problems when your world's total size and smallest feature scale lead to floating point inaccuracies. In that case, you will need to do extra work to keep track of things... but you'll probably still want to use the canvas transformation methods!
My very first game was a racing game where I moved the background instead of the car and although I want to think now that I had my reasons to make it so... I just didn't know better.
There are a few techniques that you need to know to achieve this well.
Tiled background. You need to make your track out of smaller pieces that tiled. To To draw 10,000 x 10,000 pixels is 100MPix image usually such image will have 32bit depth (4 bytes) this will end up being 400MB in memory. Compressions like PNG, JPEG won't help you since these are made to store and transfer images. They cant be rendered to a canvas without decompressing.
Move the car along your track. There is nothing worst then moving the BG under the car. If you need to add more features to your game like AI cars... now they will have to move along the map and to implement car collisions you need to make some not hard but strange spacial transformations.
Add camera entity. The camera needs to have position and viewport size (this is the size of your canvas). The camera will make or break your game. This is the entity that will give you the sense of speed in the game... You can have a camera shake for collisions, if you have drifts if your game the camera can slide pass the desired position and center back to the car, etc. Of course the most important thing will be tracking the car. Some simple suggestions I can give you are to not put the car in dead center of the camera. put the car a little behind so you can see a bit more what's in front of your. The faster the car moves the more you should offset the camera. Also you can't just compute the position of the camera instead compute desired position and slowly per frame move the current camera position to the desired position.
Now when you have camera and a large tiled map, when you draw the tiles you have to subtrack the camera position. You can also compute which tiles are not visible and skip them. This technique will allow you do extend your game with even larger maps or you can stream your map where you don't have all the tiles loaded and load in advance on background (AJAX) what will be visible soon.

Categories